diff --git a/CHANGELOG.md b/CHANGELOG.md index 14dfec7..f34fe1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,3 +40,11 @@ - 新增 `.gitea/workflows/skill-gate.yml`:PR/main 跑 `validate --strict` + `scan` + `catalog --check` + 安装器测试。 - 新增 `MAINTENANCE.md`:技能维护节奏(每日漂移、每周 evals 抽样、每月目录审阅、每季度治理复核)。 + +### 治理增强(2026-11-01) + +- 新增 git 门禁:`hooks/git/pre-commit`(validate --strict / scan / catalog --check)+ `pre-push`(安装器测试),`scripts/install-git-hooks.sh` 一键安装(Gitea Actions 无 runner,本地兜底)。 +- `install-skills.sh` 支持 `--scope project --project-dir <根>`:装到项目 `.agents/skills`,独立状态文件。 +- 新增 `scripts/scan-installed.sh`:扫描已装但非本仓库管理的第三方技能(当前 33 个,0 高危)。 +- `generate-catalog.py` 增加 `has_evals` / `has_docs` 与 `coverage` 汇总;`validate-skills.py` 增加 `--coverage` 报告与路由表一致性检查。 +- `SCOPE.md` 增加覆盖率路线图(3–4 周补齐 40 个技能的 evals 与文档);`MAINTENANCE.md` 同步。 diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 001952c..032f447 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -7,6 +7,8 @@ 1. 过 `SCOPE.md` 收录门槛(真实失败 + 组合不出来),新技能默认先 `beta`。 2. 跑四道门禁:`validate-skills.py --strict`、`scan-skill.sh`、`generate-catalog.py --check`、`tests/install-skills.test.sh`。 + - 本机已用 `./scripts/install-git-hooks.sh` 装好 pre-commit / pre-push,commit/push 时自动执行;Gitea Actions 暂无 runner,不能依赖 CI。 + - 跳过单次:`SKILL_GATE_SKIP=1 git commit ...`,提交信息里写原因。 3. 技能有增删改 → **同步回改** `docs/skill-routing.md` 与 `catalog.json`。 4. 更新 `plugin.json` 版本号与 `CHANGELOG.md`。 @@ -28,13 +30,15 @@ - 两台机器 `--audit` 漂移必须为 0(beta/deprecated 除外)。 - 审 `catalog.json`:`description` 长度 <80 或 >600 的标黄;含「各种 / 等等 / 相关」这类泛化词的标出。 -- 第三方技能(arkcli 等)有变动时,评估是否影响团队技能。 +- 第三方技能(arkcli 等)有变动时,评估是否影响团队技能;跑一次 `./scripts/scan-installed.sh`。 +- 跑 `python3 scripts/validate-skills.py --coverage`:报告缺 evals / 缺四段式文档的技能,按 `SCOPE.md` 的覆盖率路线图推进。 ## 每季度首月 1 日 10:30 — 治理复核 - 人工过一遍 `docs/skill-routing.md`:删掉不再用的引用、补上新技能。 - 清理 `deprecated`:满 3 个月且无回滚需求 → 删除插件目录。 - 复核分桶与调用模式:还有没有命令型技能占着 `model-invoked`。 +- 复核覆盖率:`--coverage` 的两项缺口是否按路线图收敛。 - 更新本文件与 `CHANGELOG.md`。 ## 责任分工 diff --git a/README.md b/README.md index ad44e7d..2935c34 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,9 @@ A: SSE 模式直连远程服务器,零依赖开箱即用(推荐)。stdio - Claude(兼容):`./install-skills.sh --agent claude` - 看漂移:`./install-skills.sh --audit` - **校验 / 安全 / 清单**:`python3 scripts/validate-skills.py`、`./scripts/scan-skill.sh`、`python3 scripts/generate-catalog.py` +- **本地门禁(Gitea Actions 无 runner,用 git hook 兜底)**:`./scripts/install-git-hooks.sh` 后,每次 commit 自动跑 `validate --strict` + `scan` + `catalog --check`,push 前跑安装器测试。跳过单次:`SKILL_GATE_SKIP=1`。 +- **项目级安装**:`./install-skills.sh --agent codex --scope project --project-dir <项目根>` → 装到 `<项目根>/.agents/skills`。 +- **第三方技能风险扫描**:`./scripts/scan-installed.sh`(扫已装但非本仓库管理的技能)。 - **建技能**:走 `skill-creator` 技能(收录门槛、分桶、调用模式、evals、四段式文档、路由回改),不要手写。 - **路由表**:`docs/skill-routing.md`(什么任务用哪个技能,人读;由原 `ai-proj-helper-entry` 技能降级而来)。 - **维护节奏**:`MAINTENANCE.md`(每次改动 / 每日 / 每周 / 每月 / 每季度各做什么)。 diff --git a/SCOPE.md b/SCOPE.md index 9ff52bb..872c6f8 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -43,3 +43,17 @@ 3. `./scripts/scan-skill.sh` 无高危项。 4. `python3 scripts/generate-catalog.py` 更新 `catalog.json`。 5. 版本号 + CHANGELOG 更新,走 PR。 + +## 覆盖率路线图(evals 与四段式文档) + +目标集合:`promoted` 且 `model-invoked` 的技能(当前 40 个)。用户级命令技能(`user-invoked`)只要求四段式文档,不强制 evals。 + +| 阶段 | 范围 | 验收 | +| --- | --- | --- | +| 第 1 周 | `core/` + `req/` 类(约 15 个) | `--coverage` 里这些类目缺口为 0 | +| 第 2 周 | `dev/` 类(约 20 个) | 同上 | +| 第 3–4 周 | 其余(`integration/`、`biz/` 里仍 model-invoked 的) | 全量缺口为 0 | + +每个技能的最低要求:`evals/evals.json` 3 条(正常 / 边界 / 失败恢复)+ `docs/skills/.md` 四段式(What it does / When to reach for it / Common questions / It's working if)。 + +先用 `python3 scripts/validate-skills.py --coverage` 看当前缺口,再按阶段补。 diff --git a/catalog.json b/catalog.json index 501135d..1547625 100644 --- a/catalog.json +++ b/catalog.json @@ -1,6 +1,95 @@ { "repo": "ai-proj-helper", - "generated_at": "2026-10-31T14:24:05Z", + "coverage": { + "required": 40, + "with_evals": 0, + "with_docs": 0, + "missing_evals": [ + "ai-proj", + "pm-ask", + "pm-risk", + "agent-browser", + "agent-swarm", + "ai-chat", + "db-migration", + "defect-analysis", + "deploy-rollback", + "dev-arch", + "dev-cicd", + "dev-coding", + "dev-commit", + "dev-deploy", + "dev-integration", + "dev-mcp", + "dev-review", + "dev-scaffold", + "dev-test", + "executing-plans", + "finishing-a-development-branch", + "frontend-design", + "karpathy-guidelines", + "pull-request", + "review-checklist", + "slark-cicd", + "slark-dsh-cicd", + "req-audit", + "req-compare", + "req-design", + "req-dev", + "req-lookback", + "req", + "req-prd", + "req-prototype", + "req-research", + "req-retro", + "req-review", + "req-test-gate", + "req-workflow" + ], + "missing_docs": [ + "ai-proj", + "pm-ask", + "pm-risk", + "agent-browser", + "agent-swarm", + "ai-chat", + "db-migration", + "defect-analysis", + "deploy-rollback", + "dev-arch", + "dev-cicd", + "dev-coding", + "dev-commit", + "dev-deploy", + "dev-integration", + "dev-mcp", + "dev-review", + "dev-scaffold", + "dev-test", + "executing-plans", + "finishing-a-development-branch", + "frontend-design", + "karpathy-guidelines", + "pull-request", + "review-checklist", + "slark-cicd", + "slark-dsh-cicd", + "req-audit", + "req-compare", + "req-design", + "req-dev", + "req-lookback", + "req", + "req-prd", + "req-prototype", + "req-research", + "req-retro", + "req-review", + "req-test-gate", + "req-workflow" + ] + }, + "generated_at": "2026-10-31T21:04:04Z", "total": 61, "counts": { "promoted/user-invoked": 18, @@ -19,7 +108,9 @@ "description": "商务合同撰写。支持多种合同类型:软件订阅合同、软件定制开发合同、物流合同、销售服务合同、贸易合同等。当用户提到合同、协议、签约、合作协议相关任务时自动激活。", "description_len": 78, "path": "skills-biz/biz-contract-plugin/skills/SKILL.md", - "digest": "3c17cae1380d82a4" + "digest": "3c17cae1380d82a4", + "has_evals": false, + "has_docs": false }, { "name": "biz-ops", @@ -30,7 +121,9 @@ "description": "商务运营技能。支持商业计划书(BP)撰写和商务合同起草。当用户提到商业计划书、BP、融资计划、商业模式、合同、协议、签约等相关任务时自动激活。", "description_len": 71, "path": "skills-biz/biz-ops-plugin/skills/SKILL.md", - "digest": "aa5433074ba277d6" + "digest": "aa5433074ba277d6", + "has_evals": false, + "has_docs": false }, { "name": "biz-plan", @@ -41,7 +134,9 @@ "description": "商业计划书撰写。支持融资BP、战略规划、商业模式设计等。当用户提到商业计划书、BP、融资计划、商业模式、战略规划相关任务时自动激活。", "description_len": 66, "path": "skills-biz/biz-plan-plugin/skills/SKILL.md", - "digest": "b6f43a914b2f7b45" + "digest": "b6f43a914b2f7b45", + "has_evals": false, + "has_docs": false }, { "name": "finance", @@ -52,7 +147,9 @@ "description": "财务对账技能。支持银行对账、应收对账、应付对账、内部往来对账等。通过自然语言实现账单导入、差异分析、对账报告生成。当用户提到对账、银行流水、应收应付、账单核对、财务核销相关任务时自动激活。", "description_len": 94, "path": "skills-biz/finance-plugin/skills/SKILL.md", - "digest": "0a9209bc4bf4db3a" + "digest": "0a9209bc4bf4db3a", + "has_evals": false, + "has_docs": false }, { "name": "ai-proj-helper-entry", @@ -63,7 +160,9 @@ "description": "ai-proj-helper 技能库路由:告诉你有哪些技能、什么任务用哪个、以及「REQ released + PDV 通过才算交付」的强制口径。人在开始需求/开发/评审/发布任务前主动调用。", "description_len": 96, "path": "skills-core/ai-proj-helper-entry-plugin/skills/SKILL.md", - "digest": "41d39b76d4c71dbf" + "digest": "41d39b76d4c71dbf", + "has_evals": true, + "has_docs": false }, { "name": "ai-proj", @@ -74,7 +173,9 @@ "description": "ai-proj 任务与需求管理。用于创建/查询/更新需求、任务、文档。当用户提到 ai-proj、任务管理、需求管理、REQ-XXX 相关操作时自动激活。", "description_len": 77, "path": "skills-core/ai-proj-plugin/skills/SKILL.md", - "digest": "77ce4d2eb10e1d29" + "digest": "77ce4d2eb10e1d29", + "has_evals": false, + "has_docs": false }, { "name": "pm-ask", @@ -85,7 +186,9 @@ "description": "基于 ai-proj MCP + git log 真实数据的项目问答。禁止编造。当用户说\"/ask\"、\"问一下\"、\"统计一下\"、\"最近多少\"、\"谁做了多少\"、\"本月进度\"等项目相关问题时自动激活。", "description_len": 98, "path": "skills-core/pm-ask-plugin/skills/SKILL.md", - "digest": "e5b69a0b56985472" + "digest": "e5b69a0b56985472", + "has_evals": false, + "has_docs": false }, { "name": "pm-risk", @@ -96,7 +199,9 @@ "description": "三维度项目风险扫描(需求层/代码层/流程层)。当用户说\"/risk\"、\"风险扫描\"、\"有什么风险\"、\"哪些需求停滞了\"、\"分支健康\"时自动激活。", "description_len": 72, "path": "skills-core/pm-risk-plugin/skills/SKILL.md", - "digest": "928cfec76018329f" + "digest": "928cfec76018329f", + "has_evals": false, + "has_docs": false }, { "name": "publish", @@ -107,7 +212,9 @@ "description": "发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。", "description_len": 48, "path": "skills-core/publish-plugin/skills/SKILL.md", - "digest": "48bfbb4149baddcc" + "digest": "48bfbb4149baddcc", + "has_evals": false, + "has_docs": false }, { "name": "skill-creator", @@ -118,7 +225,9 @@ "description": "团队技能的标准流程:收录门槛、分桶生命周期、调用模式、SKILL.md 规范、evals 全量、四段式文档、路由回改。当要新建技能、大改现有技能、或评审一个技能是否合格时使用。", "description_len": 88, "path": "skills-core/skill-creator-plugin/skills/SKILL.md", - "digest": "18f18c43c3fa56a6" + "digest": "18f18c43c3fa56a6", + "has_evals": true, + "has_docs": false }, { "name": "agent-browser", @@ -129,7 +238,9 @@ "description": "浏览器自动化技能。用于网页交互、E2E冒烟测试、需求验收验证、前端开发验证、截图对比。基于 Vercel agent-browser CLI。", "description_len": 71, "path": "skills-dev/agent-browser-plugin/skills/SKILL.md", - "digest": "f382bffe3d1c84b2" + "digest": "f382bffe3d1c84b2", + "has_evals": false, + "has_docs": false }, { "name": "agent-swarm", @@ -140,7 +251,9 @@ "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": "4164f82025a421bb" + "digest": "4164f82025a421bb", + "has_evals": false, + "has_docs": false }, { "name": "ai-chat", @@ -151,7 +264,9 @@ "description": "AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。", "description_len": 78, "path": "skills-dev/ai-chat-plugin/skills/SKILL.md", - "digest": "81193de50b43d95c" + "digest": "81193de50b43d95c", + "has_evals": false, + "has_docs": false }, { "name": "ai-proj-cicd-release", @@ -162,7 +277,9 @@ "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": "49ef1b6865c2f1b3" + "digest": "49ef1b6865c2f1b3", + "has_evals": false, + "has_docs": false }, { "name": "ai-proj-macos-release", @@ -173,7 +290,9 @@ "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": "6f2496b941706137" + "digest": "6f2496b941706137", + "has_evals": false, + "has_docs": false }, { "name": "db-migration", @@ -184,7 +303,9 @@ "description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时由 req-design 推荐激活。", "description_len": 77, "path": "skills-dev/db-migration-plugin/skills/SKILL.md", - "digest": "f8d6ebbddbbf7a71" + "digest": "f8d6ebbddbbf7a71", + "has_evals": false, + "has_docs": false }, { "name": "defect-analysis", @@ -195,7 +316,9 @@ "description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。", "description_len": 68, "path": "skills-dev/defect-analysis-plugin/skills/SKILL.md", - "digest": "23dfafda92d0c622" + "digest": "23dfafda92d0c622", + "has_evals": false, + "has_docs": false }, { "name": "deploy-rollback", @@ -206,7 +329,9 @@ "description": "回滚方案插件。部署后发现问题时的回滚策略和执行步骤。挂载在 deploy 阶段,部署出问题时激活。", "description_len": 49, "path": "skills-dev/deploy-rollback-plugin/skills/SKILL.md", - "digest": "75ebf66a3f74195a" + "digest": "75ebf66a3f74195a", + "has_evals": false, + "has_docs": false }, { "name": "dev-android", @@ -217,7 +342,9 @@ "description": "Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。当涉及 Android 开发任务时按需加载。", "description_len": 72, "path": "skills-dev/dev-android-plugin/skills/SKILL.md", - "digest": "fb058d1059b56cdd" + "digest": "fb058d1059b56cdd", + "has_evals": false, + "has_docs": false }, { "name": "dev-arch", @@ -228,7 +355,9 @@ "description": "软件架构设计技能。用于系统设计、技术选型、架构评审、设计文档编写。当用户提到架构设计、系统设计、技术方案、API 设计相关任务时自动激活。", "description_len": 69, "path": "skills-dev/dev-arch-plugin/skills/SKILL.md", - "digest": "c9a419c83a307a11" + "digest": "c9a419c83a307a11", + "has_evals": false, + "has_docs": false }, { "name": "dev-cicd", @@ -239,7 +368,9 @@ "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" + "digest": "a763f0f140516411", + "has_evals": false, + "has_docs": false }, { "name": "dev-coding", @@ -250,7 +381,9 @@ "description": "软件编码开发技能。用于代码编写、功能实现、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。核心支持 Go 后端 + Vue/React 前端开发。", "description_len": 81, "path": "skills-dev/dev-coding-plugin/skills/SKILL.md", - "digest": "cc43720aa12bb8f6" + "digest": "cc43720aa12bb8f6", + "has_evals": false, + "has_docs": false }, { "name": "dev-commit", @@ -261,7 +394,9 @@ "description": "智能 git commit — 分支保护 + 自动建功能分支 + Conventional Commits 生成。当用户说\"提交代码\"、\"commit\"、\"/commit\"、\"保存修改\"时自动激活。", "description_len": 99, "path": "skills-dev/dev-commit-plugin/skills/SKILL.md", - "digest": "1560658c4a30df45" + "digest": "1560658c4a30df45", + "has_evals": false, + "has_docs": false }, { "name": "dev-deploy", @@ -272,7 +407,9 @@ "description": "应用部署技能。支持 iOS TestFlight、Docker 容器等多平台部署。当用户提到部署、发布、TestFlight、上架、build、archive 相关任务时自动激活。", "description_len": 90, "path": "skills-dev/dev-deploy-plugin/skills/SKILL.md", - "digest": "fd15a9e9135bcc49" + "digest": "fd15a9e9135bcc49", + "has_evals": false, + "has_docs": false }, { "name": "dev-integration", @@ -283,7 +420,9 @@ "description": "前后端联调技能。API 契约验证、接口对接、联调报告生成。对应 req 流程 integration 阶段。纯后端需求自动跳过。", "description_len": 64, "path": "skills-dev/dev-integration-plugin/skills/SKILL.md", - "digest": "eff6be8eb57b7fef" + "digest": "eff6be8eb57b7fef", + "has_evals": false, + "has_docs": false }, { "name": "dev-ios", @@ -294,7 +433,9 @@ "description": "iOS 开发插件。Swift/SwiftUI + MVVM 架构,TestFlight 部署。当涉及 iOS 开发任务时按需加载。", "description_len": 65, "path": "skills-dev/dev-ios-plugin/skills/SKILL.md", - "digest": "44499e31f1abd5e2" + "digest": "44499e31f1abd5e2", + "has_evals": false, + "has_docs": false }, { "name": "dev-mcp", @@ -305,7 +446,9 @@ "description": "MCP Bridge 开发插件。TypeScript MCP 服务开发,Token 管理,HTTP 客户端模式。当涉及 mcp-task-bridge 开发时按需加载。", "description_len": 84, "path": "skills-dev/dev-mcp-plugin/skills/SKILL.md", - "digest": "83d5912212fcfa4a" + "digest": "83d5912212fcfa4a", + "has_evals": false, + "has_docs": false }, { "name": "dev-pda", @@ -316,7 +459,9 @@ "description": "PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先。当涉及 PDA/手持终端开发时按需加载。", "description_len": 57, "path": "skills-dev/dev-pda-plugin/skills/SKILL.md", - "digest": "2524f2ecd4f2a834" + "digest": "2524f2ecd4f2a834", + "has_evals": false, + "has_docs": false }, { "name": "dev-review", @@ -327,7 +472,9 @@ "description": "代码评审技能。六视角对抗性扫描法(含 Karpathy Scope 审计),用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。", "description_len": 91, "path": "skills-dev/dev-review-plugin/skills/SKILL.md", - "digest": "a8a1ec79b85e3227" + "digest": "a8a1ec79b85e3227", + "has_evals": false, + "has_docs": false }, { "name": "dev-scaffold", @@ -338,7 +485,9 @@ "description": "模块脚手架插件。新建模块时自动生成分层代码骨架。挂载在 dev 阶段,新建模块时激活。", "description_len": 43, "path": "skills-dev/dev-scaffold-plugin/skills/SKILL.md", - "digest": "4044787b1e468302" + "digest": "4044787b1e468302", + "has_evals": false, + "has_docs": false }, { "name": "dev-test", @@ -349,7 +498,9 @@ "description": "软件测试技能。用于单元测试、集成测试、E2E测试、测试用例设计。支持 Go、Vue、React、iOS、Android 等多平台测试。", "description_len": 67, "path": "skills-dev/dev-test-plugin/skills/dev-test/SKILL.md", - "digest": "a03536a478eabe6c" + "digest": "a03536a478eabe6c", + "has_evals": false, + "has_docs": false }, { "name": "executing-plans", @@ -360,7 +511,9 @@ "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" + "digest": "8991a50091af83a4", + "has_evals": false, + "has_docs": false }, { "name": "finishing-a-development-branch", @@ -371,7 +524,9 @@ "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" + "digest": "1102047ccc060e60", + "has_evals": false, + "has_docs": false }, { "name": "frontend-design", @@ -382,7 +537,9 @@ "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": "84e9c104be7967cc" + "digest": "84e9c104be7967cc", + "has_evals": false, + "has_docs": false }, { "name": "karpathy-guidelines", @@ -393,7 +550,9 @@ "description": "Karpathy 四原则编码行为守则。减少 LLM 常见编码错误:过度实现、静默假设、顺手重构、无验证标准。在任意编码场景激活。", "description_len": 64, "path": "skills-dev/karpathy-guidelines-plugin/skills/SKILL.md", - "digest": "a68f347031110d6a" + "digest": "a68f347031110d6a", + "has_evals": false, + "has_docs": false }, { "name": "pull-request", @@ -404,7 +563,9 @@ "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" + "digest": "40dac0d290782bb5", + "has_evals": false, + "has_docs": false }, { "name": "review-checklist", @@ -415,7 +576,9 @@ "description": "项目级代码评审检查清单。按项目积累特定检查项,挂载在 dev-review 下自动加载。每次 CR 时触发。", "description_len": 54, "path": "skills-dev/review-checklist-plugin/skills/SKILL.md", - "digest": "5bae13b6a8d92650" + "digest": "5bae13b6a8d92650", + "has_evals": false, + "has_docs": false }, { "name": "slark-cicd", @@ -426,7 +589,9 @@ "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": "1ff9b89a5fbc6e2d" + "digest": "1ff9b89a5fbc6e2d", + "has_evals": false, + "has_docs": false }, { "name": "slark-dsh-cicd", @@ -437,7 +602,9 @@ "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": "9819e2d515ab44e0" + "digest": "9819e2d515ab44e0", + "has_evals": false, + "has_docs": false }, { "name": "data-excel", @@ -448,7 +615,9 @@ "description": "Excel 数据处理与 BI 集成。通过自然语言操作 Excel 文件的读取、编辑、转换,并支持导入到 BI 系统(Metabase)进行可视化分析。当用户提到 Excel、表格处理、数据导入、BI 分析相关任务时自动激活。", "description_len": 112, "path": "skills-integration/data-excel-plugin/skills/SKILL.md", - "digest": "8dc4be8f88cfd866" + "digest": "8dc4be8f88cfd866", + "has_evals": false, + "has_docs": false }, { "name": "doubao-voice", @@ -459,7 +628,9 @@ "description": "豆包语音API调用。支持语音合成(TTS)和唱歌。当用户提到语音合成、文字转语音、唱歌、豆包语音相关任务时自动激活。", "description_len": 58, "path": "skills-integration/doubao-voice-plugin/skills/SKILL.md", - "digest": "7dc73d3b97e61fd2" + "digest": "7dc73d3b97e61fd2", + "has_evals": false, + "has_docs": false }, { "name": "feishu-bitable", @@ -470,7 +641,9 @@ "description": "飞书多维表格操作。用于记录增删改查、批量操作、筛选排序、数据同步。当需要操作飞书多维表格时使用。", "description_len": 48, "path": "skills-integration/feishu-bitable-plugin/skills/SKILL.md", - "digest": "3bf37533007365a3" + "digest": "3bf37533007365a3", + "has_evals": false, + "has_docs": false }, { "name": "feishu-docx", @@ -481,7 +654,9 @@ "description": "飞书云文档操作。用于创建、编辑云文档,插入内容块,会议纪要生成。当需要操作飞书云文档时使用。", "description_len": 46, "path": "skills-integration/feishu-docx-plugin/skills/SKILL.md", - "digest": "49d097bfa2c283ab" + "digest": "49d097bfa2c283ab", + "has_evals": false, + "has_docs": false }, { "name": "feishu", @@ -492,7 +667,9 @@ "description": "飞书文档与多维表格操作入口。当用户提到飞书、云文档、多维表格、Bitable 相关任务时自动激活。", "description_len": 49, "path": "skills-integration/feishu-plugin/skills/SKILL.md", - "digest": "973c6ac22104ee38" + "digest": "973c6ac22104ee38", + "has_evals": false, + "has_docs": false }, { "name": "siyuan", @@ -503,7 +680,9 @@ "description": "思源笔记 API 集成。通过自然语言创建、编辑、搜索笔记,管理笔记本和文档树。当用户提到思源笔记、SiYuan、笔记管理、知识库相关任务时自动激活。", "description_len": 74, "path": "skills-integration/siyuan-plugin/skills/SKILL.md", - "digest": "2736c2b708791763" + "digest": "2736c2b708791763", + "has_evals": false, + "has_docs": false }, { "name": "siyuan-to-feishu", @@ -514,7 +693,9 @@ "description": "将思源笔记导出为 PDF 并发送到飞书群。当用户提到\"发送笔记\"、\"导出PDF发飞书\"、\"/siyuan send\"、\"分享到飞书\"相关任务时自动激活。", "description_len": 76, "path": "skills-integration/siyuan-to-feishu-plugin/skills/SKILL.md", - "digest": "998dace910c1eb7a" + "digest": "998dace910c1eb7a", + "has_evals": false, + "has_docs": false }, { "name": "wecom", @@ -525,7 +706,9 @@ "description": "企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。", "description_len": 77, "path": "skills-integration/wecom-plugin/skills/SKILL.md", - "digest": "7084d88ccb87ba9b" + "digest": "7084d88ccb87ba9b", + "has_evals": false, + "has_docs": false }, { "name": "req-audit", @@ -536,7 +719,9 @@ "description": "部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。", "description_len": 55, "path": "skills-req/req-audit-plugin/skills/SKILL.md", - "digest": "ff2e6197bbb059c6" + "digest": "ff2e6197bbb059c6", + "has_evals": false, + "has_docs": false }, { "name": "req-compare", @@ -547,7 +732,9 @@ "description": "对比式需求分析插件。系统平移、竞品借鉴、版本升级时使用参考对象对比法编写 PRD。挂载在 analysis 阶段,需要对比分析时由 req-prd 推荐激活。", "description_len": 79, "path": "skills-req/req-compare-plugin/skills/SKILL.md", - "digest": "3428e3f37ef9e9e8" + "digest": "3428e3f37ef9e9e8", + "has_evals": false, + "has_docs": false }, { "name": "req-design", @@ -558,7 +745,9 @@ "description": "需求开发设计技能。用于 PRD 到开发设计的转换:API 契约定义、数据模型变更方案、变更文件清单、开发任务拆分、技术风险评估。当用户执行 /req doc 或需要编写开发设计文档时自动激活。", "description_len": 96, "path": "skills-req/req-design-plugin/skills/SKILL.md", - "digest": "74848800cab6e269" + "digest": "74848800cab6e269", + "has_evals": false, + "has_docs": false }, { "name": "req-dev", @@ -569,7 +758,9 @@ "description": "需求开发计划编写技能。用于 PRD 到代码转换、代码库分析、开发任务拆分、技术方案设计。当用户执行 /req doc 或需要编写开发计划时自动激活。", "description_len": 74, "path": "skills-req/req-dev-plugin/skills/SKILL.md", - "digest": "494a5be5e7a11c0b" + "digest": "494a5be5e7a11c0b", + "has_evals": false, + "has_docs": false }, { "name": "req-lookback", @@ -580,7 +771,9 @@ "description": "回归测试。部署后自动验证变更涉及的功能是否正常。可独立调用或由 /req done 自动触发。", "description_len": 47, "path": "skills-req/req-lookback-plugin/skills/SKILL.md", - "digest": "cc6bff614a8f7bf4" + "digest": "cc6bff614a8f7bf4", + "has_evals": false, + "has_docs": false }, { "name": "req", @@ -591,7 +784,9 @@ "description": "需求工作流管理。用于 /req 命令使用、需求全生命周期管理(创建→PRD→评审→开发→测试→部署→归档)。当用户提到需求管理、/req 命令、REQ-XXX 相关任务时自动激活。", "description_len": 90, "path": "skills-req/req-plugin/skills/SKILL.md", - "digest": "193cf871b73faff1" + "digest": "193cf871b73faff1", + "has_evals": false, + "has_docs": false }, { "name": "req-prd", @@ -602,7 +797,9 @@ "description": "产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。", "description_len": 76, "path": "skills-req/req-prd-plugin/skills/SKILL.md", - "digest": "7c4ad2baab6b2118" + "digest": "7c4ad2baab6b2118", + "has_evals": false, + "has_docs": false }, { "name": "req-prototype", @@ -613,7 +810,9 @@ "description": "原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。", "description_len": 81, "path": "skills-req/req-prototype-plugin/skills/SKILL.md", - "digest": "7e362f4f895fb50a" + "digest": "7e362f4f895fb50a", + "has_evals": false, + "has_docs": false }, { "name": "req-research", @@ -624,7 +823,9 @@ "description": "需求调研插件。代码审计、数据库分析、现有功能调研、技术可行性评估。挂载在 analysis 阶段,需要深度调研时由 req-prd 推荐激活。", "description_len": 71, "path": "skills-req/req-research-plugin/skills/SKILL.md", - "digest": "a94924f53bd4c80e" + "digest": "a94924f53bd4c80e", + "has_evals": false, + "has_docs": false }, { "name": "req-retro", @@ -635,7 +836,9 @@ "description": "复盘总结。自动采集数据、计算质量评分、跨需求模式识别、技能自动进化。可独立调用或由 /req done 自动触发。", "description_len": 57, "path": "skills-req/req-retro-plugin/skills/SKILL.md", - "digest": "636b7099d85e9549" + "digest": "636b7099d85e9549", + "has_evals": false, + "has_docs": false }, { "name": "req-review", @@ -646,7 +849,9 @@ "description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。", "description_len": 65, "path": "skills-req/req-review-plugin/skills/SKILL.md", - "digest": "cd1a5181d72f35f4" + "digest": "cd1a5181d72f35f4", + "has_evals": false, + "has_docs": false }, { "name": "req-test-gate", @@ -657,7 +862,9 @@ "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": "ceebcc2516ad40d3" + "digest": "ceebcc2516ad40d3", + "has_evals": false, + "has_docs": false }, { "name": "req-workflow", @@ -668,7 +875,9 @@ "description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。", "description_len": 61, "path": "skills-req/req-workflow-plugin/skills/SKILL.md", - "digest": "87499da3817d162d" + "digest": "87499da3817d162d", + "has_evals": false, + "has_docs": false }, { "name": "verification-before-completion", @@ -679,7 +888,9 @@ "description": "汇报「完成/修好/通过」或关闭任务、提交 PR、宣布 REQ 完成之前,必须先运行验证命令并附证据;没有证据不得声称完成。当准备说完成、关闭任务、或汇报交付前使用。", "description_len": 82, "path": "skills-req/verification-before-completion-plugin/skills/SKILL.md", - "digest": "7c23649f4a0a8798" + "digest": "7c23649f4a0a8798", + "has_evals": true, + "has_docs": false } ] } diff --git a/hooks/git/pre-commit b/hooks/git/pre-commit new file mode 100755 index 0000000..1b7a803 --- /dev/null +++ b/hooks/git/pre-commit @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# skill-gate 本地门禁:Gitea Actions 没有 runner,靠这个兜底。 +# 跳过:SKILL_GATE_SKIP=1 git commit ...(需在提交信息里说明原因) +set -uo pipefail +[ "${SKILL_GATE_SKIP:-0}" = "1" ] && { echo "[skill-gate] skipped by SKILL_GATE_SKIP=1"; exit 0; } +cd "$(git rev-parse --show-toplevel)" || exit 1 +fail=0 +echo "[skill-gate] validate --strict" +python3 scripts/validate-skills.py --strict || fail=1 +echo "[skill-gate] scan" +./scripts/scan-skill.sh >/tmp/skill-gate-scan.log 2>&1 || { fail=1; tail -5 /tmp/skill-gate-scan.log; } +echo "[skill-gate] catalog --check" +python3 scripts/generate-catalog.py --check || fail=1 +if [ "$fail" -ne 0 ]; then + echo "[skill-gate] 未通过:先修复,或用 SKILL_GATE_SKIP=1 并在提交信息里说明原因" + exit 1 +fi +echo "[skill-gate] OK" diff --git a/hooks/git/pre-push b/hooks/git/pre-push new file mode 100755 index 0000000..240d626 --- /dev/null +++ b/hooks/git/pre-push @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# skill-gate 推送前门禁:安装器测试 + 覆盖率提示 +set -uo pipefail +[ "${SKILL_GATE_SKIP:-0}" = "1" ] && exit 0 +cd "$(git rev-parse --show-toplevel)" || exit 1 +echo "[skill-gate] install-skills 测试" +bash tests/install-skills.test.sh || { echo "[skill-gate] 测试失败"; exit 1; } diff --git a/install-skills.sh b/install-skills.sh index f4f516c..0e60a08 100755 --- a/install-skills.sh +++ b/install-skills.sh @@ -10,6 +10,8 @@ # --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 +# --scope user (default) or project (installs into /.agents/skills) +# --project-dir Project root, required when --scope project # --dry-run Preview changes without writing anything # --category Only install plugins in dir_category= # Valid values: biz, core, dev, integration, personal, req @@ -38,6 +40,8 @@ LINK_MODE=false AUDIT_ONLY=false INCLUDE_BETA=false NO_VALIDATE=false +SCOPE="user" +PROJECT_DIR="" # ── Colour helpers ───────────────────────────────────────────────────────────── GREEN='\033[0;32m' @@ -63,6 +67,12 @@ while [[ $# -gt 0 ]]; do --audit) AUDIT_ONLY=true ;; --include-beta) INCLUDE_BETA=true ;; --no-validate) NO_VALIDATE=true ;; + --scope) + [[ $# -ge 2 ]] || { error "--scope requires user or project"; exit 1; } + SCOPE="$2"; shift ;; + --project-dir) + [[ $# -ge 2 ]] || { error "--project-dir requires a path"; exit 1; } + PROJECT_DIR="$2"; shift ;; --force) FORCE=true ;; --cleanup) CLEANUP=true ;; --list) LIST_ONLY=true ;; @@ -90,7 +100,7 @@ case "$AGENT_TARGET" in STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.agents/.ai-proj-helper-installed-skills.json}" ;; dsh) - if [[ -z "${DSH_HOME:-}" ]]; then + if [[ "$SCOPE" != "project" && -z "${DSH_HOME:-}" ]]; then error "--agent dsh requires DSH_HOME (or set AI_PROJ_HELPER_SKILLS_DIR explicitly)" exit 1 fi @@ -108,6 +118,20 @@ case "$AGENT_TARGET" in ;; esac +# ── Project scope override ───────────────────────────────────────────────────── +if [[ "$SCOPE" == "project" ]]; then + if [[ -z "$PROJECT_DIR" ]]; then + error "--scope project requires --project-dir " + exit 1 + fi + [[ -d "$PROJECT_DIR" ]] || { error "project dir 不存在: $PROJECT_DIR"; exit 1; } + PROJECT_DIR="$(cd "$PROJECT_DIR" && pwd)" + SKILLS_DIR="$PROJECT_DIR/.agents/skills" + COMMANDS_DIR="" + STATE_FILE="$PROJECT_DIR/.agents/.ai-proj-helper-installed-skills.json" + info "Project scope: $PROJECT_DIR" +fi + # ── State helpers (plain JSON via python3) ───────────────────────────────────── state_get() { # state_get -> prints version or empty string diff --git a/scripts/generate-catalog.py b/scripts/generate-catalog.py index ea8474a..38d664d 100755 --- a/scripts/generate-catalog.py +++ b/scripts/generate-catalog.py @@ -55,9 +55,12 @@ def build() -> dict: 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") + install_name = meta.get("install_name") or fm.get("name") + has_evals = any((plugin_dir / "skills").rglob("evals/evals.json")) + has_docs = (ROOT / "docs" / "skills" / f"{install_name}.md").is_file() skills.append( { - "name": meta.get("install_name") or fm.get("name"), + "name": install_name, "category": meta.get("dir_category"), "version": meta.get("version"), "status": meta.get("status", "promoted"), @@ -66,14 +69,28 @@ def build() -> dict: "description_len": len(desc), "path": str(skill_md.relative_to(ROOT)), "digest": hashlib.sha256(body.encode("utf-8")).hexdigest()[:16], + "has_evals": has_evals, + "has_docs": has_docs, } ) counts: dict = {} for skill in skills: key = f"{skill['status']}/{skill['invocation']}" counts[key] = counts.get(key, 0) + 1 + required = [ + x for x in skills + if x["status"] == "promoted" and x["invocation"] == "model-invoked" + ] + coverage = { + "required": len(required), + "with_evals": sum(1 for x in required if x["has_evals"]), + "with_docs": sum(1 for x in required if x["has_docs"]), + "missing_evals": [x["name"] for x in required if not x["has_evals"]], + "missing_docs": [x["name"] for x in required if not x["has_docs"]], + } return { "repo": "ai-proj-helper", + "coverage": coverage, "generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), "total": len(skills), "counts": counts, diff --git a/scripts/install-git-hooks.sh b/scripts/install-git-hooks.sh new file mode 100755 index 0000000..ca0f6ff --- /dev/null +++ b/scripts/install-git-hooks.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# 安装本仓库的 git 门禁钩子(pre-commit / pre-push)。 +set -euo pipefail +root="$(git rev-parse --show-toplevel)" +[ -d "$root/hooks/git" ] || { echo "找不到 hooks/git"; exit 1; } +mkdir -p "$root/.git/hooks" +for h in pre-commit pre-push; do + cp "$root/hooks/git/$h" "$root/.git/hooks/$h" + chmod +x "$root/.git/hooks/$h" + echo "已安装 .git/hooks/$h" +done +echo "跳过单次检查:SKILL_GATE_SKIP=1 git commit ..." diff --git a/scripts/scan-installed.sh b/scripts/scan-installed.sh new file mode 100755 index 0000000..c66dfec --- /dev/null +++ b/scripts/scan-installed.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# scan-installed.sh — 扫描「已安装但不是本仓库管理」的第三方技能,找出高风险内容。 +# 用法: ./scripts/scan-installed.sh [--strict] [dir ...] +# 默认扫描 ~/.agents/skills 与 $DSH_HOME/skills +# --strict: 有高危项则退出码 1 +set -uo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +STRICT=0 +dirs=() +for a in "$@"; do + case "$a" in + --strict) STRICT=1 ;; + *) dirs+=("$a") ;; + esac +done +if [[ ${#dirs[@]} -eq 0 ]]; then + dirs+=("${HOME}/.agents/skills") + [[ -n "${DSH_HOME:-}" ]] && dirs+=("${DSH_HOME}/skills") +fi + +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,}' +) + +managed="" +for st in "${HOME}/.agents/.ai-proj-helper-installed-skills.json" \ + "${DSH_HOME:-/nonexistent}/.ai-proj-helper-installed-skills.json"; do + [[ -f "$st" ]] && managed="$managed $(python3 -c "import json;print(' '.join(json.load(open('$st')).keys()))" 2>/dev/null)" +done + +total=0 high=0 third=0 +for dir in "${dirs[@]}"; do + [[ -d "$dir" ]] || continue + for entry in "$dir"/*; do + [[ -e "$entry" || -L "$entry" ]] || continue + name="$(basename "$entry")" + [[ " $managed " == *" $name "* ]] && continue + third=$((third + 1)) + for pattern in "${HIGH_PATTERNS[@]}"; do + while IFS= read -r hit; do + echo "[HIGH] $name: ${hit#*:}" + high=$((high + 1)); total=$((total + 1)) + done < <(grep -rnE --include='*.md' --include='*.sh' --include='*.py' --include='*.js' --include='*.ts' --include='*.json' -- "$pattern" "$entry" 2>/dev/null | cut -c1-180) + done + done +done + +echo "" +echo "扫描完成:第三方技能 $third 个,高危 $high 处" +[[ "$STRICT" == 1 && "$high" -gt 0 ]] && { echo "存在高危第三方技能,需人工确认来源。"; exit 1; } +exit 0 diff --git a/scripts/validate-skills.py b/scripts/validate-skills.py index 9133712..e9c2d6d 100755 --- a/scripts/validate-skills.py +++ b/scripts/validate-skills.py @@ -136,8 +136,58 @@ def check_skill(rel: Path, skill_md: Path, meta: dict): warnings.append(f"{where}: 引用的相对路径不存在: {target}") +IGNORED_ROUTING_TOKENS = { + "completed", "released", "delivery_stage", "status", "true", "false", "user-invoked", + "model-invoked", "promoted", "beta", "deprecated", "scoop", "scoop.md", +} +EXTERNAL_SKILLS = { + # 本仓库之外、由 DSH 用户目录提供的技能(docs/skill-routing.md 允许引用) + "project-management", "topic-distill", "diary", "dsh-worktable-page", + "code-review", "release-notes", "disk-cleanup", "workflow-one", +} + + +def check_routing(catalog_names: set[str]): + routing = ROOT / "docs" / "skill-routing.md" + if not routing.is_file(): + return + text = routing.read_text(encoding="utf-8") + for token in sorted(set(re.findall(r"`([a-z][a-z0-9-]{2,40})`", text))): + if token in IGNORED_ROUTING_TOKENS or token in EXTERNAL_SKILLS: + continue + if token not in catalog_names: + warnings.append(f"docs/skill-routing.md: 路由到不存在的技能 {token!r}") + + +def coverage_report() -> int: + missing_evals, missing_docs = [], [] + for plugin_json in sorted(ROOT.glob("skills-*/*-plugin/.claude-plugin/plugin.json")): + meta = json.loads(plugin_json.read_text()) + if meta.get("status", "promoted") != "promoted": + continue + skill_md = next((plugin_json.parent.parent / "skills").rglob("SKILL.md"), None) + if skill_md is None: + continue + fm, _ = parse_frontmatter(skill_md.read_text(encoding="utf-8", errors="replace")) + if (fm.get("metadata") or {}).get("invocation", "model-invoked") != "model-invoked": + continue + name = meta.get("install_name") or fm.get("name") + if not any((plugin_json.parent.parent / "skills").rglob("evals/evals.json")): + missing_evals.append(name) + if not (ROOT / "docs" / "skills" / f"{name}.md").is_file(): + missing_docs.append(name) + print(f"覆盖率(promoted + model-invoked):缺 evals {len(missing_evals)} 个,缺四段式文档 {len(missing_docs)} 个") + if missing_evals: + print("缺 evals:", ", ".join(missing_evals[:20]) + ("..." if len(missing_evals) > 20 else "")) + if missing_docs: + print("缺文档:", ", ".join(missing_docs[:20]) + ("..." if len(missing_docs) > 20 else "")) + return 0 + + def main() -> int: strict = "--strict" in sys.argv + if "--coverage" in sys.argv: + return coverage_report() plugins = sorted(ROOT.glob("skills-*/*-plugin/.claude-plugin/plugin.json")) if not plugins: print("未找到任何 plugin.json", file=sys.stderr) @@ -145,6 +195,11 @@ def main() -> int: for plugin_json in plugins: check_plugin(plugin_json) + catalog = ROOT / "catalog.json" + if catalog.is_file(): + names = {x["name"] for x in json.loads(catalog.read_text()).get("skills", [])} + check_routing(names) + for warning in warnings: print(f"[warn] {warning}") for error in errors: