Compare commits

...
Author SHA1 Message Date
johnQ aecd2ce521 docs: README 加技能路由表入口,CHANGELOG 记录降级与分类调整 2026-10-31 22:18:10 +08:00
johnQ 41a1032ccf chore(skill): 按 SCOPE 降级两个无增量技能
- verification-before-completion / ai-proj-helper-entry 标记 deprecated
  (3 组难用例均无增量:核心规则已在用户级 AGENTS.md)
- 入口路由内容转成 docs/skill-routing.md(索引不算规则,不占技能目录)
- catalog: promoted 58(40 model-invoked + 18 user-invoked)、beta 1、deprecated 2
2026-10-31 22:17:06 +08:00
johnQ d5bdfcfb7c refactor(skill): 18 个命令型技能转 user-invoked,压目录预算
- biz-* 4 个、integration-* 8 个、dev-android/ios/pda、publish、ai-proj-cicd-release、ai-proj-macos-release
- 均加 metadata.invocation: user-invoked + disable-model-invocation: true(DSH 实测生效)
- catalog: promoted/model-invoked 40、promoted/user-invoked 18、beta 3
2026-10-31 22:16:39 +08:00
johnQ d43b414fc9 feat(skill): 技能治理 v0.2 —— 分桶/调用模式/校验/安全/清单/安装矩阵
- 新增 SCOPE.md 收录门槛 + .out-of-scope/ 拒绝档案
- 生命周期分桶 promoted/beta/deprecated,marketplace 只发布 promoted
- 调用模式 model-invoked/user-invoked(user-invoked 不占模型目录)
- 新增脚本 validate-skills.py / generate-catalog.py / scan-skill.sh(+allowlist)
- 新增 beta 技能 skill-creator、ai-proj-helper-entry、verification-before-completion(各带 evals)
- install-skills.sh: --agent dsh / --link / --audit / --include-beta / --no-validate
- 融合:dev-review 接收评审意见、req-design 依赖边、agent-swarm 并行编排、dev-test TDD
- catalog.json 61 个技能(58 promoted / 3 beta);validate 0 错误;scan 0 高危;现有测试通过
2026-10-31 22:03:13 +08:00
johnQ dde146995e feat(req): 新增「复用盘点」门禁(Gate 5 + PRD §1.5)
- req 技能:4 道门禁 → 5 道,新增 Gate 5「复用盘点先于估工」;无 file:line 证据或标「未排查」禁止提审、禁止按全新增估工
- req-prd 模板:新增 §1.5「现有实现与复用盘点」强制章节(能力点 / file:line / 复用|改造|新增 / 理由)
- 触发:DS Bot 已有头像上传却被当新增估工的事故复盘
- 版本:req-plugin 2.0.0 → 2.1.0,req-prd-plugin 2.2.0 → 2.3.0;marketplace.json 同步再生成
2026-10-27 11:03:47 +08:00
johnQ d5550d62c5 docs(slark-dsh-cicd): 修正参考文件错别字(REQ-20261007-0003) 2026-10-07 17:07:15 +08:00
johnQ c74fe71f0a feat(slark-dsh-cicd): 新增 DSH/Slark 发布实战技能(REQ-20261007-0003)
- 新建 skills-dev/slark-dsh-cicd-plugin:plugin.json + skills/SKILL.md +
  skills/references/fork-release-and-post-checks.md
- 覆盖两条发布线(DSH 插件 pack 双资产 / Slark 宿主重打包+签名)、权限与身份三连
  (push:true 才可写,ls-remote 通 ≠ 能 push)、无上游写权限的 fork 发布且原仓库零改动、
  干净单提交 + git diff --stat <OURS> 树一致性 gate、改指向后必须重新 pack、
  draft→publish 与「更新检查看不到新版」的因果、GitHub HTTPS/fetch 卡死/无 macOS timeout
  的判死处置、发布后 SHA 逐项核对(verify-remote 仅 Windows)、app.asar 完整性约束、
  ai-proj staging→released 与 /req done 证据要求及文档接口故障绕过
- 与 slark-cicd 明确分工并交叉引用,不重复 staging/生产/Desktop 细节
- update-plugin-meta.py PLUGIN_MAP 增加 slark-dsh-cicd-plugin (skill/dev)
- generate-marketplace.py devops 分类补充 slark-dsh-cicd;marketplace.json 仅新增该条目
- 校验:claude plugin validate . 通过(警告为该仓库既有 install_name 字段提示)、git diff --check 干净
2026-10-07 17:06:36 +08:00
johnQ 2e0f7fe68c feat(dev-coding): 新增「Step 0.5 Shell 环境自检」— node/npm 缺 PATH + HOME 未设置
在 macOS + Slark/DSH 实测定位到:bash 工具以 bash -c(非登录非交互)执行,
子进程环境等于宿主进程环境(PATH 不被清洗,HOME/USER/TMPDIR/LANG 未设置),
宿主由 GUI 应用拉起继承最小 PATH → node/npm/git 直接不可用。

沉淀内容:
- 5 条根因(不读 rc / PATH 不被清洗 / GUI 宿主 / HOME 未设置 / shell-env 只认 DSH_*)
- 两行 export 模板:HOME + node v22.22.3 PATH(勿混用 homebrew 的 v26)
- HOME 必须补的理由:~ 靠 passwd 展开易误判,git 报 fatal: $HOME not set,
  set -u 脚本报 unbound variable;「node 能跑」≠ 环境完整
- 交付纪律:禁止把「没有 shell / 不能构建」写成交付结论,未跑构建就如实标注
2026-10-07 07:42:00 +08:00
qiudl 3ffee89840 Merge pull request '[REQ-20260825-0006] Harden Slark handoff recovery guidance' (#10) 2026-08-25 21:15:44 +00:00
qiudl 998b22e905 fix(slark-cicd): document handoff recovery
Refs REQ-20260825-0006
2026-08-26 06:33:14 +09:30
qiudl 826bba8485 Merge pull request '[REQ-20260824-0017] Add req-dev read-model migration gate' (#9) from docs/req-dev-read-model-migration-gate into main 2026-08-25 19:57:07 +00:00
qiudl f5c5bd3f40 docs(req-dev): add read-model migration gate 2026-08-26 05:24:36 +09:30
qiudl 4e6ae9036a fix(installer): detect same-metadata content updates 2026-08-22 08:53:46 +09:30
qiudl 3b38deb078 chore(marketplace): add slark-cicd-plugin 2026-08-22 08:15:02 +09:30
qiudl 16e58047a0 Merge PR #8: req-prd dual persistence and OSS prototypes
Publish req-prd and req-prototype 2.2.0.
2026-08-21 14:30:01 +00:00
qiudl dec25562a4 feat(req-prd): persist docs and prototypes remotely 2026-08-21 23:59:14 +09:30
qiudl d630b374a3 Merge PR #7: req-prd HTML prototype delivery loop
Publish req-prd and req-prototype 2.1.0.
2026-08-21 14:20:27 +00:00
83 changed files with 2773 additions and 59 deletions
+31 -5
View File
@@ -401,6 +401,32 @@
],
"strict": false
},
{
"name": "slark-cicd-plugin",
"source": "./skills-dev/slark-cicd-plugin",
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
"version": "1.1.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "slark-dsh-cicd-plugin",
"source": "./skills-dev/slark-dsh-cicd-plugin",
"description": "DSH 插件包与 Slark 宿主补丁的发布实战技能:npm run pack 双资产、无上游写权限时的 fork 发布、干净单提交与树一致性 gate、draft Release、发布后 SHA 核对、asar 完整性与 ai-proj 状态对齐。",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "req-audit-plugin",
"source": "./skills-req/req-audit-plugin",
@@ -470,7 +496,7 @@
"name": "req-plugin",
"source": "./skills-req/req-plugin",
"description": "需求工作流管理入口。用于 /req 命令使用、需求生命周期管理、需求撰写(含草稿门禁)。",
"version": "2.0.0",
"version": "2.1.0",
"category": "productivity",
"keywords": [
"project-management",
@@ -482,8 +508,8 @@
{
"name": "req-prd-plugin",
"source": "./skills-req/req-prd-plugin",
"description": "产品需求设计技能。覆盖问答访谈、PRD、缺陷收敛及 HTML 原型验证闭环。纯产品视角,不含技术实现。",
"version": "2.1.0",
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
"version": "2.3.0",
"category": "productivity",
"keywords": [
"project-management",
@@ -495,8 +521,8 @@
{
"name": "req-prototype-plugin",
"source": "./skills-req/req-prototype-plugin",
"description": "原型生成与关联。支持 HTML 正式交付、Requirement 关联、iframe 验证闭环及 Stitch AI 视觉探索。",
"version": "2.1.0",
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
"version": "2.2.0",
"category": "productivity",
"keywords": [
"project-management",
@@ -0,0 +1,19 @@
# 已拒绝:为某一种 harness 单开分支
- 状态:拒绝(长期有效)
- 日期:2026-10-31
## 想法
为 Codex / DSH / Claude 某一个客户端的特例,单独复制一份技能或加一个 harness 分支。
## 为什么拒绝
1. 复制出来的两份技能会立刻开始漂移,评测也要做两遍;
2. 客户端差异应交给安装器(目录、调用模式、字段映射)处理,不该写进技能内容;
3. 特例需求通常是个人的工作流调整,属于 `AGENTS.md` / `CLAUDE.md` 或 fork 的范围。
## 允许的替代路径
- 客户端差异 → 安装器加 target / 字段映射;
- 个人流程 → 个人目录或 fork。
+20
View File
@@ -0,0 +1,20 @@
# 已拒绝:新增「随手想到」的技能
- 状态:拒绝(长期有效)
- 日期:2026-10-31
## 想法
「我觉得应该有个技能做 X」——从想象出发新增技能,而不是从真实失败出发。
## 为什么拒绝
1. 技能目录是每次会话启动就要付的上下文预算,加一个就多一份;
2. 没有真实失败做依据的技能,写出来是泛泛而谈,实际触发率极低;
3. 技能之间会互相抢触发(description 相似),新增一个会稀释已有技能的准确率。
## 允许的替代路径
- 先用现有技能做一遍真实任务,记录卡点;
- 确实组合不出来,再按 `SCOPE.md` 门槛提,附真实失败证据;
- 只是个人偏好 → 放 `skills-personal/`,不进团队库。
+19
View File
@@ -0,0 +1,19 @@
# 已拒绝:把个人工作流调优塞进团队技能
- 状态:拒绝(长期有效)
- 日期:2026-10-31
## 想法
把某个人的偏好(提交信息格式、分支命名、审查语气、工具习惯)直接写进团队技能。
## 为什么拒绝
1. 团队技能要能被所有人用,个人偏好会变成隐式规训;
2. 一旦写进技能,改起来要走 PR,个人改不动;
3. 这类偏好本来就该放个人 `AGENTS.md` / `CLAUDE.md`。
## 允许的替代路径
- 个人偏好 → 个人配置文件或 `skills-personal/`;
- 如果是团队共识(不是个人偏好),走 `SCOPE.md` 门槛并附真实失败。
+25
View File
@@ -0,0 +1,25 @@
# 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`。
### 变更
- 18 个命令型技能转 `user-invoked`(biz/integration/dev-android|ios|pda/publish/发布链),目录预算减少 18 项。
- `dev-review`:增加「接收与响应评审意见」。
- `req-design`:增加「任务依赖边(blocking edges)」。
- `agent-swarm`:增加「并行编排流程」。
- `dev-test`:增加「TDD 循环」。
- `generate-marketplace.py`:只发布 `promoted`,beta/deprecated 不随 marketplace 分发。
- 按 SCOPE 降级两个无增量技能:`verification-before-completion`、`ai-proj-helper-entry`(规则已在用户级 AGENTS.md),入口路由内容转为 `docs/skill-routing.md`。
+7
View File
@@ -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`。
+15
View File
@@ -195,3 +195,18 @@ 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=<path> ./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、四段式文档、路由回改),不要手写。
- **路由表**:`docs/skill-routing.md`(什么任务用哪个技能,人读;由原 `ai-proj-helper-entry` 技能降级而来)。
+45
View File
@@ -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。
+21
View File
@@ -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="<your 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`。
+685
View File
@@ -0,0 +1,685 @@
{
"repo": "ai-proj-helper",
"generated_at": "2026-10-31T14:18:10Z",
"total": 61,
"counts": {
"promoted/user-invoked": 18,
"deprecated/user-invoked": 1,
"promoted/model-invoked": 40,
"beta/user-invoked": 1,
"deprecated/model-invoked": 1
},
"skills": [
{
"name": "biz-contract",
"category": "biz",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "商务合同撰写。支持多种合同类型:软件订阅合同、软件定制开发合同、物流合同、销售服务合同、贸易合同等。当用户提到合同、协议、签约、合作协议相关任务时自动激活。",
"description_len": 78,
"path": "skills-biz/biz-contract-plugin/skills/SKILL.md",
"digest": "3d346d4a316590a3"
},
{
"name": "biz-ops",
"category": "biz",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "商务运营技能。支持商业计划书(BP)撰写和商务合同起草。当用户提到商业计划书、BP、融资计划、商业模式、合同、协议、签约等相关任务时自动激活。",
"description_len": 71,
"path": "skills-biz/biz-ops-plugin/skills/SKILL.md",
"digest": "aa5433074ba277d6"
},
{
"name": "biz-plan",
"category": "biz",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "商业计划书撰写。支持融资BP、战略规划、商业模式设计等。当用户提到商业计划书、BP、融资计划、商业模式、战略规划相关任务时自动激活。",
"description_len": 66,
"path": "skills-biz/biz-plan-plugin/skills/SKILL.md",
"digest": "f3bb159157441ca7"
},
{
"name": "finance",
"category": "biz",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "财务对账技能。支持银行对账、应收对账、应付对账、内部往来对账等。通过自然语言实现账单导入、差异分析、对账报告生成。当用户提到对账、银行流水、应收应付、账单核对、财务核销相关任务时自动激活。",
"description_len": 94,
"path": "skills-biz/finance-plugin/skills/SKILL.md",
"digest": "5191b5a91b34ecd6"
},
{
"name": "ai-proj-helper-entry",
"category": "core",
"version": "0.1.0",
"status": "deprecated",
"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": "user-invoked",
"description": "发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。",
"description_len": 48,
"path": "skills-core/publish-plugin/skills/SKILL.md",
"digest": "198c63f0dcb58d57"
},
{
"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": "user-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": "49ef1b6865c2f1b3"
},
{
"name": "ai-proj-macos-release",
"category": "dev",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-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": "6f2496b941706137"
},
{
"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": "user-invoked",
"description": "Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。当涉及 Android 开发任务时按需加载。",
"description_len": 72,
"path": "skills-dev/dev-android-plugin/skills/SKILL.md",
"digest": "fb058d1059b56cdd"
},
{
"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": "user-invoked",
"description": "iOS 开发插件。Swift/SwiftUI + MVVM 架构,TestFlight 部署。当涉及 iOS 开发任务时按需加载。",
"description_len": 65,
"path": "skills-dev/dev-ios-plugin/skills/SKILL.md",
"digest": "44499e31f1abd5e2"
},
{
"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": "user-invoked",
"description": "PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先。当涉及 PDA/手持终端开发时按需加载。",
"description_len": 57,
"path": "skills-dev/dev-pda-plugin/skills/SKILL.md",
"digest": "2524f2ecd4f2a834"
},
{
"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": "user-invoked",
"description": "Excel 数据处理与 BI 集成。通过自然语言操作 Excel 文件的读取、编辑、转换,并支持导入到 BI 系统(Metabase)进行可视化分析。当用户提到 Excel、表格处理、数据导入、BI 分析相关任务时自动激活。",
"description_len": 112,
"path": "skills-integration/data-excel-plugin/skills/SKILL.md",
"digest": "8dc4be8f88cfd866"
},
{
"name": "doubao-voice",
"category": "integration",
"version": "1.0.1",
"status": "promoted",
"invocation": "user-invoked",
"description": "豆包语音API调用。支持语音合成(TTS)和唱歌。当用户提到语音合成、文字转语音、唱歌、豆包语音相关任务时自动激活。",
"description_len": 58,
"path": "skills-integration/doubao-voice-plugin/skills/SKILL.md",
"digest": "7dc73d3b97e61fd2"
},
{
"name": "feishu-bitable",
"category": "integration",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "飞书多维表格操作。用于记录增删改查、批量操作、筛选排序、数据同步。当需要操作飞书多维表格时使用。",
"description_len": 48,
"path": "skills-integration/feishu-bitable-plugin/skills/SKILL.md",
"digest": "3bf37533007365a3"
},
{
"name": "feishu-docx",
"category": "integration",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "飞书云文档操作。用于创建、编辑云文档,插入内容块,会议纪要生成。当需要操作飞书云文档时使用。",
"description_len": 46,
"path": "skills-integration/feishu-docx-plugin/skills/SKILL.md",
"digest": "49d097bfa2c283ab"
},
{
"name": "feishu",
"category": "integration",
"version": "1.1.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "飞书文档与多维表格操作入口。当用户提到飞书、云文档、多维表格、Bitable 相关任务时自动激活。",
"description_len": 49,
"path": "skills-integration/feishu-plugin/skills/SKILL.md",
"digest": "973c6ac22104ee38"
},
{
"name": "siyuan",
"category": "integration",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "思源笔记 API 集成。通过自然语言创建、编辑、搜索笔记,管理笔记本和文档树。当用户提到思源笔记、SiYuan、笔记管理、知识库相关任务时自动激活。",
"description_len": 74,
"path": "skills-integration/siyuan-plugin/skills/SKILL.md",
"digest": "55f6175d81e7b524"
},
{
"name": "siyuan-to-feishu",
"category": "integration",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "将思源笔记导出为 PDF 并发送到飞书群。当用户提到\"发送笔记\"、\"导出PDF发飞书\"、\"/siyuan send\"、\"分享到飞书\"相关任务时自动激活。",
"description_len": 76,
"path": "skills-integration/siyuan-to-feishu-plugin/skills/SKILL.md",
"digest": "998dace910c1eb7a"
},
{
"name": "wecom",
"category": "integration",
"version": "1.0.0",
"status": "promoted",
"invocation": "user-invoked",
"description": "企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。",
"description_len": 77,
"path": "skills-integration/wecom-plugin/skills/SKILL.md",
"digest": "cec289b67805389d"
},
{
"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": "deprecated",
"invocation": "model-invoked",
"description": "汇报「完成/修好/通过」或关闭任务、提交 PR、宣布 REQ 完成之前,必须先运行验证命令并附证据;没有证据不得声称完成。当准备说完成、关闭任务、或汇报交付前使用。",
"description_len": 82,
"path": "skills-req/verification-before-completion-plugin/skills/SKILL.md",
"digest": "7c23649f4a0a8798"
}
]
}
+38
View File
@@ -0,0 +1,38 @@
# 技能路由表(人读)
> 由原 `ai-proj-helper-entry` 技能降级而来:内容属于「索引」而不是「规则」,做成文档即可,不占技能目录、不用维护技能生命周期。
## 交付终点(强制)
开发任务交付终点是:需求按 REQ 流程推进到具备发布条件并完成上线(`delivery_stage=released` + PDV 验收通过)。
写代码、过单测、提 PR、合并都只是过程节点;任务 `completed` ≠ 需求完成。
## 主流程
讨论(`req`) → PRD(`req-prd`) → 评审(`req-review`) → 设计(`req-design`) → 开发(`dev-coding`/`karpathy-guidelines`) → 测试(`dev-test`+`req-test-gate`) → 代码评审(`dev-review`) → 发布(`slark-cicd`/`slark-dsh-cicd`/`publish`) → PDV 验收 → released
## 按任务选技能
| 任务 | 技能 |
| --- | --- |
| 讨论 / 调研 / 对比 | `req`、`req-research`、`req-compare` |
| PRD / 原型 | `req-prd`、`req-prototype` |
| PRD 评审 | `req-review` |
| 设计 / 拆任务 | `req-design`、`dev-arch`、`db-migration` |
| 编码 | `dev-coding`、`karpathy-guidelines` |
| 测试 | `dev-test`、`req-test-gate` |
| 代码评审 | `dev-review`、`review-checklist` |
| 发布(Slark 仓库/Desktop) | `slark-cicd` |
| 发布(DSH 插件/宿主补丁) | `slark-dsh-cicd` |
| 发布(ai-proj 服务 / macOS 包) | `ai-proj-cicd-release`、`ai-proj-macos-release` |
| 回滚 | `deploy-rollback` |
| 部署后审计 / 回归 | `req-audit`、`req-lookback` |
| 复盘 | `req-retro` |
| 项目管理 | `project-management`、`pm-risk`、`pm-ask` |
| 建/改技能 | `skill-creator` |
## 红线
- 不得自审批;不得绕过门禁(测试 Gate / 发布 Gate / 归档 Gate)
- 不得把「某步骤完成」当结束;不得无证据声称完成
- 不得把凭据/内网地址/绝对路径写进技能或文档
+9 -1
View File
@@ -60,7 +60,7 @@ def load_config():
def get_category_and_keywords(plugin_name):
if any(x in plugin_name for x in ['dev-', 'coding', 'frontend']):
return "development", ["development", "coding", "workflow"]
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server']):
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server', 'slark-cicd', 'slark-dsh-cicd']):
return "devops", ["devops", "deployment", "operations"]
elif any(x in plugin_name for x in ['ai-proj', 'req']):
return "productivity", ["project-management", "tasks", "requirements"]
@@ -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({
+95 -5
View File
@@ -5,7 +5,11 @@
# ./install-skills.sh [options]
#
# Options:
# --agent <agent> Install target: codex (default) or claude
# --agent <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 <cat> Only install plugins in dir_category=<cat>
# 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.
@@ -365,7 +411,7 @@ install_plugin() {
else
mkdir -p "$dst_dir"
# rsync resolved source (handles nested skills/ structures)
rsync -a --delete "$src_dir/" "$dst_dir/"
rsync -a --checksum --delete "$src_dir/" "$dst_dir/"
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
ok "$install_name → skill (v$version)"
INSTALL_ACTION=true
@@ -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"
+106
View File
@@ -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())
+5
View File
@@ -0,0 +1,5 @@
# 安全扫描允许清单(人工确认过的误报)
# 格式:<路径子串>::<匹配文本中的特征串>
# 例:某技能文档把危险命令当作“禁止清单”引用,而非真的要执行。
skills-dev/slark-cicd-plugin::NEVER_AUTO
skills-dev/slark-cicd-plugin::destructive
+82
View File
@@ -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 <abs_path> <matched_line>
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
+161
View File
@@ -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())
@@ -7,5 +7,6 @@
},
"install_name": "biz-contract",
"install_type": "skill",
"dir_category": "biz"
"dir_category": "biz",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: biz-contract
description: 商务合同撰写。支持多种合同类型:软件订阅合同、软件定制开发合同、物流合同、销售服务合同、贸易合同等。当用户提到合同、协议、签约、合作协议相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 商务合同撰写技能 (biz-contract)
@@ -7,5 +7,6 @@
},
"install_name": "biz-ops",
"install_type": "skill",
"dir_category": "biz"
"dir_category": "biz",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: biz-ops
description: 商务运营技能。支持商业计划书(BP)撰写和商务合同起草。当用户提到商业计划书、BP、融资计划、商业模式、合同、协议、签约等相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 商务运营 (biz-ops)
@@ -7,5 +7,6 @@
},
"install_name": "biz-plan",
"install_type": "skill",
"dir_category": "biz"
"dir_category": "biz",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: biz-plan
description: 商业计划书撰写。支持融资BP、战略规划、商业模式设计等。当用户提到商业计划书、BP、融资计划、商业模式、战略规划相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 商业计划书撰写技能 (biz-plan)
@@ -7,5 +7,6 @@
},
"install_name": "finance",
"install_type": "skill",
"dir_category": "biz"
"dir_category": "biz",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: finance
description: 财务对账技能。支持银行对账、应收对账、应付对账、内部往来对账等。通过自然语言实现账单导入、差异分析、对账报告生成。当用户提到对账、银行流水、应收应付、账单核对、财务核销相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 财务对账技能
@@ -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": "deprecated",
"invocation": "user-invoked"
}
@@ -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 回改
- 每季度人工过一遍本路由,删掉不再用的技能引用
@@ -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 安装/审计命令"
}
]
}
@@ -7,5 +7,6 @@
},
"install_name": "publish",
"install_type": "skill",
"dir_category": "core"
"dir_category": "core",
"invocation": "user-invoked"
}
@@ -2,6 +2,9 @@
name: publish
description: 发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。
user_invocable: true
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# publish - 技能市场发布与通知
@@ -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"
}
@@ -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-<N>/`,按 rubric 打分,PR 附结果
## 8. 四段式文档(每个 promoted 技能一篇)
`docs/skills/<name>.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. 是否触碰红线(自审批、绕过门禁、绝对路径、凭据)
@@ -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、入口路由"
}
]
}
@@ -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 不得写同一文件;不确定时先串行。
@@ -7,5 +7,6 @@
},
"install_name": "ai-proj-cicd-release",
"install_type": "skill",
"dir_category": "dev"
"dir_category": "dev",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: ai-proj-cicd-release
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.
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# AI-Proj CI/CD release
@@ -7,5 +7,6 @@
},
"install_name": "ai-proj-macos-release",
"install_type": "skill",
"dir_category": "dev"
"dir_category": "dev",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: ai-proj-macos-release
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.
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# AI-Proj macOS release
@@ -7,5 +7,6 @@
},
"install_name": "dev-android",
"install_type": "skill",
"dir_category": "dev"
"dir_category": "dev",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: dev-android
description: Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。当涉及 Android 开发任务时按需加载。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# Android 开发插件 (dev-android)
@@ -608,3 +608,55 @@ fi
### 非阻断原则
架构信息缺失时**仅警告不阻止**。用户仍可继续,但会被告知"生成的建议可能不够准确"。
---
## Step 0.5:Shell 环境自检(node/npm command not found 先看这里)
**在任何 `npm` / `pnpm` / `node` 命令之前,先确认解释器可解析。** 报 `command not found` 时
**不要**下结论"当前环境没有 shell",也**不要**去找"给 agent 配 shell"的开关(DSH 没有这个开关)。
### 根因(不要重复侦察;已在 macOS + Slark/DSH 上定位到代码)
| # | 事实 |
|---|------|
| 1 | DSH 的 bash 工具(`@deepseek-ai/dsh-bash-local`)一律以 **`bash -c`(非登录、非交互)** 执行 → **不读** `~/.zprofile` / `~/.zshrc` / `~/.profile` |
| 2 | 子进程环境 = **宿主进程环境** − 凭据类变量 − `DSH_*`(`@deepseek-ai/dsh-subprocess`)→ **PATH 不被清洗**,它等于启动宿主那个进程的 PATH |
| 3 | 宿主由 GUI 应用(Slark.app)拉起 → 继承 macOS GUI 的最小 PATH(`/usr/local/bin:/bin:/usr/bin:...`)→ node 不在里面 |
| 4 | `HOME` **未设置**(不是空值);`USER` / `TMPDIR` / `LANG` 同样未设置 |
| 5 | `@deepseek-ai/dsh-shell-env` 只注册/注入 **`DSH_*`** 变量,`PATH` 是保留键 → 改 profile/`cordis.patch.yml` 加 PATH **无效** |
### 正确做法(两行 export,别多一步)
```bash
export HOME="/Users/johnq" # 必须补:git 等直接读 $HOME
export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:$PATH" # node/npm/pnpm
cd <项目> && npm install && npm run build
```
**为什么 `HOME` 必须补**(实测):
- `~` 在 bash 里靠 passwd 查表展开,所以 `ls ~`、`cd ~/x` 仍能用 → **容易误判环境正常**;
- 直接读 `$HOME` 的会崩:`git` → `fatal: $HOME not set`(`status` / `commit` / `config --global` 全废);
带 `set -u` 的脚本 → `HOME: unbound variable`(例:ai-proj-helper 的 `install-skills.sh`);
- node 侧多数无事(`os.homedir()` 走 passwd 兜底,只有 `process.env.HOME` 是 `undefined`)
→ **「node 能跑」≠ 环境完整**,别据此跳过 `HOME`。
- **本机 node 必须用这一支**(定义在 `~/.zprofile`,对齐项目 `engines.node`):
`/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin/node` = v22.22.3,npm 10.9.8。
- `/opt/homebrew/bin/node` 是**另一支 v26**,不要混用;`/usr/local/bin/node` 不存在。
- 备选①:`/bin/zsh -lic '<命令>'`(登录 zsh 会读 `~/.zprofile`)。
- 备选②:绝对路径直调 `/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin/node build.mjs`。
- 路径变了先 `ls -d /Users/johnq/.local/node-v*-darwin-arm64/bin` 重新取**真实版本号**,不要猜。
### 交付纪律(配合「Step 0:验证优先」)
- **禁止**把"没有 shell / 不能构建"写成交付结论:bash 工具是好的,缺的只是 `HOME` + `PATH`。
正确表述是"我未执行构建(缺 node PATH,已给用户补 PATH 后的构建命令)"。
- 构建/测试没跑就说没跑(`未经构建与实机验证`),**不要**用"构建配置已就绪"之类中间信号冒充验收。
- 校验环境的最快方式(输出直接贴进交付):
```bash
export HOME="/Users/johnq"; export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:$PATH"
node -v && npm -v && git status --short | head -3
```
@@ -7,5 +7,6 @@
},
"install_name": "dev-ios",
"install_type": "skill",
"dir_category": "dev"
"dir_category": "dev",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: dev-ios
description: iOS 开发插件。Swift/SwiftUI + MVVM 架构,TestFlight 部署。当涉及 iOS 开发任务时按需加载。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# iOS 开发插件 (dev-ios)
@@ -7,5 +7,6 @@
},
"install_name": "dev-pda",
"install_type": "skill",
"dir_category": "dev"
"dir_category": "dev",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: dev-pda
description: PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先。当涉及 PDA/手持终端开发时按需加载。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# PDA 应用开发插件 (dev-pda)
@@ -303,3 +303,13 @@ mcp__ai-proj__link_tasks_to_requirement({
4. **严重度准确** — 不要所有问题都标 High,按实际影响分级
5. **建议可操作** — 每个发现必须附带具体修复建议
6. **关注变更** — 评审范围是 diff,不要对未变更的代码提意见(除非变更引入了对旧代码的新风险)
## 接收与响应评审意见
评审不是单向输出,收到意见后按这套来:
1. **先分类**:阻断项(必须修)/ 建议项(可讨论)/ 澄清项(问题理解不一致)。
2. **先复述再回应**:用自己的话重述意见,确认理解一致,再给证据或修改。
3. **不辩解**:用证据说话(代码、测试、日志),不用语气词反驳。
4. **逐条回评**:每条写「已修(commit)/ 不修(理由)/ 需澄清(具体问题)」,不得默默跳过。
5. **阻断项没修完不得合并**;建议项不修要记录原因,进 PR 描述。
@@ -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. 交付时附:测试命令、通过/失败数、以及「曾经红过」的证据(日志或截图记录)。
@@ -0,0 +1,11 @@
{
"name": "slark-cicd-plugin",
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
"version": "1.1.0",
"author": {
"name": "qiudl"
},
"install_name": "slark-cicd",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,233 @@
---
name: slark-cicd
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、复现或验证运行时行为、或排查发布链/推送路由问题时使用。
---
# Slark CI/CD runbook
驱动 Slark 从改代码到上线的端到端流程。权威流程与完整细节见仓库文档
`docs/cicd-staging-production.md`(本技能命令与之一致);本文件是可直接照做的分阶段清单。
仓库:`qiudl/qiu-slark`(本机克隆通常在 `/Users/donglinlai/coding/slark`)。所有命令在**仓库根**执行。
`ai-proj` 相关命令加 `GODEBUG=netdns=go` 前缀。
## 铁律(先记死)
- GitHub `origin/main` 是唯一代码权威、合并入口与生产发布来源;`internal` 只用于 CI/镜像,永不发布。
- 生产发布只接受**最新 `origin/main` 的精确 40 位 SHA**;`HEAD != origin/main` 会被 `deploy.sh` 拒绝。
- 生产发布必须在**普通 clone** 中执行,且 `.git` 必须是目录;`release-prod.sh` / `deploy.sh` 会拒绝
`.git` 为指针文件的 git worktree。不要污染现有 checkout:主目录脏或被占用时,新建干净的临时 clone。
- **生产发布前必须先发布并验收 staging,不得跳过**:同一最新 `origin/main` 精确 SHA 必须先完成迁移演练、
staging 正式部署、隔离检查和需求功能验收。把证据报告给用户后,必须再次取得明确的生产确认;开始 staging
前获得的生产授权不能替代这次确认。未通过、未完成或用户未确认时停止,不得执行生产发布命令。
- 审批式部署,永不自动:亲手敲的 `sudo`/`rm -rf`/`dd`/`curl|sh`/包安装是 `destructive`(NEVER_AUTO),
**每次都要人审**;命中审批闸就**等人批**,绝不绕过、绝不把这些 key 加进 auto-approve 白名单。
- staging 与生产硬隔离:staging 脚本带生产 IP 拒运行护栏、不 push origin、不反向 rsync。
- 当前 Slark staging 权威目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`
(Name=`slark-staging`,2026-08-18 核验公网 IP `15.135.112.181`)。公网 IP 自动分配,发布前必须按
实例 ID 重查并确认 Name/状态;不得凭历史 IP 判断目标。
- `82.157.141.202` 是 ai-proj 预生产宿主机。其 `/opt/slark-staging` cohost 是隔离的 Slark 兼容验收栈,
但不是 Slark 独立预生产;只有任务明确指定 cohost 时才能使用,不得作为普通 Slark staging 的默认目标。
- staging 发布若影响 `packages/daemon`、`packages/runtime`、Server/daemon 公共协议或 Desktop 公共运行链,
必须把 `server-staging` 与 `daemon-staging` 更新到同一精确 SHA;两者版本不一致不得宣告 staging 成功。
- 只修 PR 范围内的 CI 失败;不为过检去改 CI/workflow 或做无关改动。
## 选择链路
- 「发布/上线/部署生产」→ 生产发布链:阶段 1→2→3(同 SHA staging 验收)→ 人工确认 →4→5。
- 「Desktop/桌面版打包、发布、上传 OSS」→ 阶段 1→2 后走 `docs/desktop-oss-release.md` 的 m5max 双平台链路。
- 「盯 CI/合并 PR」→ 阶段 1→2(用 babysit 心态循环到 green + mergeable + 评论收口)。
- 「复现/验证运行时行为、别碰生产」→ staging 预验链(阶段 3,可独立随时跑)。
## 阶段 1:PR 与内网 gate(`ci/internal-gate`)
真实门禁是内网 CI(GitHub Actions 已停用)。检查与自查:
```bash
gh pr checks <PR> # 应见 ci/internal-gate
gh pr view <PR> --json state,mergeable,mergeStateStatus,isDraft,reviewDecision
```
- 基础门(全 PR):release-contract / member-gate / authz-matrix / controlled-content-exits /
onconflict-predicate / migration-idempotency / wsl-path-translation / typecheck / test(全量)。
- 条件外部门(按改动路径):改 server DB/迁移/schema → `postgresql-security`;改 web → `web-e2e`;
android / daemon+desktop 各有门。
- 本地复跑基础门可跑部分:`pnpm -r typecheck && pnpm test`。
红了:只修本 PR 范围内的失败。疑似无关的合并阻塞→先 merge 最新 `main`(可能别的 PR 已修)。
`BLOCKED: <label> requires <VAR>` = runner 环境未配外部门命令,属运维问题,不是 PR 代码问题。
## 阶段 2:合并到 `origin/main`
合并前确认:`mergeable=MERGEABLE`、`mergeStateStatus=CLEAN`、非 draft、`ci/internal-gate` 绿、评论收口。
```bash
gh pr merge <PR> --merge # 仓库风格:merge commit
```
若本机 `main` 被其他 worktree 占用导致 `--delete-branch` 本地 checkout 失败(属本地副作用):
```bash
gh pr view <PR> --json state,mergedAt,mergeCommit # 确认 GitHub 侧 MERGED
git push origin --delete <feature-branch> # 删远端
git branch -D <feature-branch> # 删本地(先切走)
```
## 阶段 3:staging 真机预验(生产前强制,也可独立运行)
生产候选必须使用最新 `origin/main` 的同一精确 SHA。先执行迁移演练,再正式部署;随后完成隔离检查和本次需求的
功能验收。验收不能只看通用 health:凡需求涉及真实集成(如飞书 OAuth),staging 缺少对应 provider/凭据时必须
明确标为未完成并停止生产链,除非用户在看到该限制后明确接受。完成后报告目标实例、SHA、Server/Daemon revision、
迁移演练、健康、隔离和功能结果,并等待用户再次确认是否进入生产。
### 3.1 当前权威路径:Slark 独立 staging
稳定目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`(Name=`slark-staging`)。它使用自动分配
公网 IP,因此每次部署前先查询当前 IP;2026-08-18 核验值为 `15.135.112.181`:
```bash
aws ec2 describe-instances --region ap-southeast-2 \
--instance-ids i-013e5ca3fdfddc13e \
--query 'Reservations[0].Instances[0].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name,PublicIp:PublicIpAddress}' \
--output table
export STAGING_SSH_KEY=~/.ssh/cloud-server-syd.pem
export STAGING_REMOTE=ubuntu@15.135.112.181
export STAGING_REMOTE_IP=15.135.112.181
export STAGING_BASE=http://15.135.112.181
scripts/deploy-staging.sh --migrate-dry-run
scripts/deploy-staging.sh
STAGING_TOKEN=$(cat /tmp/.staging_token) scripts/staging-seed.sh
scripts/staging-verify-isolation.sh
```
不得把查询到的 Name 非 `slark-staging` 的机器当作目标。四件套细节与环境隔离约束见
`docs/req-20260811-0059-staging-environment-design.md`。
### 3.2 非权威路径:ai-proj cohost(仅明确指定时)
ai-proj cohost 位于 `ubuntu@82.157.141.202:/opt/slark-staging`。全程使用隔离数据、数据库、密钥和状态目录,
但宿主机身份仍是 ai-proj staging;普通“Slark 预生产”不得走这里。仅在任务明确要求 cohost 兼容验收时,
先在**干净的独立 worktree**检出待验精确 SHA,再执行:
```bash
STAGING_SSH_KEY=~/.ssh/ai_proj_stg.pem \
STAGING_KNOWN_HOSTS_FILE=~/.ssh/known_hosts \
STAGING_REMOTE=ubuntu@82.157.141.202 \
STAGING_REMOTE_IP=82.157.141.202 \
scripts/deploy-staging-cohost.sh
```
如果改动影响 daemon/runtime/公共协议,还需用 Compose `daemon` profile 更新 `daemon-staging`,并核对
Server/daemon revision 同为待验 SHA。
### 3.3 环境选择检查
普通 Slark staging 默认走 3.1;只有用户或需求明确说“ai-proj cohost”才走 3.2。任何验收都必须记录:
环境稳定身份、当次 IP、待验 40 位 SHA、Server/daemon revision/status、Server health 和目标功能结果。
routed-remote 要 `network=enabled` 必须同时满足:① agent `workspace_access=write` +
`repository_access=write`;② per-agent 工作区是可写 git worktree。细节见
`docs/req-20260811-0059-staging-environment-design.md`。staging 刻意不碰 `deploy.sh` 的生产闸门。
## 阶段 4:生产发布(审批式)
**前置门禁**:阶段 3 已对同一 SHA 完成 staging 部署和验收,证据已报告,且用户在报告之后明确确认生产发布。
缺任一项即停止;不得把 PR 合并授权、较早的生产授权或单纯的“继续”视为验收后确认。
**唯一姿势**:从干净的普通 clone 发布最新 `origin/main`(`HEAD == origin/main` 精确 SHA)。staging 可用
独立 worktree,但生产脚本为保证同步与发布边界,会拒绝 worktree;不要在用户已有脏 checkout 中清理或发布。
```bash
# 若当前仓库不是普通 clone,先在安全父目录创建一次性干净 clone:
git clone https://github.com/qiudl/qiu-slark.git <clean-production-clone>
cd <clean-production-clone>
git fetch origin main
test -d .git # 必须通过;worktree 的 .git 是文件
git status --porcelain # 必须干净
git checkout --detach "$(git rev-parse origin/main)" # 在产品分支上时先 detach 到该 SHA
pnpm release:prod # = release-prod.sh → deploy.sh --backend --no-install --no-mirror
# 备选:scripts/deploy.sh --pull --backend
```
- `deploy.sh` 用 `check-production-release-sha.sh` 锁 `HEAD == origin/main` SHA,不符即拒。
- `--backend` 才跑迁移:owner 连接(DDL 权)与运行时 `slark_app`(DML-only)分离;幂等、失败即非零。
- 命中审批闸(发布/sudo)→ **等人批**;不要绕。脚本内部 SSH 载荷子进程的 sudo 不触发闸。
- 普通工作 clone 发布完切回原分支:`git checkout <branch>`;一次性发布 clone 可保留作审计,清理时用可恢复方式。
### HANDOFF_BLOCKED 恢复入口
发布准备遇到 `HANDOFF_BLOCKED`、handoff manifest=`failed_closed` 或命令状态不确定时,停止发布切换;禁止靠重跑
发布脚本、直接改表或默认 replay 来“解卡”。先把 manifest、命令、execution、lease/outbox 和审计证据做只读盘点,
再让用户明确授权每条记录的 reconciliation action/outcome 及是否允许继续发布。恢复细节见
[references/production-handoff-recovery.md](references/production-handoff-recovery.md);仅遇到该类事故时读取。
`COMMAND_AUTHORITY_CHANGED` 是有效并发护栏,不是可忽略错误:重新读取当前 authority/transport/execution generation,
确认期间没有新活动,再在原授权范围内幂等续办。若发现新工作、活跃 lease/outbox 或无法解释的副作用,立即停止并
重新请求决策。
## 阶段 5:发布后核查
```bash
scripts/verify-deploy.sh # 健康(前端/api/health=200)、bundle、server/daemon SHA、迁移集、federation、凭据
```
预期 `✓ deploy verification passed: server=<sha> daemon=<sha>` 且 `<sha> == origin/main`,舰队 `online ≥ 发布前`。
完成前还要独立复核 governed release 账本为 `succeeded/complete`、四组件实际 SHA 均为目标 SHA、租约已释放、
新 handoff manifest=`verified`;若本次处理过旧 manifest,还要核对其全部 case 已达授权终态且 replay 数为 0。
默认生产包装器使用 `--no-mirror`:构建 daemon candidate binary 用于运行态验证不等于上传镜像资产。镜像落后告警
在该模式下是预期的非阻断结果;不得未经单独授权补传镜像。交付说明要明确国内安装器可能回退 upstream,避免把
本地构建、生产 daemon 更新和镜像上传混为一谈。
## Desktop m5max 双平台发布
Desktop 安装包不走 Server 生产部署脚本。权威流程见仓库 `docs/desktop-oss-release.md`,已验证基线为
REQ-20260819-0005 / Desktop 0.3.1:
- 版本 PR 通过 `ci/internal-gate` 并合并后,m5max 从最新 `origin/main` 精确 SHA 的干净普通 clone 构建。
- m5max 原生构建、Developer ID 签名并公证/staple macOS DMG/ZIP;交叉构建 Windows x64 NSIS EXE。
- Darwin 不能执行 Windows 原生 `smoke:windows`。只有发布负责人明确接手 Windows 原生验收时才能继续交叉打包,交付证据必须标注该边界。
- 资产不回传开发机;由 m5max 直接上传 `xiaoqu-public-file/slark/desktop/releases/v<version>/`,manifest 最后更新。
- `xiaoqu-public-file` 的 canonical 凭证源是发布控制机上的 `/Users/donglinlai/coding/param.rxt`(必须为 `0600`);AK/SK 分别位于 XML 标签 `ossAccessKeyId` / `ossAccessKeySecret`。不得改猜 Bitwarden、Keychain、通用 `credentials.env` 或 m5max 本地配置;只有该文件缺失、权限不符或标签解析为空时才停止并报告。
- m5max 不持久化 OSS 凭证。发布控制机从 `param.rxt` 提取 AK/SK 后,只用 `printf '%s\n%s\n' ... | ssh m5max ...` 经 SSH stdin 传两行;远端用 `read -r` 接收并仅为当次 shell 导出 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`,随后运行上传脚本。禁止 `scp` 凭证文件、写远端临时文件或把值打印到日志。
- m5max 非交互 SSH 必须显式补 `PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH`;已验证 `ossutil` 位于 `/Users/johnq/.local/bin/ossutil`。执行前检查 Node、三个安装包、精确 main SHA 和干净工作树,避免因交互 shell 环境差异重新猜路径。
- m5max 默认出口若走 `utun`,只为当次 `ossutil` 使用 `--bind-address "$(ipconfig getifaddr en0)"`,不得修改整机 Tailscale/默认路由。
- 完成前核对三份资产 SHA256/大小、macOS 签名与公证、公开 URL/manifest,并回写 ai-proj 证据。
## 推送路由自查(换机器/新克隆必做)
```bash
git remote -v # origin 收发都应是 https://github.com/qiudl/qiu-slark.git
git config --get-regexp '^url\.' # 有输出 = pushInsteadOf 改写,push 可能被静默重定向到内网
scripts/git-release-governance.sh check-local
scripts/git-release-governance.sh status
```
## 故障分流
| 现象 | 处置 |
| --- | --- |
| `release-prod` 拒绝 HEAD≠origin/main | `git fetch origin main` 后 detach 到 origin/main SHA,工作树须干净 |
| `release-prod` 拒绝 git worktree / `.git` 不是目录 | 改用干净的普通 clone,锁定最新 `origin/main`;不要在现有脏 checkout 中强行切换 |
| `ci/internal-gate` red | 看 gate 分组日志找 FAIL 项;`pnpm -r typecheck && pnpm test` 本地复现修复 |
| `BLOCKED: <label> requires <VAR>` | runner 未配外部门命令,报运维配 `SLARK_CI_*_CMD`,非 PR 问题 |
| 合并阻塞但与 PR 无关 | merge 最新 `main` 再看 |
| push 成功但 GitHub 没有 | 查 `git config --get-regexp '^url\.'`,移除 pushInsteadOf 或显式指定 GitHub URL |
| staging routed-remote 恒断网 | 查两道放网杠杆(workspace_access=write + 可写 git worktree) |
| cohost Server 已更新但 daemon 仍是旧 SHA | 用 `--profile daemon up -d daemon-staging` 更新 daemon;核对两容器 revision 后才算完成 |
| cohost daemon 启动即退出/fatal | 看 `docker logs slark_daemon_staging`;修复凭据/环境或版本契约,禁止用旧 daemon 冒充验收通过 |
| verify 失败 SHA 不符 | 部署到了旧码,重发 |
| `HANDOFF_BLOCKED` / manifest=`failed_closed` | 停止切换并读取 handoff recovery 参考;只读盘点后取得逐项 action/outcome 授权,禁止默认 replay |
| reconciliation 返回 `COMMAND_AUTHORITY_CHANGED` | 查当前 generation 与新活动;无新活动才在原授权内幂等续办,有变化则停止重新决策 |
| `--no-mirror` 后提示镜像落后 | 预期非阻断;报告 upstream fallback,未经单独授权不上传镜像 |
| 生产授权已给但 staging 尚未验收 | 先完成同 SHA staging 全量验收,报告证据并重新等用户确认;不得沿用较早授权 |
| staging 缺少需求依赖的真实集成配置 | 将对应验收标为未完成并停止生产链;补齐配置后重验,或让用户基于明确限制作决定 |
## ai-proj 流程(强制)
任何改产品/代码行为的工作,动手前先在 ai-proj 立项 + 建 Task + 关联,实现/测试/交付回写;
commit/PR 引用 `REQ-...`。纯文档/工具/只读排查除外。详见仓库 `AGENTS.md` / `CLAUDE.md`。
@@ -0,0 +1,70 @@
# Production handoff recovery
仅在生产发布被 coding-session handoff 阻塞、manifest 进入 `failed_closed`,或存在 `needs_review` / 不确定命令时读取。
目标是保留 fail-closed 语义,在明确授权下终结歧义状态,并证明没有误重放命令。
## 先冻结发布,不先解锁
- 停止发布切换和自动重试;记录 release ID、候选 SHA、manifest ID、阻塞发生阶段与原始错误。
- 不把“继续”“再试一次”解释为 replay、force-end 或生产发布授权。向用户展示证据后,确认语句应绑定 manifest、
条目数量或 command ID、目标 action/outcome、是否禁止 replay,以及要继续发布的精确 SHA。
- 不直接更新 handoff、command、execution 表来改变状态。优先走已部署版本的内部治理 API;只有 API 无法恢复且
已获得对应操作授权时,才可调用该版本现有 domain repository,并保留 lifecycle event 与 audit log。
## 只读证据盘点
对 manifest 中每条 item 核对并保存摘要:
- command ID、session/project/computer ID、command status、execution state;
- manifest 记录的 authority term、transport generation、execution generation,以及当前实际值;
- command/execution lease 是否过期,outbox 是否仍有 active/pending 记录;
- session 中是否还有其他活跃命令或新事件;
- daemon acknowledgement、result/receipt、审计事件是否能证明执行或未执行。
若 lease/outbox 仍活跃、存在新命令、证据相互矛盾,或无法排除外部副作用,停止恢复并请求新的人工判断。
## Action 与 outcome 必须匹配证据
- `no_action / not_executed`:只有权威证据能证明命令从未执行,且治理接口允许该组合时使用。
- `terminate / terminated`:用于显式受控终结仍处于 uncertain/active 语义的命令;先通过 domain 操作取消 command、
force-end execution、完成 session 并写审计,再完成 reconciliation,不产生 replay。
- `mark_failed / failed`:证据确认失败、且不能安全恢复为成功或未执行时使用。
- `replay / replayed_success`:仅在用户明确授权 replay 且 exactly-once/幂等边界得到证明时使用。发布解卡绝不能默认 replay。
不要为了迎合预先选择的 outcome 忽略现场证据;如果授权与可证明事实不兼容,停止并把差异报告给用户。
## 受治理恢复顺序
1. 使用精确 manifest/item 建立或读取 reconciliation case。
2. 取得具备 action、evidence digest、operator 和有效期约束的审批。
3. 记录 decision;执行 domain 终结或治理 apply;随后用权威运行态证据 confirm terminal outcome。
4. 若 apply 返回 `COMMAND_AUTHORITY_CHANGED`,不要覆盖或绕过。重新读取当前三类 generation 和新活动:
- generation 只因刚完成的受控终结而变化,且无新命令、lease/outbox 时,可在同一授权 action 下幂等续办;
- generation 对应新工作或原因不明时,停止并重新审批。
5. 每个 item 都 terminal 后,确认 manifest 自动或受治理地进入 `reconciled`,再启动新的发布尝试。
凭据失败发生在事务前时应视为零变更并记录。不要反复猜测 owner 凭据;不得打印连接串或密钥。若必须使用运行时
`slark_app` 连接,只能通过已部署 domain repository、正确的 per-transaction project/user RLS context 和审计路径操作。
## 零重放与发布恢复验收
恢复完成至少证明:
- `terminalCount == totalCount`,每条 decision action 与 terminal outcome 等于用户授权;
- 禁止 replay 的场景下,decision action=`replay` 数和 execution replay attempt 增量均为 0;
- `terminate/terminated` 场景下,command=`cancelled`、execution=`force_ended`,并存在对应 lifecycle/audit 证据;
- 旧 manifest=`reconciled`,没有 active handoff reservation 残留。
继续生产发布时使用新 governed release / handoff manifest,不复用 failed-closed manifest。重新检查候选仍是最新
`origin/main`、同 SHA staging eligibility receipt 仍有效、工作树干净;任何一项变化都回到 staging 与人工确认门禁。
发布成功后再独立执行一次 `scripts/verify-deploy.sh`,并只读核对:release=`succeeded/complete`、target/actual Web、
Server、daemon、artifact SHA 全相等、lease 已释放、finished 已记录、新 manifest=`verified`、舰队在线数不低于基线。
将旧 manifest reconciliation 与新发布证据一起回写 ai-proj。
## `--no-mirror` 的解释边界
- `pnpm release:prod` 默认走 `deploy.sh --backend --no-install --no-mirror`;不上传 daemon 镜像资产。
- 发布过程仍可能在隔离 candidate 目录构建 daemon binary,用于同 SHA 验证或部署运行态 daemon;这不是镜像上传。
- mirror freshness 告警表示镜像源仍旧,国内安装器可能回退到较慢 upstream。它不阻断当前生产运行态发布。
- 补传 mirror 是单独的外部写操作,需要单独授权和凭据;不能为了消除告警在发布收尾时顺手执行。
@@ -0,0 +1,11 @@
{
"name": "slark-dsh-cicd-plugin",
"description": "DSH 插件包与 Slark 宿主补丁的发布实战技能:npm run pack 双资产、无上游写权限时的 fork 发布、干净单提交与树一致性 gate、draft Release、发布后 SHA 核对、asar 完整性与 ai-proj 状态对齐。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "slark-dsh-cicd",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,213 @@
---
name: slark-dsh-cicd
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 完整性/签名问题时使用。
---
# DSH 插件与 Slark 宿主发布 runbook (slark-dsh-cicd)
面向「把插件包/宿主补丁真正发出去」的可执行清单。默认在**发布机**执行;命令按阶段照做,
每阶段结束先核验再进入下一阶段。
## 适用与分工
两条发布线,**互不依赖**,不要串流程:
| 发布线 | 产物 | 入口 | 权威源 |
| --- | --- | --- | --- |
| A · DSH 插件 | `dist/v<ver>/dsh-worktable.tgz` + `dsh-worktable-<ver>.tgz`(同一验收包) | `<pkg>/npm run pack` | GitHub Release(tag = `v<包内版本>`) |
| B · Slark 宿主补丁 | 重打包 + 签名的 Slark.app(含内嵌 DSH runtime) | 宿主自身打包/签名链 | 宿主发布链,不经 GitHub Release |
与同市场技能的分工,避免重复:
- **本技能**:DSH 插件包发布、宿主补丁打包侧的完整性约束、发布链本身(权限、tag、Release、SHA 核对)。
- `slark-cicd`:Slark 仓库 staging 验收、生产发布、Desktop 安装包上传 OSS、PR/CI 门禁——服务器与包分发细节以它为准。
- `dev-cicd`:通用流水线设计与排查(Gitea Actions/缓存/并发)。
- `ai-proj-cicd-release`:AI-Proj 服务自身的门禁与回滚。
## 铁律(先记死)
1. **打包只走唯一入口**:`npm run pack`(或仓库自带的等价脚本)。手写 `tar`/`npm pack` 会绕过结构断言与安装导入验证。
脚本自己会做:版本一致性 → 兼容回归 → 构建 → 语法检查 → 结构断言(精确文件清单、无 `src/`、无 `.map`)→
独立临时目录真实安装 + `import()` 断言 → 客户端/宿主门禁 → 双资产同源 → SHA-256。
2. **`package.json` 与 `dsh.plugin.json` 的版本必须相等**,否则构建与打包脚本 fail-closed。发版只升这一处对,不要只改一边。
3. **产物出了包就不再改**:任何源码/常量/文档改动都可能改变 bundle → 旧 `.tgz` 立即作废、sha 必变。**改完必须重新 pack 并重新记录 sha**。
4. **对上游仓库零改动是硬指标**(尤其是没有写权限的外部作者仓库):不 push、不打 tag、不建 Release/PR,一次都不做。
5. **公开发布必须是 draft 起步**,对外动作经用户过目后再 `--draft=false`。
6. **force push 只允许发生在自己 fork 的分支/tag 上**;绝不对上游使用 `-f`。
7. **发布用的分支必须是干净单提交**,不要为了省事把本地历史推上去(本地历史可能含个人路径、凭据、临时调试 commit)。
8. **"下载通了" ≠ "hash 对了"**:发布完成的判据是「远端资产 sha == 本地验收 sha」,不是页面能打开。
## 阶段 0:身份与权限三连(先判定能力,再决定链路)
```bash
gh auth status # 登录账号是否符合预期
ssh -T git@github.com 2>&1 | head -3 # SSH 身份(回显 Hi <user>! 即通)
gh api repos/<owner>/<repo> --jq '.permissions' # 关键:{"pull":true,"push":<bool>}
```
- **只有 `push:true` 才能走「上游直发」**;`push:false` 时不要硬撞,直接走阶段 2 的 fork 发布。
- **`git ls-remote` 通 ≠ 能 push**:读权限随时可通,写权限被拒要到 push 才暴露。不要用 ls-remote 成功推断可写。
- 同时确认远端协议:`git remote -v`。HTTPS 到 GitHub 可能整体不通(见「网络与链路故障处置」),
必要时改用 SSH:`git remote set-url origin git@github.com:<owner>/<repo>.git`。
## 阶段 1:发布线 A — DSH 插件(有上游写权限)
```bash
export HOME="/Users/johnq"
export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:/opt/homebrew/bin:$PATH"
cd <repo>/<pkg>
npm run check && npm run test:gate && npm run pack
shasum -a 256 dist/v<ver>/*.tgz # 两个文件必须同 sha
tar -xzf dist/v<ver>/dsh-worktable.tgz -C "$(mktemp -d)" && grep -rn "<旧仓库名>" <解包目录> # 期望无输出
git add -A && git commit -m "release: <name> v<ver>(REQ-…)…"
git tag -f v<ver> && git push origin HEAD v<ver>
gh release create v<ver> dist/v<ver>/dsh-worktable.tgz dist/v<ver>/dsh-worktable-<ver>.tgz \
--draft --title "<name> v<ver>" --notes-file <notes.md>
```
- tag **必须等于包内版本**(`v` + `package.json#version`),否则下游按 tag 拼版本化资产名会 404。
- Release 附**双资产**:固定名(供 `releases/latest/download/<fixed>.tgz` 长期入口)+ 版本化名(可追责)。
## 阶段 2:发布线 B — 无上游写权限 → fork 发布
```bash
gh repo fork <upstream-owner>/<repo> --clone=false # 已存在则复用
git remote add fork git@github.com:<me>/<repo>.git # 已存在则 git remote set-url fork …
git fetch --no-tags origin main
```
### 2.1 干净单提交 + 树一致性 gate(必做,不可省)
```bash
OURS=$(git rev-parse <本地完成发布内容的 HEAD>)
git checkout -B release/v<ver> origin/main
git rm -rq --cached .
git checkout "$OURS" -- .
git add -A
git commit -m "release: <name> v<ver>(REQ-…)…"
git diff --stat "$OURS" # 必须是空输出
```
- `git diff --stat "$OURS"` **非空即 abort**:切回原分支、删掉该发布分支、报告差异,不要「差一点也推」。
- 该 gate 的真实作用是:让公开发布分支的**树**等于本地验收树,同时**不携带本地历史提交**(个人路径、调试、凭据)。
- `git rm -rq --cached .` 只清索引,随后 `git checkout "$OURS" -- .` 覆盖工作树;若上游 `main` 存在本地树里**已删除**的
文件,残留文件会被 `git add -A` 重新加回导致 gate 失败——先确认 `git diff --name-status origin/main <OURS>` 无 `D`/`R`。
- 提交前可顺手确认没有敏感路径混入:`git log -S'<本机绝对路径前缀>' --oneline`。
### 2.2 推分支 + tag + 附双资产的 draft Release
```bash
git push -u fork release/v<ver>
git tag -f v<ver> && git push -f fork v<ver> # -f 只作用于 fork 的 tag
gh release create v<ver> dist/v<ver>/dsh-worktable.tgz dist/v<ver>/dsh-worktable-<ver>.tgz \
--repo <me>/<repo> --draft --title "<name> v<ver>" --notes-file <notes.md>
```
- 推完复核「原仓库零改动」:`git ls-remote <origin-url>`(应无新分支/tag)+ `gh release list --repo <upstream>`(列表应与之前一致)。
- Release notes 至少写:新增 / 修复 / 清理 / 验证(实际跑过的测试与数字)/ 安装命令(指向 fork)/ 包 SHA-256 / 已知边界。
## 阶段 3:改指向(换仓库、换发布方时)
只要「发布方」变了,插件里所有指向旧仓库的常量都要一次改全,否则**更新检查读的还是旧仓库 → 永远发现不了新版**:
- 更新检查仓库常量(如 `UPDATE_REPO`,可能有多份:入口 + 独立模块 + 设置面板各自实现);
- 升级命令/提示词里的安装 URL(可能拼在字符串里);
- `package.json#repository.url`;
- 发布后核对脚本里硬编码的 REPO;
- README/AGENTS/安装说明里的一行命令、`git clone` 地址、文档链接;
- 任何 `grep -rn "<旧 owner>"` 的残留。
规则:
- **只改指向,不改版本号与逻辑**;逐处 `git diff` 复核。
- 「相关项目/其它仓库」的外链如果指向**另一位开发者的独立仓库**,不要顺手改指(目标仓库不存在会变成死链)——保留并在交付里说明。
- **改完必须重新 pack**(铁律 3),解包 `grep` 确认产物内无旧仓库名,sha 与 Release 全部按新值重来。
## 阶段 4:draft → publish
```bash
gh release edit v<ver> --repo <me>/<repo> --draft=false
```
- **draft 期间 `releases/latest` 仍指向上一个已发布版本** → 插件内「检查更新」看不到新版本;
draft 资产的 tag 路径也不公开可下(需鉴权)。这是「更新检查不生效」最常见的**非 bug 原因**,先查 Release 是否还是 draft。
- 发布前用用户过目确认;发布后再跑阶段 5。
## 阶段 5:发布后核对
优先用仓库自带的核对脚本,但**平台适配要先判定**:`verify-remote.mjs` 之类脚本若用
`powershell Invoke-WebRequest` 下载,则**只在 Windows 可用**,在 macOS 会以 `FAIL: download fixed-name asset` 收场
(它的 GET URL 仍能证明改指生效,不代表脚本思路错)。
macOS/无 PowerShell 时的等价核对(全部要过):
```bash
gh release view v<ver> --repo <me>/<repo> --json assets # 两个资产的 digest 必须都等于本地 sha
gh release download v<ver> --repo <me>/<repo> --dir "$TMP" # draft 也可下载(已鉴权)
shasum -a 256 "$TMP"/*.tgz # 与本地验收 sha 逐字一致
cmp "$TMP/dsh-worktable.tgz" dist/v<ver>/dsh-worktable.tgz # byte-identical
tar -xzf "$TMP/dsh-worktable.tgz" -C "$TMP/ext" && grep -rn "<旧仓库名>" "$TMP/ext" # 无输出
curl -sL -o /dev/null -w '%{http_code}\n' <版本化资产 URL> # 发布后 200/302;draft 阶段 404 属预期
```
结论口径:**文件名 + 结构(精确文件清单)+ 包内版本 + 双资产同源 + 远端=本地验收 SHA + 真实安装导入** 全过才算发布验收。
draft 阶段只能做「远端资产 = 本地验收包」的比对,匿名可下载性要等 publish 后再验。
## 阶段 6:Slark 宿主补丁(宿主侧特有)
- **改 `app.asar` 无效**:Electron 用 `ElectronAsarIntegrity` 记录 asar 头哈希并有 fuse 完整性校验,直接热改会让
哈希失配,破坏签名,应用拒绝启动或行为异常。**必须重打包 + 重新安装**,不要在安装目录里就地改文件。
- 宿主补丁落在 fork/分支上时:rebase 到发布基线后**必须重跑全量测试**(类型检查 + 全量单测),
例如 `pnpm -r typecheck` 与 `node --import tsx --test "src/**/*.test.ts"`;rebase 不产生冲突**不代表语义没变**。
- 宿主发布与插件发布解耦:宿主要用新插件版本,通常靠宿主内嵌 runtime 的升级,而不是「插件先发、宿主自动跟进」。
## 网络与链路故障处置
| 现象 | 判定 | 处置 |
| --- | --- | --- |
| `curl` 访问 GitHub 返回 HTTP `000`(HTTPS 整体不通) | 出口到 github.com:443 被掐断,与凭据无关 | 改走 SSH:`git remote set-url origin git@github.com:<owner>/<repo>.git`,并确认 SSH 身份 |
| `git fetch` 长时间无输出/0 字节、卡十几分钟 | 链路假死,不是"慢" | 判死并清理后重试(见下方循环模板),不要原地等 |
| 30 秒内报 `fatal: early EOF` | 链路被中途掐断(代理/MTU/网络策略) | 记录原文与时间点;换协议/换网络重试;不要反复 force |
| macOS 没有 `timeout` 命令 | BSD 无 GNU timeout | 用后台 + 轮询模板 |
| `git push` 报无权限但 ls-remote 正常 | 只读凭据 | 直接走 fork 发布(阶段 2),不要重试上游 |
macOS 无 `timeout` 时的判死模板:
```bash
( git fetch --no-tags origin main ) & PID=$!
for i in $(seq 1 30); do sleep 1; kill -0 "$PID" 2>/dev/null || break; done
if kill -0 "$PID" 2>/dev/null; then kill -9 "$PID"; pkill -9 -f git-upload-pack; echo "TIMEOUT(30s) — 链路假死"; fi
```
- 认证/网络失败时**不做破坏性重试**(尤其不要为了"绕过"而 force 到上游);把失败原文、已完成的步骤、当前指针状态写清楚上报。
- 推送成功但平台上看不到:查 `git config --get-regexp '^url\.'` 是否有 `pushInsteadOf` 静默改写了目标。
## ai-proj 对齐
- 需求阶段:动手前立项(`create_requirement`,写清需求描述 / 预期结果 / 验收标准三段式 + AC),commit/PR 引用 `REQ-…`。
纯文档/工具/只读排查可例外。
- 交付阶段:**真实发布之后**才推进 `staging → released`;只有计划、没有发布产物或验收证据时不要推进。
- 归档阶段:`/req done` 归档前要**逐条 AC 证据**(命令、输出、资产 sha、URL),不能只写"已完成"。
- **文档接口故障绕过**:若 `append-document-content` / `create-and-attach` 持续报
`document_versions_document_id_version_number_key` 唯一约束错误(同一 `(document_id, version_number)` 冲突),
改用 `PUT /api/v1/requirements/{id}` 把说明写进**需求描述**——`requirements` 表不经过 `document_versions`,可绕开该约束;
不要伪造版本号或删除已有文档版本。
## 故障分流
| 现象 | 处置 |
| --- | --- |
| 插件「检查更新」永远看不到新版 | 依次查:Release 是否还是 draft;`releases/latest` 指向;插件内 `UPDATE_REPO` 是否仍指旧仓库;`latest` 资产名是否与代码拼的一致 |
| pack 报结构断言失败 | 包内混入了 `src/`、`.map` 或多余文件;检查 `files` 字段与构建产物位置,不要手改 tgz |
| 两个 tgz 的 sha 不一致 | 打包脚本的"同源复制"被绕过(手工 pack/改名);重新走唯一入口 |
| `git diff --stat <OURS>` 非空 | 上游 `main` 有本地已删除/重命名文件残留 → 先 `git rm --cached` 清理并确认无 `D`/`R`,gate 不过不上推 |
| 发布分支含个人路径/凭据 commit | 不要 push 该历史;改用干净单提交分支(阶段 2.1) |
| `gh release create` 报 tag 不存在/被占用 | tag 必须已存在或由 `create` 指定;draft 会以 `untagged-…` 预览 URL 呈现,属正常,publish 后即 `.../tags/v<ver>` |
| draft 资产匿名下载 404 | 预期行为(draft 需鉴权);发布后用 `curl -sL -o /dev/null -w '%{http_code}'` 复验 |
| 宿主改完不生效 | 是否只改了 `app.asar`(被完整性校验挡住);必须重打包重装;再查是否加载了另一份 runtime |
## 参考
- `references/fork-release-and-post-checks.md` —— fork 发布可复制命令序列、Release notes 模板、发布后核对矩阵。
- 同市场:`slark-cicd`(Slark staging/生产/Desktop)、`dev-cicd`(流水线设计)、`ai-proj-cicd-release`(AI-Proj 发布链)。
- 权威流程以目标仓库自带的发布脚本与文档为准;本技能是清单,不替代仓库脚本的断言。
@@ -0,0 +1,134 @@
# Fork 发布与发布后核对
本文件是 `slark-dsh-cicd` 的操作附件:需要**无上游写权限发布**,或需要**逐项核对远端资产**时读取。
把它当模板:替换 `<...>` 占位符,按阶段执行,每阶段的核验不通过就停下,不要"带病"推进。
## 0. 变量与前置
```bash
export HOME="/Users/johnq"
export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:/opt/homebrew/bin:$PATH"
UP=<upstream-owner>/<repo> # 例如 Aisland-SJL/dsh-worktable(外部作者,无写权限)
ME=<your-account> # 例如 qiudl
PKG=<repo>/01_content # 打包脚本所在目录
VER=0.4.1 # = package.json#version
```
```bash
gh auth status
ssh -T git@github.com 2>&1 | head -3
gh api "repos/$UP" --jq '.permissions' # push:false → 必须走 fork 发布
git remote -v
```
## 1. 改指向 → 重新打包(顺序不可颠倒)
```bash
cd "$PKG"
grep -rn "<upstream-owner>" .. --include='*.json' --include='*.ts' --include='*.tsx' --include='*.md' --include='*.mjs'
# 逐处改完之后再打包:
npm run check && npm run test:gate && npm run pack
shasum -a 256 dist/v$VER/*.tgz
TMP=$(mktemp -d) && tar -xzf dist/v$VER/dsh-worktable.tgz -C "$TMP"
grep -rn "<upstream-owner>" "$TMP" ; echo "grep exit=$? (1 = 无残留,正确)"
```
判据:`check`/`test:gate`/`pack` 全部 exit 0;两个 tgz 同 sha;解包无旧仓库名。
## 2. fork 与干净发布分支
```bash
cd <repo-root>
gh repo fork "$UP" --clone=false # 已存在会提示 already exists,可复用
git remote add fork "git@github.com:$ME/<repo>.git" # 已存在:git remote set-url fork …
git fetch --no-tags origin main
OURS=$(git rev-parse HEAD) # 本地"发布内容已就绪"的 HEAD
git diff --name-status origin/main "$OURS" | awk '$1 ~ /^[DR]/' # 期望空;有 D/R 先处理再用 gate
git checkout -B release/v$VER origin/main
git rm -rq --cached .
git checkout "$OURS" -- .
git add -A
git commit -m "release: <name> v$VER(REQ-…)<一句话说明>"
DIFFOUT="$(git diff --stat "$OURS")"
if [ -n "$DIFFOUT" ]; then
echo "GATE FAILED:"; echo "$DIFFOUT"
git checkout <原分支> && git branch -D release/v$VER # abort:不留半成品分支
exit 1
fi
echo "GATE PASSED: release tree == OURS tree"
```
## 3. 推送(只对 fork)与 draft Release
```bash
git push -u fork release/v$VER
git tag -f v$VER && git push -f fork v$VER # -f 仅限自己 fork 的 tag
gh release create v$VER \
dist/v$VER/dsh-worktable.tgz dist/v$VER/dsh-worktable-$VER.tgz \
--repo "$ME/<repo>" --draft --title "<name> v$VER" --notes-file /tmp/rel-notes.md
```
原仓库零改动复核:
```bash
git ls-remote "git@github.com:$UP.git" # 无 release/v… 分支、无新 tag
gh release list --repo "$UP" # 与发布前一致
```
### Release notes 模板(draft 阶段就写全新值)
```markdown
# <name> v<ver>
> 发布方:fork <ME>/<repo>(原仓库 <UP> 为上游来源)。插件内更新检查已指向本 fork。
## 新增 / 修复 / 清理
## 验证
- check / gate / pack 实际输出(测试条数、断言项)
- 双资产同 SHA:<sha256>
- 解包 grep 无旧仓库名
- 发布分支为干净单提交(父提交 = 上游 main),`git diff --stat <OURS>` 为空
## 安装
网页端 / 桌面端一行命令(指向 fork)
## 已知边界
- draft 期间 releases/latest 仍指旧版 → 更新检查看不到新版
- 保留的第三方外链、平台未验证范围
```
## 4. publish 与发布后核对矩阵
```bash
gh release edit v$VER --repo "$ME/<repo>" --draft=false
```
| 核对项 | 命令 | 通过判据 |
| --- | --- | --- |
| 资产列表与 digest | `gh release view v$VER --repo $ME/<repo> --json assets` | 两个资产 `digest` = 本地 sha |
| 下载后 sha | `gh release download v$VER --repo $ME/<repo> --dir "$D"` + `shasum -a 256 "$D"/*.tgz` | 与本地逐字一致 |
| 与本地验收件一致 | `cmp "$D/dsh-worktable.tgz" dist/v$VER/dsh-worktable.tgz` | 无差异(byte-identical) |
| 包内无旧仓库名 | 解包后 `grep -rn "<upstream-owner>"` | 无输出(exit 1) |
| 包内版本 = tag | 解包读 `package.json#version` | `v$VER` |
| 匿名可下载 | `curl -sL -o /dev/null -w '%{http_code}\n' <资产 URL>` | publish 后 200/302;draft 期 404 属预期 |
| 安装可用 | 临时目录 `npm install <tgz>` + `import()` 断言 | 导出/版本断言通过 |
- **`verify-remote.mjs` 的平台限制**:其下载走 `powershell Invoke-WebRequest`,只在 Windows 可用;
在 macOS 会 `FAIL: download fixed-name asset`。此时用上表的 `gh release view/download` + `shasum` + `cmp` 等价替代,
并说明该脚本的 GET URL 已证明改指生效。
- **"检查更新"看不到新版**的排查顺序:Release 是否 draft → `releases/latest` 指向 → 插件内 `UPDATE_REPO` 指向 →
`latest` 资产名与代码拼法一致。
## 5. 链路判死模板(macOS 无 `timeout`)
```bash
( git fetch --no-tags origin main ) & PID=$!
for i in $(seq 1 30); do sleep 1; kill -0 "$PID" 2>/dev/null || break; done
if kill -0 "$PID" 2>/dev/null; then kill -9 "$PID"; pkill -9 -f git-upload-pack; echo "TIMEOUT(30s)"; fi
```
- HTTPS 到 GitHub `curl` 返回 `000` → 整体不通,改 SSH(`git remote set-url`)。
- 30 秒内 `fatal: early EOF` → 链路被掐断;记录原文与时间,换网络/协议重试。
- 认证或网络失败时不做破坏性重试,也不要把 force 用到上游;保留本地提交并上报失败原文。
@@ -7,5 +7,6 @@
},
"install_name": "data-excel",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: data-excel
description: Excel 数据处理与 BI 集成。通过自然语言操作 Excel 文件的读取、编辑、转换,并支持导入到 BI 系统(Metabase)进行可视化分析。当用户提到 Excel、表格处理、数据导入、BI 分析相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# Excel 数据处理与 BI 集成 Skill
@@ -7,5 +7,6 @@
},
"install_name": "doubao-voice",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: doubao-voice
description: 豆包语音API调用。支持语音合成(TTS)和唱歌。当用户提到语音合成、文字转语音、唱歌、豆包语音相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 豆包语音API技能
@@ -7,5 +7,6 @@
},
"install_name": "feishu-bitable",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: feishu-bitable
description: 飞书多维表格操作。用于记录增删改查、批量操作、筛选排序、数据同步。当需要操作飞书多维表格时使用。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 飞书多维表格 (Bitable)
@@ -7,5 +7,6 @@
},
"install_name": "feishu-docx",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: feishu-docx
description: 飞书云文档操作。用于创建、编辑云文档,插入内容块,会议纪要生成。当需要操作飞书云文档时使用。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 飞书云文档 (Docx)
@@ -7,5 +7,6 @@
},
"install_name": "feishu",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: feishu
description: 飞书文档与多维表格操作入口。当用户提到飞书、云文档、多维表格、Bitable 相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 飞书集成
@@ -7,5 +7,6 @@
},
"install_name": "siyuan",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: siyuan
description: 思源笔记 API 集成。通过自然语言创建、编辑、搜索笔记,管理笔记本和文档树。当用户提到思源笔记、SiYuan、笔记管理、知识库相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 思源笔记 API 集成 Skill
@@ -7,5 +7,6 @@
},
"install_name": "siyuan-to-feishu",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: siyuan-to-feishu
description: 将思源笔记导出为 PDF 并发送到飞书群。当用户提到"发送笔记"、"导出PDF发飞书"、"/siyuan send"、"分享到飞书"相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# siyuan-to-feishu Skill
@@ -7,5 +7,6 @@
},
"install_name": "wecom",
"install_type": "skill",
"dir_category": "integration"
"dir_category": "integration",
"invocation": "user-invoked"
}
@@ -1,6 +1,9 @@
---
name: wecom
description: 企业微信集成。通过自然语言发送消息、管理群机器人、操作审批流程、管理通讯录。当用户提到企业微信、微信工作、群机器人、企业号、wecom相关任务时自动激活。
metadata:
invocation: user-invoked
disable-model-invocation: true
---
# 企业微信集成技能
@@ -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,再开自己。
+54
View File
@@ -322,6 +322,59 @@ npm run lint
---
## ⚠️ 既有契约与读模型迁移门禁(必须)
> **惨痛教训**:新写链路把真实数据写入新表,旧 API 仍读原表,前端虽然没改却从此看不到新数据。“后端已成功执行”不等于“用户能看到执行结果”。
开发计划涉及新表、新账本、新写路径、替换存储模型或接口版本时,必须先完成以下门禁。未通过时,不得把“新建平行表/新建平行 API”写成默认方案。
### 1. 先证明旧模型不能复用
- [ ] 已检查现有表、字段、索引、状态机和扩展字段(如 metadata/JSON)。
- [ ] 已说明为什么增加字段、子表或现有类型无法满足需求。
- [ ] 新表承载的是真正独立的实体或生命周期,而不是为同一业务实体建立第二个彼此脱节的世界。
- [ ] 已区分“内部不可变证据/事件账本”和“产品对外读模型”;新建内部账本不代表必须更换原有产品接口。
### 2. 真实调用方查证
必须从对外接口向所有消费方反向追踪,不能只审查新后端写路径:
- [ ] 列出现有 API 路径、请求参数、响应结构和身份/分页语义。
- [ ] 使用 `rg` 查找 Web、iOS、Android、定时任务、报表和第三方调用方。
- [ ] 若仓库存在 `.codex-fe-ref/`,必须在其中查证配套前端的真实调用。
- [ ] 开发计划的变更文件清单必须覆盖“写入 → 投影/查询 → API → 页面”完整链路。
### 3. 稳定契约默认不变
- 既有用户界面已消费的 API,默认保留路径和响应契约;除非用户明确批准破坏性迁移,不得通过新建版本接口把兼容成本转嫁给前端。
- 同一业务概念只保留一个产品级读模型。内部账本可以拆分,但必须投影回既有读模型,或由原 API 无感聚合。
- 日志、告警、信号或推测数据不得在查询降级时冒充业务事实(例如把 warning 当成交易记录)。
### 4. 不可避免新写模型时的强制迁移计划
若确有独立生命周期、不可变审计或 1:N/N:N 证据需求,可以增加新表,但开发计划必须同时包含:
1. **写入兼容**:双写,或从新账本向既有读模型做事务性/幂等投影。
2. **历史回填**:有界、可恢复、可重跑,且不猜测无法证明的归属。
3. **去重身份**:定义跨旧/新数据源的稳定业务键,并用数据库唯一约束或等价强保证防重。
4. **读取切换**:定义何时以新证据为准、旧数据如何兼容,以及结果数量/金额/状态对账门槛。
5. **回滚策略**:回滚新写入时仍能读取已产生的真实业务事实,不删除或隐藏已成功数据。
6. **可观测性**:监控新写入成功但旧读模型缺失、投影延迟、去重冲突和回填差异。
### 5. 用户可见性是必须验收项
测试不得只证明“新写路径成功”。至少要有一个真实业务记录贯穿测试,同时证明:
- [ ] 新写路径产生了正确事实。
- [ ] 原有对外 API 可以立即或在约定 SLA 内返回该记录。
- [ ] 每个真实消费页面/客户端都能正确解码并展示。
- [ ] 时间、方向、状态、数量、金额与唯一标识在数据库、API 和 UI 之间一致。
- [ ] 部分失败、重试、重复投递、迟到数据和回滚后仍不丢数、不重复、不冒充。
开发计划必须把上述内容落成明确的变更文件、任务、测试用例和发布门禁,不得只在“风险”章节留一句提醒。
---
## 开发计划文档模板
```markdown
@@ -1695,3 +1748,4 @@ migrate -path migrations -database "postgres://..." up
|------|------|----------|--------|
| V1.0 | 2026-01-26 | 初始版本,创建 req-dev 技能 | Claude + qiudl |
| V1.1 | 2026-01-29 | 添加 iOS 端开发规范(SwiftUI + MVVM 架构) | Claude Opus 4.5 |
| V1.2 | 2026-08-26 | 新增既有契约与读模型迁移强制门禁,防止新写链路与原 API/前端脱节 | Codex |
@@ -1,7 +1,7 @@
{
"name": "req-plugin",
"description": "需求工作流管理入口。用于 /req 命令使用、需求生命周期管理、需求撰写(含草稿门禁)。",
"version": "2.0.0",
"version": "2.1.0",
"author": {
"name": "qiudl"
},
+5 -2
View File
@@ -48,6 +48,7 @@ analysis → design → dev → review → testing → [待部署池] → releas
- **操作前先确认实际 ID** — 从 URL 提取 ID(如 `/requirements/897` → ID=897)
- **务实路线关闭也必须补全关联任务** — 每个进度条阶段需创建关联任务
- **阶段内容门禁(防空转)** — `/req next` 时检查关键阶段任务是否有实质内容
- **复用盘点先于估工(Gate 5,强制)** — PRD 必须含「现有实现与复用盘点」章节:每个能力点给出**现有实现(file:line)+ 结论(复用 / 改造 / 新增)**;结论=复用/改造的只按「接入差异」估工,结论=新增的必须写「为什么现有实现不能满足」。没有 file:line 证据、或标「未排查」的,**禁止 submit、禁止按全新增估工**;独立复查由非 PRD 写作者用 grep 复核并在 note 留命令与命中结果
- **Harness 环境检测** — `/req dev` 启动开发前,快速检测项目基础设施(`.husky/` 存在?`scripts/check-*.sh` 存在?)。若两者都不存在(Level 0),输出一行提示:「项目无质量护栏,建议先运行 `/harness init`」。检测结果不阻塞开发,仅提示
## 禁止直接调用(必须走命令流程)
@@ -55,7 +56,7 @@ analysis → design → dev → review → testing → [待部署池] → releas
| 禁止直接调用 | 必须通过 | 原因 |
|-------------|---------|------|
| `ai-proj req create` with allowSelfApprove | `/req new` | 禁止自动提交,必须创建为 draft |
| `ai-proj req submit` (直接调用) | `/req submit` | 必须先通过 4 道门禁检查 |
| `ai-proj req submit` (直接调用) | `/req submit` | 必须先通过 5 道门禁检查 |
| `ai-proj req archive` | `/req done` | 必须先执行类型化门禁检查 |
| `ai-proj req approve` | `/req review pass` | 必须先展示 PRD 摘要并等待用户确认 |
| `ai-proj req advance --to <stage>` (force) | `/req next` | 必须先 AskUserQuestion 确认 + 记录跳过原因 |
@@ -73,13 +74,15 @@ ai-proj req create \
# → 结果必定是 draft 状态
```
### 从 draft 到 submit 的 4 道门禁
### 从 draft 到 submit 的 5 道门禁
```
Gate 1: 需求讨论 ── description 末尾有「## 讨论结论」章节
Gate 2: 方案确认 ── AskUserQuestion 获得「方案确认通过」
Gate 3: PRD 文档 ── linkRole=prd 的任务存在且有文档
Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD 存在
Gate 5: 复用盘点 ── PRD 有「现有实现与复用盘点」章节;每条能力点有 file:line 证据
或「为什么不能复用」的理由;估工按 复用/改造/新增 分别计(无盘点 = 阻断)
```
## 完整工作流
@@ -1,7 +1,7 @@
{
"name": "req-prd-plugin",
"description": "产品需求设计技能。覆盖问答访谈、PRD、缺陷收敛及 HTML 原型验证闭环。纯产品视角,不含技术实现。",
"version": "2.1.0",
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
"version": "2.3.0",
"author": {
"name": "qiudl"
},
+54 -3
View File
@@ -1,6 +1,6 @@
---
name: req-prd
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
description: 产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。
---
# 产品需求设计 Skill (req-prd)
@@ -19,6 +19,36 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
- `req-prototype` — UI 模块在 PRD/缺陷收敛后生成、上传并关联 HTML 原型
- `defect-analysis` — 设计访谈确认后,对最新版 PRD 反复审计和修订直至收敛
## 产品需求文档双写门禁
本技能创建或修改的所有正式需求文档都必须同时保存到:
1. 当前产品仓库的本地 Markdown 文件;
2. Requirement 对应角色任务的 ai-proj Task Document。
适用文档至少包括原始诉求/讨论记录、PRD、缺陷优化记录、原型版本与评审记录。Requirement description 只保存已确认的讨论摘要,不能替代 Task Document。
### 路径与任务映射
优先遵循仓库已有文档目录和命名约定;没有约定时使用:
| 文档 | 本地默认路径 | ai-proj 任务角色 |
|------|--------------|------------------|
| 需求讨论记录 | `docs/product/{REQ-ID}-{slug}-discussion.md` | `documentation` |
| PRD(含缺陷修订和原型回填) | `docs/product/{REQ-ID}-{slug}-prd.md` | `prd` |
同一 Requirement、同一角色只维护一个当前任务文档。不得把本地文件路径当成 ai-proj 持久化,也不得只把远程 Task Document 导出一次后继续单边修改。
### 每次写入协议
1. 修改前同时读取本地文件与 ai-proj Task Document;任一不存在则基于另一份初始化,二者都不存在才新建空模板;
2. 若两份内容不一致,比较文档 ID、版本、更新时间和内容摘要,保留双方未知内容并显式合并;无法安全合并时停止并请用户选择,禁止静默覆盖;
3. 先用安全文件编辑方式写入本地 Markdown,再创建或更新对应 Task Document;
4. 写后重新读取两端,计算或比较内容摘要,确认正文一致,并记录本地路径、task_id、document_id、version/updated_at;
5. 任一端写入或复读失败都属于未完成的部分写入:保留已成功一端用于恢复,立即报告并停止后续阶段,不得宣称“已保存”“已收敛”或提交评审。
问答每一轮、每次 PRD 修订、每轮 defect 处置和每次原型回填都执行该协议;不能等到流程结束再一次性补传。
## 模块设计访谈模式
设计模块、系统、跨域流程,或目标/边界/业务规则尚未确定时,必须先执行问答式设计访谈,不得直接补全假设后生成 PRD。用户明确要求“你问我答”时也进入此模式。范围小、规则已完整确认的需求可以直接编写 PRD。
@@ -41,8 +71,8 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
1. 原型基于最新版、已完成缺陷收敛的 PRD,并记录 PRD 文档标识、版本或内容摘要;
2. 覆盖核心入口、主流程以及 PRD 明确要求的空态、失败态、无权限态和确认/撤销反馈;
3. 上传后重新读取 Requirement,确认原型 URL/版本已关联,并验证 URL 可访问、iframe 可展示、核心交互可操作;
4. 将 iframe、原型版本、版本说明和验证结果回填 PRD `4.2 界面原型`,并把生成、反馈、修订和确认写入同一讨论文档;
3. 将本地 HTML 源文件通过 ai-proj 上传到 OSS;上传后重新读取 Requirement,确认 OSS URL/版本已关联,并验证 URL 可访问、iframe 可展示、核心交互可操作;
4. 将 iframe、原型版本、版本说明和验证结果双写到本地 PRD 与 prd 角色 Task Document,并把生成、反馈、修订和确认双写到本地讨论记录与 documentation 任务文档;
5. 用户明确确认最终 PRD 与原型表达的是同一方案。
纯后端、批处理、基础设施等确实没有用户界面的模块可以跳过,但必须在讨论文档和 PRD `4.2` 中记录“无 UI,原型不适用”的理由及用户确认,不得静默省略。
@@ -107,6 +137,21 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
- 会议/邮件/聊天记录链接
- 客户特殊约束(如"必须在 Q2 前上线")
### 1.5 现有实现与复用盘点 ⭐ 强制
> **目的**:防止把「已经有的能力」当成新增来估工和开发(真实事故:DS Bot 早已有头像上传/裁剪功能,PRD 仍按新建估工)。
> **检索证据**:每条都要给 `file:line`(或 grep 命令 + 命中结果),不接受「凭印象认为没有」。
| 能力点 | 现有实现(file:line) | 结论 | 说明 |
|--------|----------------------|------|------|
| 头像上传/裁剪 | `ds-bot/src/client/bot-settings.js:xx` | 复用 | 只改存储落点与主体 |
| …(本次涉及的每个能力点都要有一行) | | | |
**硬规则**:
- 结论是 **复用 / 改造** 的,估工只算「接入差异」,不许按全新功能算。
- 结论是 **新增** 的,必须写「为什么现有实现不能满足」。
- 标「未排查」或没有 `file:line` 的 PRD **不得提交评审**;独立复查人(非 PRD 作者)要用 grep 复核并在 note 留证据。
## 2. 用户分析
### 2.1 目标用户
[用户画像描述]
@@ -401,6 +446,8 @@ mcp__ai-proj__link_tasks_to_requirement
### 文档管理
以下 MCP 操作只完成 ai-proj 侧写入;每次调用前后都必须按“产品需求文档双写门禁”同步并校验本地 Markdown。
```bash
# 创建 PRD 文档并关联任务
mcp__ai-proj__create-and-attach
@@ -418,6 +465,8 @@ mcp__ai-proj__export_task_document_to_file
- taskId: 任务ID
```
导出命令不能代替双写校验:导出后仍需确认目标路径符合仓库约定、正文与 Task Document 当前版本一致,且没有覆盖本地新增内容。
---
## 功能设计流程
@@ -561,6 +610,8 @@ UI 模块还必须核对最终 HTML 原型与最新版 PRD 一致,并取得用
### PRD 完整性检查
- [ ] 模块/系统设计已完成单轮单问访谈,且全过程已写入 ai-proj 讨论文档
- [ ] 讨论记录与 PRD 均已保存到仓库本地 Markdown 和对应 ai-proj Task Document
- [ ] 两端复读正文一致,交付说明包含本地路径、task/document 标识和远程版本
- [ ] 讨论结论已由用户明确确认
- [ ] `defect-analysis` 已基于最新版 PRD 收敛到一轮 0 个新缺陷
- [ ] 无未处置的致命/高严重度缺陷
@@ -28,6 +28,7 @@
- 任务标题:`【讨论】需求讨论: {需求标题}`
- 文档标题:`{REQ-ID} 需求讨论记录`
- 本地文件:优先使用仓库约定;默认 `docs/product/{REQ-ID}-{slug}-discussion.md`
- 一个 Requirement 只维护一个当前讨论文档,不因会话中断重复创建。
查找时同时核对 Requirement 关联关系、任务角色和标题,不能只按相似标题猜测。发现多个候选讨论文档时,列出标识和最近更新时间,请用户指定或授权合并;在此之前不得静默选择其中一个继续写入。
@@ -38,7 +39,15 @@
若尚未指定 Requirement,先请用户提供已有 Requirement,或明确授权创建。取得 Requirement 和讨论文档前不得开始声称“已留痕”的正式访谈;不得仅为执行本技能本身擅自创建 Requirement。用户明确要求“创建需求并设计”才构成创建授权。
每次恢复会话时,先读取 Requirement、现有 PRD 和讨论文档,从最后一个未决问题继续。讨论文档是跨会话、上下文压缩后的权威记录;模型记忆不能覆盖文档中的用户原话和已确认决策。
每次恢复会话时,先读取 Requirement、现有 PRD,以及讨论记录/PRD 的本地文件和 ai-proj Task Document,从最后一个未决问题继续。两端持久化内容必须一致;模型记忆不能覆盖文档中的用户原话和已确认决策。
### 本地与 ai-proj 双写
- 讨论记录和 PRD 的每次新增或修订,都必须同步到仓库本地 Markdown 与对应 ai-proj Task Document;本地文件用于代码库评审和版本控制,Task Document 用于需求关联、跨会话恢复和团队查看。
- 修改前读取两端。内容不一致时按版本、更新时间和摘要显式合并,保留双方未知内容;不能判断时停止并请用户选择,禁止以任一旧副本覆盖另一端。
- 每轮问答按顺序完成:更新本地讨论文件 → 更新 documentation 任务文档 → 复读两端并核对正文/摘要 → 再向用户提出下一问。
- 每次 PRD/defect/原型回填按同样协议更新本地 PRD 文件和 prd 任务文档。默认本地路径为 `docs/product/{REQ-ID}-{slug}-prd.md`,已有项目约定优先。
- 任一端失败时记录“部分写入”及成功端的路径/标识,停止后续流程。恢复时从成功端与失败前最后版本合并,禁止重复追加同一 Q/Round/Prototype 编号。
### 写入纪律
@@ -49,7 +58,7 @@
- 用户原话逐字保留在引用块中;AI 的解释、推论和建议必须分栏,不能伪装成用户决定。访问令牌、密码、私钥及依法需要保护的个人敏感信息不得落库,用 `[敏感信息已脱敏]` 替代并注明脱敏原因。
- 文档以追加式记录为主。状态为“待回答”的问题块可以在收到回答后原位补全一次;变为“已确认”后不得静默改写。纠正已确认结论时追加“决策变更”,并引用被替代的编号。
- 更新整篇文档前重新读取最新版并保留未知内容;若读取后文档又发生变化,基于最新版合并后重试,不能用旧副本覆盖其他会话的记录。
- 写入后读取文档确认本轮编号和正文存在。写入或校验失败时立即报告,停止进入下一轮,且不得声称“已记录”。
- 写入后读取本地文件和 ai-proj Task Document,确认本轮编号、正文和内容摘要一致。任一写入或校验失败时立即报告,停止进入下一轮,且不得声称“已记录”。
- Requirement 描述只同步用户确认后的“讨论结论”摘要;完整过程保留在讨论文档中。
## 3. 单轮单问访谈
@@ -155,9 +164,9 @@ PRD 包含页面、表单、列表、可视状态、用户操作或跨页面流
### 6.3 上传、关联、回填与验证
1. 通过 `upload_prototype` 上传 HTML,并记录 Requirement 数字 ID、原型 URL、版本说明和上传时间;
2. 重新读取 Requirement,确认返回的原型 URL/版本确实已关联。仅拿到上传成功响应不足以通过;
3. 将 iframe、PRD 基线、原型版本、版本说明和验证结果回填 PRD `4.2 界面原型`;
1. 将 HTML 源文件保存到仓库约定目录(默认 `docs/prototypes/`),再通过 `upload_prototype` 上传到 ai-proj 配置的 OSS,并记录 Requirement 数字 ID、OSS URL、版本说明和上传时间;
2. 重新读取 Requirement,确认返回的 OSS URL/版本确实已关联。仅有本地文件或上传成功响应不足以通过;
3. 将 iframe、PRD 基线、原型版本、版本说明和验证结果同时回填本地 PRD 与 prd 角色 Task Document;
4. 用浏览器或等价方式验证 URL 可访问、iframe 可展示、核心导航和交互可操作、关键状态可识别。使用临时浏览器时按环境规则关闭;
5. 将生成输入、上传结果、验证证据和待确认差异写入讨论文档。任何写入或验证失败都必须停止,不得声称原型已完成。
@@ -236,7 +245,9 @@ PRD 包含页面、表单、列表、可视状态、用户操作或跨页面流
- ai-proj Requirement 标识;
- 讨论任务/文档标识;
- 讨论记录本地路径及双写一致性状态;
- PRD 任务/文档标识;
- PRD 本地路径及双写一致性状态;
- 问答轮数、缺陷审计轮数和收敛轮;
- HTML 原型版本、URL、Requirement 关联与验证状态;无 UI 时给出跳过理由和用户确认;
- 仍被接受的中/低风险;
@@ -1,7 +1,7 @@
{
"name": "req-prototype-plugin",
"description": "原型生成与关联。支持 HTML 正式交付、Requirement 关联、iframe 验证闭环及 Stitch AI 视觉探索。",
"version": "2.1.0",
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
"version": "2.2.0",
"author": {
"name": "qiudl"
},
+29 -15
View File
@@ -1,6 +1,6 @@
---
name: req-prototype
description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 PRD 自动生成 UI 原型截图;(2) AI 编写 HTML 原型并上传关联到需求详情页 iframe。当执行 /req prototype 或需要生成/上传界面原型时使用。
description: 原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。
---
# 原型设计 Skill (req-prototype)
@@ -13,7 +13,7 @@ description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 P
| 模式 | 命令 | 适用场景 | 输出 |
|------|------|----------|------|
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 可交互 HTML + Requirement 关联 + PRD iframe |
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 本地 HTML 源文件 + OSS URL + Requirement 关联 + PRD iframe |
| **Stitch AI** | `/req prototype` | 精细 UI 视觉探索、多屏草图 | 截图回填 PRD,后续仍需转为 HTML 正式原型 |
## 前置条件
@@ -27,6 +27,17 @@ description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 P
| PRD 已完成 defect 收敛(正式 HTML 模式) | 读取讨论文档的收敛轮和最新版 PRD 标识 | 报错:先完成 req-prd/defect-analysis 收敛 |
| UI 原型适用 | PRD 含页面、操作流程或可视状态 | 无 UI 时记录不适用理由与用户确认,不生成空壳原型 |
## HTML 原型持久化门禁
正式 HTML 原型必须上传到 ai-proj 配置的 OSS(对象存储),并以 OSS HTTPS URL 关联 Requirement。仅生成本地文件、`file://` URL、临时 HTTP 服务或聊天附件都不算完成。
- 本地源文件优先遵循仓库约定;默认保存为 `docs/prototypes/{REQ-ID}-{slug}-v{N}.html`,纳入版本控制。
- OSS 上传必须通过 `mcp__ai-proj__upload_prototype` 或 ai-proj 提供的等价正式接口完成,禁止绕过 Requirement 关联自行上传后只粘贴 URL。
- `/tmp` 只能存放编码或校验过程中的临时副本,不能作为原型交付位置。
- 上传后必须复读 Requirement,确认 `prototype_urls`/版本记录指向本次 OSS URL;再验证 URL 可访问、响应为 `text/html` 且可内联展示。
- OSS 地址必须由 ai-proj 长期管理,不能把短期预签名 URL 写入 PRD;访问控制与 iframe 策略由 ai-proj 统一提供。
- 原型元数据和 iframe 回填属于 PRD 修订,必须同时更新本地 PRD Markdown 与 prd 角色 Task Document,并复读校验一致。
## 子命令
### 0. `/req prototype upload [REQ-ID] [--note "版本说明"]` — 上传 HTML 原型(**推荐**)
@@ -40,24 +51,24 @@ description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 P
2. 完整读取最新版 PRD,记录任务/文档 ID、版本、更新时间和内容摘要或哈希;正式交付还要核对 defect 收敛轮
3. 从 PRD 提取页面清单、角色入口、主流程、关键状态和验收条件,形成覆盖矩阵
4. AI 编写带完整样式和必要原生交互的独立 HTML 原型文件(见设计规范)
5. 保存到 /tmp/proto_<req_id>_<timestamp>.html,并在本地做结构、大小和敏感信息检查
6. Base64 编码:base64 < /tmp/proto_<req_id>_<timestamp>.html
7. 调用 mcp__ai-proj__upload_prototype 上传(传入 requirementId + base64 content)
8. 重新读取 Requirement,确认原型 URL/版本已关联;不得只相信上传响应
9. 将 iframe、PRD 基线、原型版本/说明和验证状态回填 PRD「4.2 界面原型」
5. 保存到仓库原型目录(默认 docs/prototypes/<REQ-ID>-<slug>-v<N>.html),并做结构、大小和敏感信息检查
6. 从本地源文件 Base64 编码;如工具需要,可在 /tmp 创建临时编码副本
7. 调用 mcp__ai-proj__upload_prototype 上传到 OSS(传入 requirementId + base64 content)
8. 重新读取 Requirement,确认 OSS URL/版本已关联;不得只相信上传响应
9. 将 iframe、PRD 基线、原型版本/说明和验证状态双写到本地 PRD 与 prd 角色 Task Document
10. 打开最终 URL 或需求详情页,验证 iframe 展示和核心交互;记录证据后关闭临时浏览器
11. 将生成、关联、验证、用户反馈和版本状态写入同一讨论文档
11. 将生成、关联、验证、用户反馈和版本状态双写到本地讨论记录与 documentation 角色 Task Document
```
**Step 5-6 执行方式**:
**Step 6-7 执行方式**:
```bash
# 5. Base64 编码 HTML 文件
B64=$(base64 < /tmp/proto_<req_id>_<timestamp>.html)
# 6. Base64 编码本地 HTML 源文件
B64=$(base64 < docs/prototypes/<REQ-ID>-<slug>-v<N>.html)
```
```
# 6. 通过 MCP 工具上传(无需本地后端)
# 7. 通过 MCP 工具上传到 OSS(无需本地后端)
mcp__ai-proj__upload_prototype(
requirementId = <需求数字ID>,
content = <B64 字符串>,
@@ -72,7 +83,7 @@ mcp__ai-proj__upload_prototype(
"success": true,
"message": "原型已上传并关联到需求 <id>(version=N/A)",
"data": {
"url": "https://ai-proj-1252326374.cos.ap-beijing.myqcloud.com/prototypes/<uuid>.html",
"url": "https://<ai-proj-oss-domain>/prototypes/<uuid>.html",
"versionNote": "...",
"uploadedAt": "...",
"requirementId": <id>
@@ -80,7 +91,7 @@ mcp__ai-proj__upload_prototype(
}
```
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 COS 上的 HTML 文件。**无需本地后端运行**。
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 OSS 上的 HTML 文件。**无需本地后端运行**。OSS 的具体厂商和域名由 ai-proj 服务配置,技能不得硬编码 COS、S3 或其他厂商地址。
**参数**:
@@ -183,6 +194,9 @@ AI 生成的 HTML 原型必须满足以下要求:
#### HTML 上传后验证清单
- [ ] 上传响应成功且 Requirement 复读能看到同一 URL/版本
- [ ] URL 为 ai-proj 返回的持久化 OSS HTTPS 地址,不是本地或临时地址
- [ ] URL 不是短期预签名地址,响应 `Content-Type` 为 `text/html` 且不会强制下载
- [ ] 仓库中保留与该 OSS 版本对应的 HTML 源文件
- [ ] 原型 URL 返回可展示的 HTML,不是下载错误页、登录页或 404
- [ ] 需求详情页使用 iframe 展示,没有降级为截图或图片
- [ ] 核心入口、主流程和覆盖矩阵中的关键状态可识别/可操作
@@ -327,7 +341,7 @@ generated_at: "<timestamp>"
| 异常 | 处理 |
|------|------|
| `mcp__ai-proj__upload_prototype` 返回失败 | 检查 requirementId 是否为数字 ID(非 display_id REQ-xxx) |
| `mcp__ai-proj__upload_prototype` 返回失败 | 检查 requirementId 是否为数字 ID(非 display_id REQ-xxx);不得降级为只留本地文件 |
| HTML 文件超过 5MB | 精简样式或拆分多版本上传 |
| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 |
| base64 命令失败 | macOS 用 `base64 < file`,Linux 用 `base64 -w 0 < file` |
@@ -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": "deprecated",
"invocation": "model-invoked"
}
@@ -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` 并说明「还差哪项验证」。
@@ -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 及原因,不得声称全部通过"
}
]
}
+3
View File
@@ -42,6 +42,9 @@ description: Installer fixture version two.
---
version two
EOF
# Reproduce rsync's quick-check edge case: changed content with identical size
# and mtime must still replace the recorded, unmodified installation.
touch -r "$TEST_HOME/.agents/skills/example/SKILL.md" "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
grep -q 'version two' "$TEST_HOME/.agents/skills/example/SKILL.md"
grep -q '"version": "2.0.0"' "$TEST_HOME/.agents/.ai-proj-helper-installed-skills.json"
+1
View File
@@ -49,6 +49,7 @@ PLUGIN_MAP = {
"karpathy-guidelines-plugin": ("karpathy-guidelines", "skill", "dev"),
"pull-request-plugin": ("pull-request", "skill", "dev"),
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
"slark-dsh-cicd-plugin": ("slark-dsh-cicd", "skill", "dev"),
# skills-integration
"data-excel-plugin": ("data-excel", "skill", "integration"),