diff --git a/.out-of-scope/harness-specific-branches.md b/.out-of-scope/harness-specific-branches.md new file mode 100644 index 0000000..2a80b0a --- /dev/null +++ b/.out-of-scope/harness-specific-branches.md @@ -0,0 +1,19 @@ +# 已拒绝:为某一种 harness 单开分支 + +- 状态:拒绝(长期有效) +- 日期:2026-10-31 + +## 想法 + +为 Codex / DSH / Claude 某一个客户端的特例,单独复制一份技能或加一个 harness 分支。 + +## 为什么拒绝 + +1. 复制出来的两份技能会立刻开始漂移,评测也要做两遍; +2. 客户端差异应交给安装器(目录、调用模式、字段映射)处理,不该写进技能内容; +3. 特例需求通常是个人的工作流调整,属于 `AGENTS.md` / `CLAUDE.md` 或 fork 的范围。 + +## 允许的替代路径 + +- 客户端差异 → 安装器加 target / 字段映射; +- 个人流程 → 个人目录或 fork。 diff --git a/.out-of-scope/new-skills.md b/.out-of-scope/new-skills.md new file mode 100644 index 0000000..ac5132d --- /dev/null +++ b/.out-of-scope/new-skills.md @@ -0,0 +1,20 @@ +# 已拒绝:新增「随手想到」的技能 + +- 状态:拒绝(长期有效) +- 日期:2026-10-31 + +## 想法 + +「我觉得应该有个技能做 X」——从想象出发新增技能,而不是从真实失败出发。 + +## 为什么拒绝 + +1. 技能目录是每次会话启动就要付的上下文预算,加一个就多一份; +2. 没有真实失败做依据的技能,写出来是泛泛而谈,实际触发率极低; +3. 技能之间会互相抢触发(description 相似),新增一个会稀释已有技能的准确率。 + +## 允许的替代路径 + +- 先用现有技能做一遍真实任务,记录卡点; +- 确实组合不出来,再按 `SCOPE.md` 门槛提,附真实失败证据; +- 只是个人偏好 → 放 `skills-personal/`,不进团队库。 diff --git a/.out-of-scope/personal-workflow-tweaks.md b/.out-of-scope/personal-workflow-tweaks.md new file mode 100644 index 0000000..33b26f3 --- /dev/null +++ b/.out-of-scope/personal-workflow-tweaks.md @@ -0,0 +1,19 @@ +# 已拒绝:把个人工作流调优塞进团队技能 + +- 状态:拒绝(长期有效) +- 日期:2026-10-31 + +## 想法 + +把某个人的偏好(提交信息格式、分支命名、审查语气、工具习惯)直接写进团队技能。 + +## 为什么拒绝 + +1. 团队技能要能被所有人用,个人偏好会变成隐式规训; +2. 一旦写进技能,改起来要走 PR,个人改不动; +3. 这类偏好本来就该放个人 `AGENTS.md` / `CLAUDE.md`。 + +## 允许的替代路径 + +- 个人偏好 → 个人配置文件或 `skills-personal/`; +- 如果是团队共识(不是个人偏好),走 `SCOPE.md` 门槛并附真实失败。 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..68b4d8a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## Unreleased — 2026-10-31 + +### 新增 + +- 技能治理:`SCOPE.md` 收录门槛 + `.out-of-scope/` 拒绝档案。 +- 生命周期分桶(`promoted` / `beta` / `deprecated`)与调用模式(`model-invoked` / `user-invoked`)。 +- `scripts/validate-skills.py`:规范/大小/引用/调用模式/文档校验。 +- `scripts/generate-catalog.py`:生成可审阅的 `catalog.json`。 +- `scripts/scan-skill.sh` + `scripts/scan-allowlist.txt`:入库前安全扫描。 +- 新技能(beta):`skill-creator`、`ai-proj-helper-entry`、`verification-before-completion`。 +- `install-skills.sh`:`--agent dsh`、`--link`、`--audit`、`--include-beta`、`--no-validate`。 + +### 变更 + +- `dev-review`:增加「接收与响应评审意见」。 +- `req-design`:增加「任务依赖边(blocking edges)」。 +- `agent-swarm`:增加「并行编排流程」。 +- `dev-test`:增加「TDD 循环」。 +- `generate-marketplace.py`:只发布 `promoted`,beta/deprecated 不随 marketplace 分发。 diff --git a/CLAUDE.md b/CLAUDE.md index c1ae585..3ae2cea 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,3 +52,10 @@ skills: - `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具 - 其余 `skills-*` 目录均由 Git 版本控制 - 只有受 Git 跟踪的分类目录会被 `generate-marketplace.py` 扫描并加入公开 marketplace;`skills-personal/` 始终排除 + +## 技能治理规则 + +- 公开 marketplace 只发布 `status=promoted`;`beta`/`deprecated` 不进 marketplace(`generate-marketplace.py` 已按 status 过滤)。 +- 每个 `plugin.json` 建议带 `status`,每个 `SKILL.md` 在 `metadata.invocation` 标 `model-invoked` / `user-invoked`。 +- 任何技能增删改后,回改 `catalog.json` 与入口技能 `ai-proj-helper-entry`。 +- 提交前依次跑:`python3 scripts/validate-skills.py`、`./scripts/scan-skill.sh`、`python3 scripts/generate-catalog.py`。 diff --git a/README.md b/README.md index ce150be..77de812 100644 --- a/README.md +++ b/README.md @@ -195,3 +195,17 @@ A: SSE 模式直连远程服务器,零依赖开箱即用(推荐)。stdio - **管理员**:Donglin Lai (qiudl) - **邮箱**:qiudl@zhiyuncai.com - **仓库**:https://gitea.pipexerp.com/pipexerp/ai-proj-helper + +## 技能治理(2026-10-31 起) + +- **真相源**:本仓库。`~/.agents/skills`、`~/.claude/skills`、`$DSH_HOME/skills` 都只是安装产物。 +- **收录门槛**见 [SCOPE.md](./SCOPE.md):只收「真实失败 + 组合不出来」,被拒的想法记在 `.out-of-scope/`。 +- **生命周期**:`promoted`(默认安装)/ `beta`(需 `--include-beta`)/ `deprecated`(不安装);新技能一律先进 beta。 +- **调用模式**:`model-invoked`(占模型目录预算)vs `user-invoked`(只由人触发,不占目录预算)。 +- **安装**: + - Codex:`./install-skills.sh --agent codex` + - DSH:`DSH_HOME= ./install-skills.sh --agent dsh --link` + - Claude(兼容):`./install-skills.sh --agent claude` + - 看漂移:`./install-skills.sh --audit` +- **校验 / 安全 / 清单**:`python3 scripts/validate-skills.py`、`./scripts/scan-skill.sh`、`python3 scripts/generate-catalog.py` +- **建技能**:走 `skill-creator` 技能(收录门槛、分桶、调用模式、evals、四段式文档、路由回改),不要手写。 diff --git a/SCOPE.md b/SCOPE.md new file mode 100644 index 0000000..9ff52bb --- /dev/null +++ b/SCOPE.md @@ -0,0 +1,45 @@ +# Scope — ai-proj-helper 技能的收录门槛 + +本仓库是团队每天在用的技能集,**不是技能收藏夹**。技能目录会在每次会话启动时占用模型的上下文预算,所以「多加一个」永远是有代价的。 + +## 门槛 + +新技能或改动**默认拒绝**,只有同时满足两条才进入评审: + +1. **真实失败**:能说清在哪个真实任务/会话里出了问题——跑了什么、期望什么、实际什么。假设性的「这样会更好」不算。 +2. **组合不出来**:用现有技能组合做不到。能组合的,改现有技能,不新增。 + +规模不重要:一个词的修改和一次重写按同一标准审。 + +## 分桶 + +| 桶 | 含义 | 安装 | 进 README / plugin.json | +| --- | --- | --- | --- | +| `promoted` | 已验证、日常在用 | 默认 | 必须 | +| `beta` | 公开试跑、收反馈 | `--include-beta` | 不进默认清单 | +| `deprecated` | 不再使用 | 不安装 | 只留文档,标弃用 | + +新技能一律先进 `beta`;promoted 需要真实使用记录 + evals 通过。 + +## 调用模式 + +- `model-invoked`(默认):进模型目录,agent 自己判断何时用。 +- `user-invoked`:只由人下命令触发,不占目录预算;必须写 `disable-model-invocation: true` + `metadata.invocation: user-invoked`。 + +判定:这件事是不是「人下命令才开始」?是 → user-invoked。 + +## 已经拒绝的想法 + +每个被拒概念一个文件,写在 [`.out-of-scope/`](./.out-of-scope/) 下,先读再提。当前已有: + +- [`new-skills.md`](./.out-of-scope/new-skills.md) +- [`harness-specific-branches.md`](./.out-of-scope/harness-specific-branches.md) +- [`personal-workflow-tweaks.md`](./.out-of-scope/personal-workflow-tweaks.md) + +## 提交流程 + +1. 先过 [`skill-creator`](./skills-core/skill-creator-plugin/skills/SKILL.md) 的收录门槛与质量门禁。 +2. `python3 scripts/validate-skills.py` 通过。 +3. `./scripts/scan-skill.sh` 无高危项。 +4. `python3 scripts/generate-catalog.py` 更新 `catalog.json`。 +5. 版本号 + CHANGELOG 更新,走 PR。 diff --git a/SYNC-GUIDE.md b/SYNC-GUIDE.md index 6360413..5819b97 100644 --- a/SYNC-GUIDE.md +++ b/SYNC-GUIDE.md @@ -67,3 +67,24 @@ Claude Code 需要显式选择目标: **如何移除技能?** 删除插件目录、重新生成 marketplace、提交变更。使用者随后执行 `./install-skills.sh --dry-run --cleanup`,确认后再去掉 `--dry-run`。 + +## 安装矩阵(2026-10 更新) + +| agent | 安装目录 | 默认模式 | 状态文件 | +| --- | --- | --- | --- | +| `codex`(默认) | `~/.agents/skills` | copy | `~/.agents/.ai-proj-helper-installed-skills.json` | +| `dsh` | `$DSH_HOME/skills` | copy(开发机建议 `--link`) | `$DSH_HOME/.ai-proj-helper-installed-skills.json` | +| `claude`(兼容) | `~/.claude/skills` | copy | `~/.claude/.installed-skills.json` | + +```bash +# 本机(DSH 开发机,改仓库即时生效) +DSH_HOME="" ./install-skills.sh --agent dsh --link + +# 远程/其他机器 +./install-skills.sh --agent codex + +# 看谁落后了 +./install-skills.sh --agent codex --audit +``` + +`beta` 技能默认不装:需要时加 `--include-beta`。`promoted/beta/deprecated` 见 `SCOPE.md`。 diff --git a/catalog.json b/catalog.json new file mode 100644 index 0000000..41803fa --- /dev/null +++ b/catalog.json @@ -0,0 +1,683 @@ +{ + "repo": "ai-proj-helper", + "generated_at": "2026-10-31T14:03:00Z", + "total": 61, + "counts": { + "promoted/model-invoked": 58, + "beta/user-invoked": 2, + "beta/model-invoked": 1 + }, + "skills": [ + { + "name": "biz-contract", + "category": "biz", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "商务合同撰写。支持多种合同类型:软件订阅合同、软件定制开发合同、物流合同、销售服务合同、贸易合同等。当用户提到合同、协议、签约、合作协议相关任务时自动激活。", + "description_len": 78, + "path": "skills-biz/biz-contract-plugin/skills/SKILL.md", + "digest": "b8a94cb7dece26e4" + }, + { + "name": "biz-ops", + "category": "biz", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "商务运营技能。支持商业计划书(BP)撰写和商务合同起草。当用户提到商业计划书、BP、融资计划、商业模式、合同、协议、签约等相关任务时自动激活。", + "description_len": 71, + "path": "skills-biz/biz-ops-plugin/skills/SKILL.md", + "digest": "c4959eef7dabfbe3" + }, + { + "name": "biz-plan", + "category": "biz", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "商业计划书撰写。支持融资BP、战略规划、商业模式设计等。当用户提到商业计划书、BP、融资计划、商业模式、战略规划相关任务时自动激活。", + "description_len": 66, + "path": "skills-biz/biz-plan-plugin/skills/SKILL.md", + "digest": "4229b7a96501e0c2" + }, + { + "name": "finance", + "category": "biz", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "财务对账技能。支持银行对账、应收对账、应付对账、内部往来对账等。通过自然语言实现账单导入、差异分析、对账报告生成。当用户提到对账、银行流水、应收应付、账单核对、财务核销相关任务时自动激活。", + "description_len": 94, + "path": "skills-biz/finance-plugin/skills/SKILL.md", + "digest": "c3f3eabd01ff7cac" + }, + { + "name": "ai-proj-helper-entry", + "category": "core", + "version": "0.1.0", + "status": "beta", + "invocation": "user-invoked", + "description": "ai-proj-helper 技能库路由:告诉你有哪些技能、什么任务用哪个、以及「REQ released + PDV 通过才算交付」的强制口径。人在开始需求/开发/评审/发布任务前主动调用。", + "description_len": 96, + "path": "skills-core/ai-proj-helper-entry-plugin/skills/SKILL.md", + "digest": "41d39b76d4c71dbf" + }, + { + "name": "ai-proj", + "category": "core", + "version": "2.0.1", + "status": "promoted", + "invocation": "model-invoked", + "description": "ai-proj 任务与需求管理。用于创建/查询/更新需求、任务、文档。当用户提到 ai-proj、任务管理、需求管理、REQ-XXX 相关操作时自动激活。", + "description_len": 77, + "path": "skills-core/ai-proj-plugin/skills/SKILL.md", + "digest": "f2ef00fdebb29034" + }, + { + "name": "pm-ask", + "category": "core", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "基于 ai-proj MCP + git log 真实数据的项目问答。禁止编造。当用户说\"/ask\"、\"问一下\"、\"统计一下\"、\"最近多少\"、\"谁做了多少\"、\"本月进度\"等项目相关问题时自动激活。", + "description_len": 98, + "path": "skills-core/pm-ask-plugin/skills/SKILL.md", + "digest": "e5b69a0b56985472" + }, + { + "name": "pm-risk", + "category": "core", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "三维度项目风险扫描(需求层/代码层/流程层)。当用户说\"/risk\"、\"风险扫描\"、\"有什么风险\"、\"哪些需求停滞了\"、\"分支健康\"时自动激活。", + "description_len": 72, + "path": "skills-core/pm-risk-plugin/skills/SKILL.md", + "digest": "928cfec76018329f" + }, + { + "name": "publish", + "category": "core", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。", + "description_len": 48, + "path": "skills-core/publish-plugin/skills/SKILL.md", + "digest": "222151d3dbf35099" + }, + { + "name": "skill-creator", + "category": "core", + "version": "0.1.0", + "status": "beta", + "invocation": "user-invoked", + "description": "团队技能的标准流程:收录门槛、分桶生命周期、调用模式、SKILL.md 规范、evals 全量、四段式文档、路由回改。当要新建技能、大改现有技能、或评审一个技能是否合格时使用。", + "description_len": 88, + "path": "skills-core/skill-creator-plugin/skills/SKILL.md", + "digest": "18f18c43c3fa56a6" + }, + { + "name": "agent-browser", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "浏览器自动化技能。用于网页交互、E2E冒烟测试、需求验收验证、前端开发验证、截图对比。基于 Vercel agent-browser CLI。", + "description_len": 71, + "path": "skills-dev/agent-browser-plugin/skills/SKILL.md", + "digest": "f382bffe3d1c84b2" + }, + { + "name": "agent-swarm", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.", + "description_len": 153, + "path": "skills-dev/agent-swarm-plugin/skills/SKILL.md", + "digest": "a0d8a329ab9468f5" + }, + { + "name": "ai-chat", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。", + "description_len": 78, + "path": "skills-dev/ai-chat-plugin/skills/SKILL.md", + "digest": "97ce03993394605c" + }, + { + "name": "ai-proj-cicd-release", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Execute and audit the AI-Proj service CI/CD flow across Gitea gates, immutable image builds, staging verification, approved production release, rollback, and evidence capture. Use for AI-Proj CI status, release PRs, staging or production deployments, failed-release diagnosis, deployed commit/schema verification, and delivery-chain repair. Do not use for unrelated repositories or macOS application packaging.", + "description_len": 410, + "path": "skills-dev/ai-proj-cicd-release-plugin/skills/SKILL.md", + "digest": "65adfbf96fc4b392" + }, + { + "name": "ai-proj-macos-release", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Build, sign, notarize, publish, and verify the AI-Proj macOS Apple Silicon package through the repository's release chain. Use when asked to release, republish, update, or repair the downloadable macOS application, including Gatekeeper failures and download-manifest updates. Do not use for service deployments or unrelated applications.", + "description_len": 337, + "path": "skills-dev/ai-proj-macos-release-plugin/skills/SKILL.md", + "digest": "595fbd781968025e" + }, + { + "name": "db-migration", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时由 req-design 推荐激活。", + "description_len": 77, + "path": "skills-dev/db-migration-plugin/skills/SKILL.md", + "digest": "f8d6ebbddbbf7a71" + }, + { + "name": "defect-analysis", + "category": "dev", + "version": "1.1.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。", + "description_len": 68, + "path": "skills-dev/defect-analysis-plugin/skills/SKILL.md", + "digest": "23dfafda92d0c622" + }, + { + "name": "deploy-rollback", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "回滚方案插件。部署后发现问题时的回滚策略和执行步骤。挂载在 deploy 阶段,部署出问题时激活。", + "description_len": 49, + "path": "skills-dev/deploy-rollback-plugin/skills/SKILL.md", + "digest": "75ebf66a3f74195a" + }, + { + "name": "dev-android", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。当涉及 Android 开发任务时按需加载。", + "description_len": 72, + "path": "skills-dev/dev-android-plugin/skills/SKILL.md", + "digest": "ca7442afd02c6129" + }, + { + "name": "dev-arch", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "软件架构设计技能。用于系统设计、技术选型、架构评审、设计文档编写。当用户提到架构设计、系统设计、技术方案、API 设计相关任务时自动激活。", + "description_len": 69, + "path": "skills-dev/dev-arch-plugin/skills/SKILL.md", + "digest": "c9a419c83a307a11" + }, + { + "name": "dev-cicd", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "CI/CD 流水线设计、优化与排查。适配 Gitea Actions + Go/Swift/Next.js/Docker 栈。当用户提到 CI、CD、流水线、pipeline、workflow、构建失败、runner 相关任务时自动激活。", + "description_len": 119, + "path": "skills-dev/dev-cicd-plugin/skills/SKILL.md", + "digest": "a763f0f140516411" + }, + { + "name": "dev-coding", + "category": "dev", + "version": "2.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "软件编码开发技能。用于代码编写、功能实现、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。核心支持 Go 后端 + Vue/React 前端开发。", + "description_len": 81, + "path": "skills-dev/dev-coding-plugin/skills/SKILL.md", + "digest": "1b754e668965132f" + }, + { + "name": "dev-commit", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "智能 git commit — 分支保护 + 自动建功能分支 + Conventional Commits 生成。当用户说\"提交代码\"、\"commit\"、\"/commit\"、\"保存修改\"时自动激活。", + "description_len": 99, + "path": "skills-dev/dev-commit-plugin/skills/SKILL.md", + "digest": "1560658c4a30df45" + }, + { + "name": "dev-deploy", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "应用部署技能。支持 iOS TestFlight、Docker 容器等多平台部署。当用户提到部署、发布、TestFlight、上架、build、archive 相关任务时自动激活。", + "description_len": 90, + "path": "skills-dev/dev-deploy-plugin/skills/SKILL.md", + "digest": "00873ab922fb1595" + }, + { + "name": "dev-integration", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "前后端联调技能。API 契约验证、接口对接、联调报告生成。对应 req 流程 integration 阶段。纯后端需求自动跳过。", + "description_len": 64, + "path": "skills-dev/dev-integration-plugin/skills/SKILL.md", + "digest": "eff6be8eb57b7fef" + }, + { + "name": "dev-ios", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "iOS 开发插件。Swift/SwiftUI + MVVM 架构,TestFlight 部署。当涉及 iOS 开发任务时按需加载。", + "description_len": 65, + "path": "skills-dev/dev-ios-plugin/skills/SKILL.md", + "digest": "364efd9f6f8158c2" + }, + { + "name": "dev-mcp", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "MCP Bridge 开发插件。TypeScript MCP 服务开发,Token 管理,HTTP 客户端模式。当涉及 mcp-task-bridge 开发时按需加载。", + "description_len": 84, + "path": "skills-dev/dev-mcp-plugin/skills/SKILL.md", + "digest": "83d5912212fcfa4a" + }, + { + "name": "dev-pda", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先。当涉及 PDA/手持终端开发时按需加载。", + "description_len": 57, + "path": "skills-dev/dev-pda-plugin/skills/SKILL.md", + "digest": "e93c3ab182398571" + }, + { + "name": "dev-review", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "代码评审技能。六视角对抗性扫描法(含 Karpathy Scope 审计),用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。", + "description_len": 91, + "path": "skills-dev/dev-review-plugin/skills/SKILL.md", + "digest": "a8a1ec79b85e3227" + }, + { + "name": "dev-scaffold", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "模块脚手架插件。新建模块时自动生成分层代码骨架。挂载在 dev 阶段,新建模块时激活。", + "description_len": 43, + "path": "skills-dev/dev-scaffold-plugin/skills/SKILL.md", + "digest": "4044787b1e468302" + }, + { + "name": "dev-test", + "category": "dev", + "version": "2.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "软件测试技能。用于单元测试、集成测试、E2E测试、测试用例设计。支持 Go、Vue、React、iOS、Android 等多平台测试。", + "description_len": 67, + "path": "skills-dev/dev-test-plugin/skills/dev-test/SKILL.md", + "digest": "a03536a478eabe6c" + }, + { + "name": "executing-plans", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Use when you have a written implementation plan to execute in a separate session with review checkpoints", + "description_len": 104, + "path": "skills-dev/executing-plans-plugin/skills/SKILL.md", + "digest": "8991a50091af83a4" + }, + { + "name": "finishing-a-development-branch", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Use when implementation is complete and all tests pass - verifies and creates PR", + "description_len": 80, + "path": "skills-dev/finishing-branch-plugin/skills/SKILL.md", + "digest": "1102047ccc060e60" + }, + { + "name": "frontend-design", + "category": "dev", + "version": "1.0.1", + "status": "promoted", + "invocation": "model-invoked", + "description": "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.", + "description_len": 234, + "path": "skills-dev/frontend-design-plugin/skills/SKILL.md", + "digest": "6bc30a1a562bae8c" + }, + { + "name": "karpathy-guidelines", + "category": "dev", + "version": "1.0.1", + "status": "promoted", + "invocation": "model-invoked", + "description": "Karpathy 四原则编码行为守则。减少 LLM 常见编码错误:过度实现、静默假设、顺手重构、无验证标准。在任意编码场景激活。", + "description_len": 64, + "path": "skills-dev/karpathy-guidelines-plugin/skills/SKILL.md", + "digest": "a68f347031110d6a" + }, + { + "name": "pull-request", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Use when starting new development tasks, creating pull requests, reviewing code, or managing PR feedback cycles on Gitea. Triggers on /pr commands or when user mentions PR, pull request, code review, or branch creation.", + "description_len": 219, + "path": "skills-dev/pull-request-plugin/skills/SKILL.md", + "digest": "40dac0d290782bb5" + }, + { + "name": "review-checklist", + "category": "dev", + "version": "1.1.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "项目级代码评审检查清单。按项目积累特定检查项,挂载在 dev-review 下自动加载。每次 CR 时触发。", + "description_len": 54, + "path": "skills-dev/review-checklist-plugin/skills/SKILL.md", + "digest": "5bae13b6a8d92650" + }, + { + "name": "slark-cicd", + "category": "dev", + "version": "1.1.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Slark 仓库 staging、生产和 Desktop 安装包的端到端 CI/CD 可执行 runbook。覆盖本地预推快检、PR 与内网 ci/internal-gate 门禁、合并 origin/main、生产前强制 staging 验收、审批式生产发布,以及在 m5max 构建签名、公证并上传 macOS/Windows Desktop 包到 OSS。当用户要在 slark(qiudl/qiu-slark)里发布/上线、部署到生产或 staging、发布 Desktop 安装包、盯 CI/合并 PR、复现或验证运行时行为、或排查发布链/推送路由问题时使用。", + "description_len": 285, + "path": "skills-dev/slark-cicd-plugin/skills/SKILL.md", + "digest": "2919c19d8a38dd23" + }, + { + "name": "slark-dsh-cicd", + "category": "dev", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "DSH 插件包与 Slark 宿主补丁的发布 runbook。覆盖 npm run pack 双 tgz 双资产、无上游写权限时的 fork 发布、干净单提交与树一致性 gate、改指向后必须重新打包、draft→publish 节奏、GitHub HTTPS/SSH 与 fetch 卡死处置、发布后 SHA 核对、app.asar 完整性约束、ai-proj 发布状态对齐。当用户要发布或升级 DSH 插件(dsh-worktable 等)、发布/更新 Slark 宿主补丁、push 或下载 GitHub 失败、插件「检查更新」看不到新版本、需要 fork 发布、或排查 asar 完整性/签名问题时使用。", + "description_len": 306, + "path": "skills-dev/slark-dsh-cicd-plugin/skills/SKILL.md", + "digest": "44a1322e15d42845" + }, + { + "name": "data-excel", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "Excel 数据处理与 BI 集成。通过自然语言操作 Excel 文件的读取、编辑、转换,并支持导入到 BI 系统(Metabase)进行可视化分析。当用户提到 Excel、表格处理、数据导入、BI 分析相关任务时自动激活。", + "description_len": 112, + "path": "skills-integration/data-excel-plugin/skills/SKILL.md", + "digest": "1d6a88d967ef8eaf" + }, + { + "name": "doubao-voice", + "category": "integration", + "version": "1.0.1", + "status": "promoted", + "invocation": "model-invoked", + "description": "豆包语音API调用。支持语音合成(TTS)和唱歌。当用户提到语音合成、文字转语音、唱歌、豆包语音相关任务时自动激活。", + "description_len": 58, + "path": "skills-integration/doubao-voice-plugin/skills/SKILL.md", + "digest": "716037a762904fdd" + }, + { + "name": "feishu-bitable", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "飞书多维表格操作。用于记录增删改查、批量操作、筛选排序、数据同步。当需要操作飞书多维表格时使用。", + "description_len": 48, + "path": "skills-integration/feishu-bitable-plugin/skills/SKILL.md", + "digest": "e9678f06e0e02c52" + }, + { + "name": "feishu-docx", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "飞书云文档操作。用于创建、编辑云文档,插入内容块,会议纪要生成。当需要操作飞书云文档时使用。", + "description_len": 46, + "path": "skills-integration/feishu-docx-plugin/skills/SKILL.md", + "digest": "a90e9c689c2e914d" + }, + { + "name": "feishu", + "category": "integration", + "version": "1.1.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "飞书文档与多维表格操作入口。当用户提到飞书、云文档、多维表格、Bitable 相关任务时自动激活。", + "description_len": 49, + "path": "skills-integration/feishu-plugin/skills/SKILL.md", + "digest": "36c8167f43a3df88" + }, + { + "name": "siyuan", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "思源笔记 API 集成。通过自然语言创建、编辑、搜索笔记,管理笔记本和文档树。当用户提到思源笔记、SiYuan、笔记管理、知识库相关任务时自动激活。", + "description_len": 74, + "path": "skills-integration/siyuan-plugin/skills/SKILL.md", + "digest": "92b97573d6682e8b" + }, + { + "name": "siyuan-to-feishu", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "将思源笔记导出为 PDF 并发送到飞书群。当用户提到\"发送笔记\"、\"导出PDF发飞书\"、\"/siyuan send\"、\"分享到飞书\"相关任务时自动激活。", + "description_len": 76, + "path": "skills-integration/siyuan-to-feishu-plugin/skills/SKILL.md", + "digest": "4ddc5e600c520f48" + }, + { + "name": "wecom", + "category": "integration", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。", + "description_len": 77, + "path": "skills-integration/wecom-plugin/skills/SKILL.md", + "digest": "57eacac81d6f76ab" + }, + { + "name": "req-audit", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。", + "description_len": 55, + "path": "skills-req/req-audit-plugin/skills/SKILL.md", + "digest": "ff2e6197bbb059c6" + }, + { + "name": "req-compare", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "对比式需求分析插件。系统平移、竞品借鉴、版本升级时使用参考对象对比法编写 PRD。挂载在 analysis 阶段,需要对比分析时由 req-prd 推荐激活。", + "description_len": 79, + "path": "skills-req/req-compare-plugin/skills/SKILL.md", + "digest": "3428e3f37ef9e9e8" + }, + { + "name": "req-design", + "category": "req", + "version": "2.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "需求开发设计技能。用于 PRD 到开发设计的转换:API 契约定义、数据模型变更方案、变更文件清单、开发任务拆分、技术风险评估。当用户执行 /req doc 或需要编写开发设计文档时自动激活。", + "description_len": 96, + "path": "skills-req/req-design-plugin/skills/SKILL.md", + "digest": "8ec85838666b5cc5" + }, + { + "name": "req-dev", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "需求开发计划编写技能。用于 PRD 到代码转换、代码库分析、开发任务拆分、技术方案设计。当用户执行 /req doc 或需要编写开发计划时自动激活。", + "description_len": 74, + "path": "skills-req/req-dev-plugin/skills/SKILL.md", + "digest": "3b0dd9396df3c236" + }, + { + "name": "req-lookback", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "回归测试。部署后自动验证变更涉及的功能是否正常。可独立调用或由 /req done 自动触发。", + "description_len": 47, + "path": "skills-req/req-lookback-plugin/skills/SKILL.md", + "digest": "cc6bff614a8f7bf4" + }, + { + "name": "req", + "category": "req", + "version": "2.1.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "需求工作流管理。用于 /req 命令使用、需求全生命周期管理(创建→PRD→评审→开发→测试→部署→归档)。当用户提到需求管理、/req 命令、REQ-XXX 相关任务时自动激活。", + "description_len": 90, + "path": "skills-req/req-plugin/skills/SKILL.md", + "digest": "bdb1fab4d3d8c3d2" + }, + { + "name": "req-prd", + "category": "req", + "version": "2.3.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。", + "description_len": 76, + "path": "skills-req/req-prd-plugin/skills/SKILL.md", + "digest": "0e5b16fcef3105bd" + }, + { + "name": "req-prototype", + "category": "req", + "version": "2.2.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。", + "description_len": 81, + "path": "skills-req/req-prototype-plugin/skills/SKILL.md", + "digest": "7e362f4f895fb50a" + }, + { + "name": "req-research", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "需求调研插件。代码审计、数据库分析、现有功能调研、技术可行性评估。挂载在 analysis 阶段,需要深度调研时由 req-prd 推荐激活。", + "description_len": 71, + "path": "skills-req/req-research-plugin/skills/SKILL.md", + "digest": "a94924f53bd4c80e" + }, + { + "name": "req-retro", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "复盘总结。自动采集数据、计算质量评分、跨需求模式识别、技能自动进化。可独立调用或由 /req done 自动触发。", + "description_len": 57, + "path": "skills-req/req-retro-plugin/skills/SKILL.md", + "digest": "636b7099d85e9549" + }, + { + "name": "req-review", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。", + "description_len": 65, + "path": "skills-req/req-review-plugin/skills/SKILL.md", + "digest": "cd1a5181d72f35f4" + }, + { + "name": "req-test-gate", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论(Ratchet、约定建立、门禁层级)。当用户提到质量门禁、架构约束、约定检查、ratchet、harness 相关任务时自动激活。", + "description_len": 159, + "path": "skills-req/req-test-gate-plugin/skills/SKILL.md", + "digest": "0eba060fa456885d" + }, + { + "name": "req-workflow", + "category": "req", + "version": "1.0.0", + "status": "promoted", + "invocation": "model-invoked", + "description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。", + "description_len": 61, + "path": "skills-req/req-workflow-plugin/skills/SKILL.md", + "digest": "87499da3817d162d" + }, + { + "name": "verification-before-completion", + "category": "req", + "version": "0.1.0", + "status": "beta", + "invocation": "model-invoked", + "description": "汇报「完成/修好/通过」或关闭任务、提交 PR、宣布 REQ 完成之前,必须先运行验证命令并附证据;没有证据不得声称完成。当准备说完成、关闭任务、或汇报交付前使用。", + "description_len": 82, + "path": "skills-req/verification-before-completion-plugin/skills/SKILL.md", + "digest": "7c23649f4a0a8798" + } + ] +} diff --git a/generate-marketplace.py b/generate-marketplace.py index af0db19..65b4d29 100644 --- a/generate-marketplace.py +++ b/generate-marketplace.py @@ -96,6 +96,14 @@ def scan_plugins(directory, source_prefix, disabled): with open(manifest_path) as f: manifest = json.load(f) + # Lifecycle buckets: only promoted plugins ship in the public + # marketplace. beta/deprecated must be installed with --include-beta. + import os + status = manifest.get("status", "promoted") + if status in ("beta", "deprecated") and os.environ.get("ALLOW_BETA") != "1": + print(f" ⊘ {plugin_name} (status={status}, not shipped)") + continue + category, keywords = get_category_and_keywords(plugin_name) plugins.append({ diff --git a/install-skills.sh b/install-skills.sh index 32d93c9..db3ecef 100755 --- a/install-skills.sh +++ b/install-skills.sh @@ -5,7 +5,11 @@ # ./install-skills.sh [options] # # Options: -# --agent Install target: codex (default) or claude +# --agent Install target: codex (default), dsh, or claude +# --link Symlink skills from the repo instead of copying (dev machines) +# --audit Show installed vs repo versions for the selected target +# --include-beta Also install skills whose plugin.json status=beta +# --no-validate Skip scripts/validate-skills.py before installing # --dry-run Preview changes without writing anything # --category Only install plugins in dir_category= # Valid values: biz, core, dev, integration, personal, req @@ -30,6 +34,10 @@ FORCE=false CLEANUP=false LIST_ONLY=false INSTALL_ACTION=false +LINK_MODE=false +AUDIT_ONLY=false +INCLUDE_BETA=false +NO_VALIDATE=false # ── Colour helpers ───────────────────────────────────────────────────────────── GREEN='\033[0;32m' @@ -48,9 +56,13 @@ dry() { echo -e "${YELLOW}[dry]${RESET} $*"; } while [[ $# -gt 0 ]]; do case "$1" in --agent) - [[ $# -ge 2 ]] || { error "--agent requires codex or claude"; exit 1; } + [[ $# -ge 2 ]] || { error "--agent requires codex, dsh or claude"; exit 1; } AGENT_TARGET="$2"; shift ;; --dry-run) DRY_RUN=true ;; + --link) LINK_MODE=true ;; + --audit) AUDIT_ONLY=true ;; + --include-beta) INCLUDE_BETA=true ;; + --no-validate) NO_VALIDATE=true ;; --force) FORCE=true ;; --cleanup) CLEANUP=true ;; --list) LIST_ONLY=true ;; @@ -77,13 +89,21 @@ case "$AGENT_TARGET" in SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.agents/skills}" STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.agents/.ai-proj-helper-installed-skills.json}" ;; + dsh) + if [[ -z "${DSH_HOME:-}" ]]; then + error "--agent dsh requires DSH_HOME (or set AI_PROJ_HELPER_SKILLS_DIR explicitly)" + exit 1 + fi + SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${DSH_HOME}/skills}" + STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${DSH_HOME}/.ai-proj-helper-installed-skills.json}" + ;; claude) SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.claude/skills}" COMMANDS_DIR="${AI_PROJ_HELPER_COMMANDS_DIR:-${HOME}/.claude/commands}" STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.claude/.installed-skills.json}" ;; *) - error "Unsupported agent: $AGENT_TARGET (expected codex or claude)" + error "Unsupported agent: $AGENT_TARGET (expected codex, dsh or claude)" exit 1 ;; esac @@ -281,8 +301,19 @@ install_plugin() { effective_install_type="skill" fi + local status + status="$(read_field "$json_path" status)" + status="${status:-promoted}" + if [[ "$LIST_ONLY" == true ]]; then - echo " [$dir_category] $effective_install_type:$install_name v$version" + echo " [$dir_category] $status $effective_install_type:$install_name v$version" + return + fi + + if [[ "$status" == "deprecated" ]]; then + return + fi + if [[ "$status" == "beta" && "$INCLUDE_BETA" != true ]]; then return fi @@ -305,6 +336,21 @@ install_plugin() { return fi + # Dev machines may symlink instead of copying: repository edits apply at once. + if [[ "$LINK_MODE" == true && "$effective_install_type" != "command" ]]; then + if [[ "$DRY_RUN" == true ]]; then + dry "$install_name → symlink $target_path → $src_dir" + else + mkdir -p "$SKILLS_DIR" + rm -rf "$target_path" + ln -sfn "$src_dir" "$target_path" + state_set "$install_name" "$version" "symlink" "$(content_digest "$src_dir")" + ok "$install_name → symlink (v$version)" + fi + INSTALL_ACTION=true + return + fi + # A recorded content digest distinguishes repository updates from user edits. # Legacy state is adopted automatically only when the target is missing or # already identical to the repository source. @@ -415,6 +461,38 @@ cleanup_removed() { done < <(state_all_names) } +# ── Audit ────────────────────────────────────────────────────────────────────── +audit_target() { + python3 - "$REPO_DIR" "$STATE_FILE" "$AGENT_TARGET" "$SKILLS_DIR" <<'PYEOF' +import json, sys, pathlib +repo, state_file, agent, skills_dir = sys.argv[1:5] +root = pathlib.Path(repo) +state = {} +if pathlib.Path(state_file).is_file(): + try: state = json.loads(pathlib.Path(state_file).read_text()) + except Exception: state = {} +rows = [] +for pj in sorted(root.glob('skills-*/*-plugin/.claude-plugin/plugin.json')): + try: meta = json.loads(pj.read_text()) + except Exception: continue + name = meta.get('install_name') + if not name: continue + status = meta.get('status', 'promoted') + want = meta.get('version', '') + got = state.get(name, {}).get('version', '') + itype = state.get(name, {}).get('install_type', '') + drift = '' if got == want else ('missing' if not got else 'stale') + rows.append((name, status, want, got or '-', itype or '-', drift)) +drift_rows = [r for r in rows if r[5]] +print(f'audit agent={agent} skills_dir={skills_dir}') +print(f'{"name":34} {"status":10} {"repo":8} {"installed":9} {"mode":8} drift') +for r in rows: + print(f'{r[0]:34} {r[1]:10} {r[2]:8} {r[3]:9} {r[4]:8} {r[5]}') +print(f'\n{len(rows)} 个技能,{len(drift_rows)} 个漂移(未安装/版本落后)') +raise SystemExit(1 if drift_rows else 0) +PYEOF +} + # ── Main ─────────────────────────────────────────────────────────────────────── main() { if [[ "$LIST_ONLY" == true ]]; then @@ -429,7 +507,19 @@ main() { return fi + if [[ "$AUDIT_ONLY" == true ]]; then + audit_target + return + fi + info "Installing skills for $AGENT_TARGET from: $REPO_DIR" + if [[ "$NO_VALIDATE" != true && -f "$REPO_DIR/scripts/validate-skills.py" ]]; then + if ! python3 "$REPO_DIR/scripts/validate-skills.py" >/tmp/ai-proj-helper-validate.log 2>&1; then + error "validate-skills.py 未通过,修复后再装(或加 --no-validate 跳过)" + tail -20 /tmp/ai-proj-helper-validate.log >&2 || true + exit 1 + fi + fi [[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written" [[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER" diff --git a/scripts/generate-catalog.py b/scripts/generate-catalog.py new file mode 100755 index 0000000..ea8474a --- /dev/null +++ b/scripts/generate-catalog.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +"""Generate catalog.json — the reviewable list of every skill in this repo. + +Usage: python3 scripts/generate-catalog.py [--check] + (default) write catalog.json + --check fail if catalog.json is out of date (for CI) +""" +from __future__ import annotations + +import hashlib +import json +import re +import sys +from datetime import datetime, timezone +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +CATALOG = ROOT / "catalog.json" + + +def frontmatter(text: str) -> dict: + if not text.startswith("---"): + return {} + end = text.find("\n---", 3) + if end == -1: + return {} + data: dict = {} + metadata: dict = {} + key = None + for line in text[3:end].splitlines(): + if not line.strip(): + continue + m = re.match(r"^([A-Za-z0-9_-]+):\s*(.*)$", line) + if m: + key = m.group(1) + data[key] = m.group(2).strip().strip('"').strip("'") + continue + m = re.match(r"^\s+([A-Za-z0-9_-]+):\s*(.*)$", line) + if m and key == "metadata": + metadata[m.group(1)] = m.group(2).strip().strip('"').strip("'") + if metadata: + data["metadata"] = metadata + return data + + +def build() -> dict: + skills = [] + for plugin_json in sorted(ROOT.glob("skills-*/*-plugin/.claude-plugin/plugin.json")): + plugin_dir = plugin_json.parent.parent + meta = json.loads(plugin_json.read_text(encoding="utf-8")) + skill_files = sorted((plugin_dir / "skills").rglob("SKILL.md")) + if not skill_files: + continue + skill_md = skill_files[0] + fm = frontmatter(skill_md.read_text(encoding="utf-8", errors="replace")) + desc = fm.get("description", "") + body = skill_md.read_text(encoding="utf-8", errors="replace") + skills.append( + { + "name": meta.get("install_name") or fm.get("name"), + "category": meta.get("dir_category"), + "version": meta.get("version"), + "status": meta.get("status", "promoted"), + "invocation": (fm.get("metadata") or {}).get("invocation", "model-invoked"), + "description": desc, + "description_len": len(desc), + "path": str(skill_md.relative_to(ROOT)), + "digest": hashlib.sha256(body.encode("utf-8")).hexdigest()[:16], + } + ) + counts: dict = {} + for skill in skills: + key = f"{skill['status']}/{skill['invocation']}" + counts[key] = counts.get(key, 0) + 1 + return { + "repo": "ai-proj-helper", + "generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "total": len(skills), + "counts": counts, + "skills": skills, + } + + +def main() -> int: + catalog = build() + text = json.dumps(catalog, ensure_ascii=False, indent=2) + "\n" + if "--check" in sys.argv: + if not CATALOG.is_file(): + print("catalog.json 不存在,请运行 python3 scripts/generate-catalog.py") + return 1 + current = json.loads(CATALOG.read_text(encoding="utf-8")) + current.pop("generated_at", None) + fresh = dict(catalog) + fresh.pop("generated_at", None) + if current != fresh: + print("catalog.json 已过期,请重新生成") + return 1 + print("catalog.json 是最新的") + return 0 + CATALOG.write_text(text, encoding="utf-8") + print(f"写入 {CATALOG.relative_to(ROOT)}:{catalog['total']} 个技能 {catalog['counts']}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/scan-allowlist.txt b/scripts/scan-allowlist.txt new file mode 100644 index 0000000..35f462c --- /dev/null +++ b/scripts/scan-allowlist.txt @@ -0,0 +1,5 @@ +# 安全扫描允许清单(人工确认过的误报) +# 格式:<路径子串>::<匹配文本中的特征串> +# 例:某技能文档把危险命令当作“禁止清单”引用,而非真的要执行。 +skills-dev/slark-cicd-plugin::NEVER_AUTO +skills-dev/slark-cicd-plugin::destructive diff --git a/scripts/scan-skill.sh b/scripts/scan-skill.sh new file mode 100755 index 0000000..deed20c --- /dev/null +++ b/scripts/scan-skill.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# scan-skill.sh — security scan before a skill enters the team library. +# +# Usage: ./scripts/scan-skill.sh [plugin-dir ...] +# With no arguments scans every skills-*/*-plugin directory. +# Exit 0 = clean (warnings allowed), 1 = high severity finding. +set -uo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +HIGH=0 +WARN=0 + +# High severity: destructive, remote-code-execution, secret material. +HIGH_PATTERNS=( + 'rm[[:space:]]+-[a-zA-Z]*r[a-zA-Z]*[[:space:]]+/($|[[:space:]])' + 'curl[^|]*\|[[:space:]]*(ba|z)?sh' + 'wget[^|]*\|[[:space:]]*(ba|z)?sh' + 'chmod[[:space:]]+777' + 'BEGIN (RSA|OPENSSH|EC|DSA) PRIVATE KEY' + 'sk-[A-Za-z0-9]{16,}' + 'AKIA[0-9A-Z]{16}' + 'ghp_[A-Za-z0-9]{20,}' +) +# Warnings: machine-specific paths, plain http endpoints. +WARN_PATTERNS=( + '/Users/[A-Za-z0-9._-]+/' + 'http://[A-Za-z0-9.-]+' + 'password[[:space:]]*=[[:space:]]*[^$]' +) + +targets=("$@") +if [[ ${#targets[@]} -eq 0 ]]; then + while IFS= read -r dir; do + targets+=("$(dirname "$(dirname "$dir")")") + done < <(find "$ROOT" -path "*/skills-*/*-plugin/.claude-plugin/plugin.json" | sort) +fi + +ALLOWLIST="$ROOT/scripts/scan-allowlist.txt" +is_allowlisted() { + # is_allowlisted + local path="$1" line="$2" entry sub needle + [[ -f "$ALLOWLIST" ]] || return 1 + while IFS= read -r entry; do + [[ -z "$entry" || "$entry" == \#* ]] && continue + sub="${entry%%::*}" + needle="${entry#*::}" + if [[ "$path" == *"$sub"* && "$line" == *"$needle"* ]]; then + return 0 + fi + done < "$ALLOWLIST" + return 1 +} + +for dir in "${targets[@]}"; do + rel="${dir#"$ROOT"/}" + for pattern in "${HIGH_PATTERNS[@]}"; do + while IFS= read -r hit; do + abs="${hit%%:*}" + detail="${hit#*:}" + if is_allowlisted "$abs" "$hit"; then + echo "[allow] $rel: $detail" + continue + fi + echo "[HIGH] $rel: $detail" + HIGH=$((HIGH + 1)) + done < <(grep -rnE --include='*.md' --include='*.sh' --include='*.py' --include='*.js' --include='*.ts' --include='*.json' -- "$pattern" "$dir" 2>/dev/null | cut -c1-200) + done + for pattern in "${WARN_PATTERNS[@]}"; do + while IFS= read -r hit; do + echo "[warn] $rel: ${hit%%:*}:${hit#*:}" + WARN=$((WARN + 1)) + done < <(grep -rnE --include='*.md' --include='*.sh' --include='*.py' --include='*.js' --include='*.ts' -- "$pattern" "$dir" 2>/dev/null | cut -c1-200) + done +done + +echo "" +echo "扫描完成:${#targets[@]} 个插件,$HIGH 个高危,$WARN 个警告" +if [[ "$HIGH" -gt 0 ]]; then + echo "存在高危项,禁止入库,除非逐条确认并记录原因。" + exit 1 +fi +exit 0 diff --git a/scripts/validate-skills.py b/scripts/validate-skills.py new file mode 100755 index 0000000..803ca96 --- /dev/null +++ b/scripts/validate-skills.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +"""Validate plugins and SKILL.md files against the Agent Skills spec + team rules. + +Usage: python3 scripts/validate-skills.py [--strict] +Exit 0 = pass, 1 = errors found. +""" +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +ALLOWED_FRONTMATTER = { + "name", "description", "license", "compatibility", "metadata", + "allowed-tools", "disable-model-invocation", "version", +} +NAME_RE = re.compile(r"^[a-z0-9][a-z0-9-]{0,63}$") +BODY_MAX_BYTES = 20 * 1024 +DESC_MIN, DESC_MAX = 30, 1024 +STATUSES = {"promoted", "beta", "deprecated"} +INVOCATIONS = {"model-invoked", "user-invoked"} +REQUIRED_PLUGIN_FIELDS = ("install_name", "install_type", "dir_category", "version") + +errors: list[str] = [] +warnings: list[str] = [] + + +def parse_frontmatter(text: str): + """Return (frontmatter dict, body text). Supports one level of nesting.""" + if not text.startswith("---"): + return {}, text + end = text.find("\n---", 3) + if end == -1: + return {}, text + raw, body = text[3:end], text[end + 4:] + data: dict = {} + metadata: dict = {} + key = None + for line in raw.splitlines(): + if not line.strip(): + continue + m = re.match(r"^([A-Za-z0-9_-]+):\s*(.*)$", line) + if m: + key = m.group(1) + data[key] = m.group(2).strip().strip('"').strip("'") + continue + m = re.match(r"^\s+([A-Za-z0-9_-]+):\s*(.*)$", line) + if m and key == "metadata": + metadata[m.group(1)] = m.group(2).strip().strip('"').strip("'") + elif key: + data[key] = (data.get(key, "") + " " + line.strip()).strip() + if metadata: + data["metadata"] = metadata + return data, body + + +def check_plugin(plugin_json: Path): + plugin_dir = plugin_json.parent.parent + rel = plugin_dir.relative_to(ROOT) + try: + meta = json.loads(plugin_json.read_text(encoding="utf-8")) + except Exception as exc: # noqa: BLE001 + errors.append(f"{rel}: plugin.json 解析失败: {exc}") + return + + for field in REQUIRED_PLUGIN_FIELDS: + if not meta.get(field): + errors.append(f"{rel}: plugin.json 缺少 {field}") + status = meta.get("status", "") + if status and status not in STATUSES: + errors.append(f"{rel}: status 非法 {status!r}(应为 {sorted(STATUSES)})") + install_name = meta.get("install_name", "") + if install_name and not NAME_RE.match(install_name): + errors.append(f"{rel}: install_name 不合规 {install_name!r}") + + skills_dir = plugin_dir / "skills" + skill_files = sorted(skills_dir.rglob("SKILL.md")) if skills_dir.is_dir() else [] + if not skill_files: + errors.append(f"{rel}: 没有找到 skills/**/SKILL.md") + return + for skill_md in skill_files: + check_skill(rel, skill_md, meta) + + +def check_skill(rel: Path, skill_md: Path, meta: dict): + text = skill_md.read_text(encoding="utf-8", errors="replace") + fm, body = parse_frontmatter(text) + where = f"{rel}/{skill_md.name}" + + name = fm.get("name", "") + if not name: + errors.append(f"{where}: frontmatter 缺少 name") + elif not NAME_RE.match(name): + errors.append(f"{where}: name 不合规 {name!r}(小写字母/数字/连字符,≤64)") + + desc = fm.get("description", "") + if not desc: + errors.append(f"{where}: frontmatter 缺少 description") + elif not (DESC_MIN <= len(desc) <= DESC_MAX): + warnings.append(f"{where}: description 长度 {len(desc)},建议 {DESC_MIN}-{DESC_MAX}(决定是否被触发)") + + for key in fm: + if key == "metadata": + continue + if key not in ALLOWED_FRONTMATTER: + warnings.append(f"{where}: 非标准 frontmatter 字段 {key!r},建议移入 metadata") + + body_bytes = len(body.encode("utf-8")) + if body_bytes > BODY_MAX_BYTES: + warnings.append(f"{where}: 正文 {body_bytes} 字节,超过 20KB 预算,建议拆 references/") + + metadata = fm.get("metadata") or {} + invocation = metadata.get("invocation", "") + if invocation and invocation not in INVOCATIONS: + errors.append(f"{where}: metadata.invocation 非法 {invocation!r}") + disable_model = str(fm.get("disable-model-invocation", "")).lower() == "true" + if invocation == "user-invoked" and not disable_model: + errors.append(f"{where}: user-invoked 技能必须设置 disable-model-invocation: true") + if invocation == "model-invoked" and disable_model: + errors.append(f"{where}: model-invoked 技能不应设置 disable-model-invocation: true") + + status = meta.get("status", "") + if status == "promoted": + docs = ROOT / "docs" / "skills" / f"{meta.get('install_name', name)}.md" + if not docs.is_file(): + warnings.append(f"{where}: promoted 技能缺少四段式文档 docs/skills/{docs.name}") + + # Relative links must resolve. + for target in re.findall(r"\]\((\.[^)\s]+|[A-Za-z0-9_-]+/[^)\s]+)\)", body): + if target.startswith(("http://", "https://", "#")): + continue + if not (skill_md.parent / target).exists(): + warnings.append(f"{where}: 引用的相对路径不存在: {target}") + + +def main() -> int: + strict = "--strict" in sys.argv + plugins = sorted(ROOT.glob("skills-*/*-plugin/.claude-plugin/plugin.json")) + if not plugins: + print("未找到任何 plugin.json", file=sys.stderr) + return 1 + for plugin_json in plugins: + check_plugin(plugin_json) + + for warning in warnings: + print(f"[warn] {warning}") + for error in errors: + print(f"[error] {error}") + print(f"\n检查 {len(plugins)} 个插件:{len(errors)} 个错误,{len(warnings)} 个警告") + if errors: + return 1 + if strict and warnings: + print("--strict 模式下,警告视为失败") + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/skills-core/ai-proj-helper-entry-plugin/.claude-plugin/plugin.json b/skills-core/ai-proj-helper-entry-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..ddd6c96 --- /dev/null +++ b/skills-core/ai-proj-helper-entry-plugin/.claude-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "ai-proj-helper-entry-plugin", + "description": "技能库路由:列出技能、什么任务用哪个、交付终点口径。由人主动调用,不占模型目录 token。", + "version": "0.1.0", + "author": { + "name": "qiudl" + }, + "install_name": "ai-proj-helper-entry", + "install_type": "skill", + "dir_category": "core", + "status": "beta", + "invocation": "user-invoked" +} diff --git a/skills-core/ai-proj-helper-entry-plugin/skills/SKILL.md b/skills-core/ai-proj-helper-entry-plugin/skills/SKILL.md new file mode 100644 index 0000000..3f7c491 --- /dev/null +++ b/skills-core/ai-proj-helper-entry-plugin/skills/SKILL.md @@ -0,0 +1,77 @@ +--- +name: ai-proj-helper-entry +description: ai-proj-helper 技能库路由:告诉你有哪些技能、什么任务用哪个、以及「REQ released + PDV 通过才算交付」的强制口径。人在开始需求/开发/评审/发布任务前主动调用。 +metadata: + invocation: user-invoked + owner: qiudl +disable-model-invocation: true +--- + +# ai-proj-helper 入口(路由器) + +## 0. 这个技能是什么 + +一个**纯人触发**的路由器:人问「该用哪个技能 / 从哪开始」,就读这里。它不进模型目录,所以不占每次会话的目录 token;代价是必须由人主动喊。 + +> 路由规则:**任何技能增、删、改名、改行为后,必须回改本文件**。一个没提到新技能、或还指向已删技能的路由器,就是假的路由器(见 `skill-creator` §9)。 + +## 1. 交付终点(强制,优先于路由) + +开发任务的交付终点是:需求按 REQ 流程推进到具备发布条件并完成上线(`delivery_stage=released` + PDV 验收通过)。 + +- 写代码、过单测、提 PR、过 internal gate、合并代码,都是过程节点,**不得当作交付终点**; +- 任务 `completed` ≠ 需求完成;REQ 未 `released` 不得报完成; +- 汇报格式:**当前 REQ 阶段 + 下一个要做的节点**; +- 只有必须由人拍板/授权的阻塞(生产发布授权、密钥权限、需求变更、无法自动修复的失败)才停下来问,并写清卡点与下一步。 + +## 2. 主流程:需求 → 上线 + +``` +讨论(req) → PRD(req-prd) → 评审(req-review) → 设计(req-design) +→ 开发(dev-coding / karpathy-guidelines) → 测试(dev-test + req-test-gate) +→ 代码评审(dev-review) → 发布(publish / slark-cicd / slark-dsh-cicd) → PDV 验收 → released +``` + +| 阶段 | 技能 | +| --- | --- | +| 讨论/调研 | `req`、`req-research`、`req-compare` | +| PRD | `req-prd`、`req-prototype` | +| 评审 | `req-review` | +| 设计/拆任务 | `req-design`、`dev-arch`、`db-migration` | +| 编码 | `dev-coding`、`karpathy-guidelines` | +| 测试 | `dev-test`、`req-test-gate` | +| 代码评审 | `dev-review`、`review-checklist` | +| 发布 | `publish`、`slark-cicd`、`slark-dsh-cicd`、`deploy-rollback` | +| 部署后 | `req-audit`、`req-lookback` | +| 复盘 | `req-retro` | +| 项目管理 | `project-management`、`pm-risk`、`pm-ask` | +| 建/改技能 | `skill-creator` | +| 汇报完成前 | `verification-before-completion` | + +## 3. 按任务类型的旁路 + +- 「这个 bug 很难查」→ `diagnosing-bugs`(先建红循环再推理) +- 「帮我审这个 PR」→ `dev-review` +- 「发版」→ 对应 `*-cicd` runbook,不是通用 `dev-deploy` +- 「不确定该用哪个」→ 读到这里就够了,别猜 + +## 4. 红线 + +- 不得自审批(提交人不能批自己的 REQ) +- 不得绕过门禁(测试 Gate、发布 Gate、归档 Gate) +- 不得把「某步骤完成」当结束 +- 不得无证据声称完成(见 `verification-before-completion`) +- 不得把凭据/内网地址/绝对路径写进技能或文档 + +## 5. 技能从哪来 + +- 用户级:`~/.agents/skills/`(Codex)、`$DSH_HOME/skills/`(DSH) +- 项目级:项目根 `.agents/skills/` +- **真相源**:`ai-proj-helper` 仓库;本机目录是安装产物,不要直接改 +- 个人技能:`skills-personal/`(不入库、不发布) + +## 6. 维护检查 + +- `./install-skills.sh --audit` 漂移数 > 0 → 先同步再干活 +- 技能有增删改 → 本文件 + `catalog.json` 必须同 PR 回改 +- 每季度人工过一遍本路由,删掉不再用的技能引用 diff --git a/skills-core/ai-proj-helper-entry-plugin/skills/evals/evals.json b/skills-core/ai-proj-helper-entry-plugin/skills/evals/evals.json new file mode 100644 index 0000000..198478a --- /dev/null +++ b/skills-core/ai-proj-helper-entry-plugin/skills/evals/evals.json @@ -0,0 +1,24 @@ +{ + "skill_name": "ai-proj-helper-entry", + "skill_version": "0.1.0", + "evals": [ + { + "id": 1, + "kind": "happy_path", + "prompt": "我要给 qiu-slark 做个新功能,从哪开始", + "expected_output": "给出 req → req-prd → req-review → req-design 的路径,并声明交付终点是 released + PDV,不是写完代码" + }, + { + "id": 2, + "kind": "edge_case", + "prompt": "我已经把单测跑过了,这个需求可以算完成了吗", + "expected_output": "否定:单测只是过程节点,REQ 未 released 不算完成;给出当前阶段与下一节点" + }, + { + "id": 3, + "kind": "failure_recovery", + "prompt": "你说的那个技能我机器上没装,怎么办", + "expected_output": "说明技能真相源在 ai-proj-helper 仓库、本机目录是安装产物;给出 install-skills.sh 安装/审计命令" + } + ] +} diff --git a/skills-core/skill-creator-plugin/.claude-plugin/plugin.json b/skills-core/skill-creator-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..159c420 --- /dev/null +++ b/skills-core/skill-creator-plugin/.claude-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "skill-creator-plugin", + "description": "团队技能创建与维护的标准流程:收录门槛、分桶生命周期、调用模式、evals、四段式文档、路由回改。", + "version": "0.1.0", + "author": { + "name": "qiudl" + }, + "install_name": "skill-creator", + "install_type": "skill", + "dir_category": "core", + "status": "beta", + "invocation": "user-invoked" +} diff --git a/skills-core/skill-creator-plugin/skills/SKILL.md b/skills-core/skill-creator-plugin/skills/SKILL.md new file mode 100644 index 0000000..e32e763 --- /dev/null +++ b/skills-core/skill-creator-plugin/skills/SKILL.md @@ -0,0 +1,127 @@ +--- +name: skill-creator +description: 团队技能的标准流程:收录门槛、分桶生命周期、调用模式、SKILL.md 规范、evals 全量、四段式文档、路由回改。当要新建技能、大改现有技能、或评审一个技能是否合格时使用。 +metadata: + invocation: user-invoked + owner: qiudl +disable-model-invocation: true +--- + +# 技能创建(团队标准流程) + +## 0. 一句话 + +先有真实失败,再写技能;没有 evals 的技能不算完成;**技能目录是预算,不是收藏夹**。 + +## 1. 何时用 + +- 新建技能 +- 大改现有技能(改 description、改核心流程、改门禁) +- 评审别人提上来的技能 +- 判断某个想法「该不该做成技能」 + +何时不用:只改错别字/格式 → 直接改;一次性个人偏好 → 放个人技能,不进团队。 + +## 2. 收录门槛(先过这一关,再谈怎么写) + +新技能**默认拒绝**,只有同时满足两条才立项: + +1. **真实失败**:能说出在哪个真实任务/会话里出了问题——跑了什么、期望什么、实际什么。假想改进(「这样会更好」)不算。 +2. **组合不出来**:用现有技能组合做不到;能组合的,就改现有技能,不新增。 + +被拒的想法记进仓库 `.out-of-scope/<概念>.md`,写清理由,避免下次重复讨论。 + +## 3. 分桶与生命周期 + +| 桶 | 含义 | 是否安装 | 是否进 README / plugin.json | +| --- | --- | --- | --- | +| `promoted` | 已验证、日常在用 | 默认安装 | 必须出现 | +| `beta` | 公开试跑,收反馈 | 需 `--include-beta` | 不进默认清单 | +| `deprecated` | 不再用 | 不安装 | 留文档,标弃用 | + +- 新技能一律先进 `beta`,跑够真实使用 + evals 通过才 `promoted`。 +- 只有 `promoted` 能进模型目录;beta 不占目录预算。 + +## 4. 调用模式(省目录 token 的关键) + +每个技能二选一,写进 frontmatter: + +- **`model-invoked`**(默认):进模型目录,agent 自己判断何时用。 +- **`user-invoked`**:只由人下命令触发,**不进模型目录**;必须同时写 `disable-model-invocation: true` 和 `metadata.invocation: user-invoked`。 + +判定口径:这件事是不是「人下命令才开始」?是 → user-invoked。典型:publish、retro、triage、发布 runbook、建技能。 + +## 5. SKILL.md 硬约束(Agent Skills 规范) + +- 目录:`SKILL.md` + 可选 `scripts/`、`references/`、`assets/` +- frontmatter 必填:`name`(小写字母/数字/连字符,≤64)、`description`(≤1024,写清「做什么 + 何时用」) +- 可选:`license`、`compatibility`、`metadata`、`allowed-tools` +- **非标准字段**一律进 `metadata` +- 正文 ≤20KB(约 5000 token),细节拆 `references/` +- 只写 agent 不知道的东西:项目约定、边界、坑;不写通用常识 + +## 6. 正文结构模板 + +``` +# 名称 +## 0. 一句话 +## 1. 何时用 / 何时不用 +## 2. 步骤(可执行、有顺序) +## 3. 硬约束与红线 +## 4. 常见坑(gotchas) +## 5. 验证清单 +## 6. 参考(references/ 链接) +``` + +## 7. evals(强制、全量) + +- 路径:`evals/evals.json`;至少 3 条:正常路径 / 边界输入 / 失败恢复 +- 跑「有技能 / 无技能」对比,结果存 `iteration-/`,按 rubric 打分,PR 附结果 + +## 8. 四段式文档(每个 promoted 技能一篇) + +`docs/skills/.md`,四节固定顺序: + +1. **What it does** +2. **When to reach for it** +3. **Common questions** +4. **It's working if**(必须给可验证证据,不许写「感觉对了」) + +beta 不写文档;弃用保留文档并标 archived。 + +## 9. 路由回改(硬规则) + +所有技能增、删、改名、改行为后,**必须同步回改入口技能 `ai-proj-helper-entry` 和 `catalog.json`**。一个没提到新技能、或还在路由到已删技能的路由器,就是假的路由器。 + +## 10. 质量门禁(提 PR 前逐条打勾) + +- [ ] 过了收录门槛(真实失败 + 组合不出来) +- [ ] 桶与调用模式已标,`beta` 不得出现在默认清单 +- [ ] `name`/`description` 合规,description 含「何时用」 +- [ ] 正文 ≤20KB,细节已拆 references +- [ ] evals ≥3 条,有「有/无技能」对比 +- [ ] 四段式文档已写(promoted 才需要) +- [ ] 入口路由与 `catalog.json` 已回改 +- [ ] `plugin.json` 已登记 `install_name`/`install_type`/`dir_category`/`status`/版本号 +- [ ] `python3 scripts/validate-skills.py` 通过 +- [ ] `./scripts/scan-skill.sh` 无高危项 +- [ ] 版本号与 CHANGELOG 已更新 +- [ ] 无绝对路径、无凭据、无内网地址 + +## 11. 反模式 + +- 一次写 800 行「大全」,什么都想覆盖 +- description 写成「各种任务都能用」 +- 没有 evals 就提 PR;没有四段式文档就 promoted +- 直接复制外部技能,不改写成我们的 REQ/ai-proj 语境 +- 把临时排障步骤固化成团队技能(这类放 personal) +- 技能改名后忘了回改路由 + +## 12. 评审别人技能时看什么 + +1. 收录门槛过没过(有没有真实失败) +2. description 能不能让模型判断「何时用」 +3. 桶与调用模式是否正确(该 user-invoked 的别占目录) +4. 和现有技能是否重复(先查 `catalog.json`) +5. evals 是否覆盖失败路径、文档是否有「It's working if」 +6. 是否触碰红线(自审批、绕过门禁、绝对路径、凭据) diff --git a/skills-core/skill-creator-plugin/skills/evals/evals.json b/skills-core/skill-creator-plugin/skills/evals/evals.json new file mode 100644 index 0000000..ee3b94b --- /dev/null +++ b/skills-core/skill-creator-plugin/skills/evals/evals.json @@ -0,0 +1,24 @@ +{ + "skill_name": "skill-creator", + "skill_version": "0.1.0", + "evals": [ + { + "id": 1, + "kind": "happy_path", + "prompt": "我想加一个新技能,用来在每次部署后自动跑一遍冒烟", + "expected_output": "先问真实失败场景(哪次部署出过问题、跑了什么、期望什么),再判断现有 req-lookback/req-audit 能否组合;给出 bucket/调用模式/evals 计划" + }, + { + "id": 2, + "kind": "edge_case", + "prompt": "直接帮我把这个想法写成 SKILL.md:一个能自动优化代码风格的技能", + "expected_output": "拒绝直接写,指出没有真实失败证据,要求先给案例;若无证据则建议放个人技能" + }, + { + "id": 3, + "kind": "failure_recovery", + "prompt": "技能有 evals 但 validate-skills.py 报了 name 不合规,怎么处理", + "expected_output": "说明 name 规则(小写/数字/连字符、≤64),给出改名步骤,并提示要同步 install_name、catalog、入口路由" + } + ] +} diff --git a/skills-dev/agent-swarm-plugin/skills/SKILL.md b/skills-dev/agent-swarm-plugin/skills/SKILL.md index 52c8f61..5a586ad 100644 --- a/skills-dev/agent-swarm-plugin/skills/SKILL.md +++ b/skills-dev/agent-swarm-plugin/skills/SKILL.md @@ -404,3 +404,14 @@ ssh melbourne "cd /Users/coolbuy-dev/coding/new-ai-proj && \ - [OpenAI Swarm 文档](https://github.com/openai/swarm) - [Multi-Agent Systems 设计模式](https://arxiv.org/abs/2308.00352) - [Claude Code Skills 文档](https://docs.anthropic.com/claude-code/skills) + +## 并行编排流程 + +把大任务拆给多个子 agent 时按这个顺序: + +1. **先划写入边界**:每个子 agent 拥有互不重叠的目录/文件;共享文件(锁文件、入口文件)由编排者最后统一改。 +2. **子 agent 必须新上下文**:不要 fork 父上下文,否则它继承了本该甩掉的包袱。 +3. **每个子任务给验收标准 + 回报格式**:三句话(结果 / 证据路径 / 下一步)。 +4. **子 agent 不做合并与发布**:只交分支或补丁,合并由编排者做。 +5. **汇总时先跑集成验证**,再回报;冲突由编排者解,不让子 agent 互改。 +6. 两个子 agent 不得写同一文件;不确定时先串行。 diff --git a/skills-dev/dev-review-plugin/skills/SKILL.md b/skills-dev/dev-review-plugin/skills/SKILL.md index 6611403..ecbef4b 100644 --- a/skills-dev/dev-review-plugin/skills/SKILL.md +++ b/skills-dev/dev-review-plugin/skills/SKILL.md @@ -303,3 +303,13 @@ mcp__ai-proj__link_tasks_to_requirement({ 4. **严重度准确** — 不要所有问题都标 High,按实际影响分级 5. **建议可操作** — 每个发现必须附带具体修复建议 6. **关注变更** — 评审范围是 diff,不要对未变更的代码提意见(除非变更引入了对旧代码的新风险) + +## 接收与响应评审意见 + +评审不是单向输出,收到意见后按这套来: + +1. **先分类**:阻断项(必须修)/ 建议项(可讨论)/ 澄清项(问题理解不一致)。 +2. **先复述再回应**:用自己的话重述意见,确认理解一致,再给证据或修改。 +3. **不辩解**:用证据说话(代码、测试、日志),不用语气词反驳。 +4. **逐条回评**:每条写「已修(commit)/ 不修(理由)/ 需澄清(具体问题)」,不得默默跳过。 +5. **阻断项没修完不得合并**;建议项不修要记录原因,进 PR 描述。 diff --git a/skills-dev/dev-test-plugin/skills/dev-test/SKILL.md b/skills-dev/dev-test-plugin/skills/dev-test/SKILL.md index bf8ad79..aeb8778 100644 --- a/skills-dev/dev-test-plugin/skills/dev-test/SKILL.md +++ b/skills-dev/dev-test-plugin/skills/dev-test/SKILL.md @@ -215,3 +215,11 @@ AI 根据需求变更范围动态生成 Playwright spec,模板见 `templates/p 若 git diff 显示同一功能的 `handlers/`、`middleware/`、`routes/` 文件均有变更(通过命名模式识别,如 `impersonation_handler.go` + `impersonation_middleware.go` + `impersonation_routes.go`),则除单元测试外**额外生成** `backend/tests/` 下的集成测试。 识别方式:提取文件名中的功能前缀(如 `impersonation`),若在三个目录中均出现,则触发集成测试生成。 + +## TDD 循环(红 → 绿 → 重构) + +1. **一次只做一个行为**:写一个小测试,先确认它**失败**,并确认失败原因就是你要修的那件事(不是编译错误/环境问题)。 +2. **最小实现让它变绿**,不做顺手重构。 +3. **绿了再重构**,重构期间测试保持绿。 +4. 禁止先写实现再补测试;补的测试要能证明它真的会红(临时改坏一次验证)。 +5. 交付时附:测试命令、通过/失败数、以及「曾经红过」的证据(日志或截图记录)。 diff --git a/skills-req/req-design-plugin/skills/SKILL.md b/skills-req/req-design-plugin/skills/SKILL.md index bc24be2..3895cc8 100644 --- a/skills-req/req-design-plugin/skills/SKILL.md +++ b/skills-req/req-design-plugin/skills/SKILL.md @@ -474,3 +474,13 @@ PRD 说「做什么」(用户故事、业务规则、验收标准),设计 | V1.0 | 2026-01-26 | 初始版本(原名 req-dev) | | V2.0 | 2026-04-06 | 重构为 req-design:移除架构指南和编码规范,聚焦 API 契约 + 任务拆分 | | V2.1 | 2026-04-16 | 新增 Memory 隔离规则(REQ-20260416-0017) | + +## 任务依赖边(blocking edges) + +拆子任务时,每个任务必须显式声明依赖,而不是只给层级: + +- 每个任务写 `blockers: [任务编号...]`,没有依赖就写 `blockers: []`; +- **被阻塞的任务不得先开工**,即使它看起来更简单; +- 依赖图落进需求的任务描述,供 ai-proj / PM 检查; +- 出现循环依赖直接拒绝拆分方案,重新设计边界; +- 验收时检查:所有 blockers 是否 completed,再开自己。 diff --git a/skills-req/verification-before-completion-plugin/.claude-plugin/plugin.json b/skills-req/verification-before-completion-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..bbd50f6 --- /dev/null +++ b/skills-req/verification-before-completion-plugin/.claude-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "verification-before-completion-plugin", + "description": "汇报完成/关闭任务/提交 PR 前必须先跑验证并附证据;没有证据不得声称完成。", + "version": "0.1.0", + "author": { + "name": "qiudl" + }, + "install_name": "verification-before-completion", + "install_type": "skill", + "dir_category": "req", + "status": "beta", + "invocation": "model-invoked" +} diff --git a/skills-req/verification-before-completion-plugin/skills/SKILL.md b/skills-req/verification-before-completion-plugin/skills/SKILL.md new file mode 100644 index 0000000..a808c35 --- /dev/null +++ b/skills-req/verification-before-completion-plugin/skills/SKILL.md @@ -0,0 +1,55 @@ +--- +name: verification-before-completion +description: 汇报「完成/修好/通过」或关闭任务、提交 PR、宣布 REQ 完成之前,必须先运行验证命令并附证据;没有证据不得声称完成。当准备说完成、关闭任务、或汇报交付前使用。 +metadata: + invocation: model-invoked + owner: qiudl +--- + +# 完成前验证 + +## 0. 一句话 + +**没有证据的「完成」不算完成。** + +## 1. 何时用 + +- 准备说「搞定了 / 修好了 / 通过了 / 可以发了」 +- 准备把任务标 `completed`、关 issue、提 PR +- 准备宣布 REQ 完成或可发布 +- 收到「你确认一下」这类要求时 + +何时不用:还在探索阶段、明确记录的是中间发现(这时要写「未验证」而不是「完成」)。 + +## 2. 证据三件套 + +1. **命令**:原样可复制,别人能重跑 +2. **输出关键行**:可读文本,不要只看截图 +3. **判定**:退出码 / 通过数 / 失败数 + +格式:`验证:<命令> → <结果>(通过 N / 失败 M),证据:<日志路径或输出片段>` + +## 3. 按类型的验证清单 + +| 改动类型 | 必须验证 | +| --- | --- | +| 代码改动 | 构建 + 单测 + 类型检查(有则跑) | +| bug 修复 | 先复现(证明坏)→ 修复 → 同一用例再跑(证明好) | +| 需求级交付 | 验收标准逐条打勾 + PDV 验收通过 | +| 发布/部署 | 健康检查 + E2E + 回滚预案可用 | +| 配置/文档 | 生效验证(如 `--dump-config` 结果、命令输出) | +| 数据变更 | 变更前后数据抽查 + 回滚脚本验证 | + +## 4. 反模式 + +- 「应该可以」「本地没问题」「理论上过了」 +- 只贴成功截图,不贴命令 +- 跳过失败用例不说明 +- 把「编译通过」当成「功能可用」 +- 把「测试跑了一部分」说成「全部通过」 + +## 5. 与 ai-proj 对接 + +- 任务标 `completed` 前,把证据挂到该任务文档; +- REQ 未 `released` 时不得报需求完成(见 `ai-proj-helper-entry` 的交付终点); +- 证据缺失时,正确做法是状态写 `in_progress` 并说明「还差哪项验证」。 diff --git a/skills-req/verification-before-completion-plugin/skills/evals/evals.json b/skills-req/verification-before-completion-plugin/skills/evals/evals.json new file mode 100644 index 0000000..a70fddf --- /dev/null +++ b/skills-req/verification-before-completion-plugin/skills/evals/evals.json @@ -0,0 +1,24 @@ +{ + "skill_name": "verification-before-completion", + "skill_version": "0.1.0", + "evals": [ + { + "id": 1, + "kind": "happy_path", + "prompt": "我改完了登录接口,可以提交了吗", + "expected_output": "要求给出构建/单测命令与结果、失败数;附证据路径后再提交" + }, + { + "id": 2, + "kind": "edge_case", + "prompt": "测试环境没有依赖装不上,先合了吧,本地我手动看过没问题", + "expected_output": "拒绝以「手动看过」作为证据;说明缺失依赖要记录为未验证项,状态保持 in_progress" + }, + { + "id": 3, + "kind": "failure_recovery", + "prompt": "测试跑过了 10 个,还有 2 个没跑,能说全部通过吗", + "expected_output": "不能:必须写明通过 10 / 未跑 2 及原因,不得声称全部通过" + } + ] +}