Author SHA1 Message Date
qiudl 8fc1cd05b7 feat(req-prd): add HTML prototype delivery loop 2026-08-21 23:48:43 +09:30
admin b859a84455 Merge PR #6: req-prd design interview and defect convergence
Adds traceable one-question-per-round product design interviews and a defect-analysis convergence loop.
2026-08-21 13:05:55 +00:00
qiudl 9a1400758e feat(req-prd): add design interview and defect convergence workflow 2026-08-21 22:34:09 +09:30
qiudl a58dd1aff3 Merge PR #5: make Codex the default skill target
Validated Codex and explicit Claude install layouts, stable content digests, exclusions, and real user-scope installation.
2026-08-20 02:37:34 +00:00
qiudl bb5e6be73e feat(skills): make Codex the default install target 2026-08-20 12:07:10 +09:30
qiudl ef0e9ca1f0 Merge PR #4: refresh marketplace release workflows
Validated installer migration, marketplace integrity, skill frontmatter, plugin manifests, and sanitized release skills.
2026-08-20 01:45:40 +00:00
qiudl ad4e2b16a8 feat(skills): refresh marketplace release workflows 2026-08-20 10:34:16 +09:30
qiudlandClaude Sonnet 4.6 ba107a54a8 fix(req-prototype): fix arguments regex causing Skill loader error
arguments 字段中 [REQ-ID] 被 Skill loader 编译为 JS regex 时,
Q-I 字符范围(ASCII 81 > 73)触发 "range out of order" 错误。
改为 <REQ-ID> [subcommand] [options] 避免字符类范围问题。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 13:55:55 +09:30
qiudl 4ea6920a13 chore(marketplace): update marketplace.json — req-prototype upload 改用 MCP 直传 COS 2026-05-17 13:36:54 +09:30
qiudlandClaude Sonnet 4.6 039a749e3e feat(req-prototype): upload 模式改用 MCP upload_prototype 直传 COS
- 移除对本地后端(localhost:8080)的依赖
- 执行流程改为:生成 HTML → base64 编码 → mcp__ai-proj__upload_prototype
- 删除前置条件中「后端运行中」检查项
- 更新异常处理:移除 token/后端错误,新增 base64 兼容性说明

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:52:28 +09:30
qiudlandClaude Sonnet 4.6 daca19a262 chore(marketplace): req-plugin 归档前强制 AC 验收 Gate 0
- /req done 新增 Gate 0:归档前逐条确认验收标准
- 无 AC 或有未确认项均阻断,需提供证据或说明 N/A 原因
- AC 确认后自动追加验证记录到需求描述(带日期戳)
- 更新关键约束说明

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 08:20:38 +09:30
qiudl ddb5d5cb06 chore(marketplace): remove stale skills-personal entries
skills-personal/ directory no longer exists; marketplace.json had 9
plugin entries pointing to missing sources (gitea, openclaw,
ops-servers, ops-tools, qiudl-personal, reload-session, req-deploy,
save-session, search-sessions). Regenerated via generate-marketplace.py.
2026-05-07 02:40:47 +02:00
qiudlandClaude Sonnet 4.6 da57cccf96 chore(marketplace): update req-retro karpathy-score dimension, req-test-gate gate-0b docs
- req-retro: 新增 karpathy_score × 0.20 维度,QS 公式扩展为 5 维
- req-test-gate: Gate 0B 新增 check-surgical.sh Ratchet 文档

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 10:55:13 +09:30
qiudl 7eed2b8f10 chore(marketplace): add karpathy-guidelines-plugin, update dev-coding/dev-review/review-checklist
Karpathy 四原则融合到 req 技能工作流 (REQ-20260421-0003):
- dev-coding: 新增 Step 0「验证优先」(Goal-Driven Execution)
- dev-review: 五视角 → 六视角,新增 Scope 审计者 (Simplicity + Surgical)
- review-checklist/general: 新增 Karpathy 反模式速查表
- karpathy-guidelines-plugin: 新增独立插件,含四原则全文 + 与 req 工作流映射
2026-04-21 10:08:18 +09:30
qiudl 5a45916b2c feat: devflow-claude P0/P1 集成 + VP 三件套强制规则 2026-04-20 23:51:03 +00:00
qiudl bcea648e3c merge: resolve conflict in req-prototype SKILL.md, keep iframe display rule from main 2026-04-21 09:20:55 +09:30
qiudlandClaude Sonnet 4.6 e3513f137b feat(req-prd): PRD 模板新增验收标准章节强制含 VP 三件套(REQ-20260421-0002)
- 模板第7节新增「验收标准」章节,含 VP-Data/VP-Steps/VP-Pass 完整示例
- 检查清单「验收标准可测试」更新说明要求 VP 三件套
- 原第7节「风险评估」顺移为第8节

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:19:08 +09:30
qiudlandClaude Sonnet 4.6 011916ceb9 feat(req-review): 新增 VP 三件套强制检查(REQ-20260421-0002)
- 结构检查表新增「VP 三件套」必须项
- 新增「VP 三件套强制检查」章节,含四项检查指标和驳回条件
- 常见驳回原因更新:验收不明包含 VP 缺失场景

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:17:11 +09:30
dongliangandClaude Sonnet 4.6 48b792fb5a feat(req-prototype): 原型展示必须用 iframe,禁止图片方式 (REQ-20260420-0031)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 01:07:10 +09:30
qiudlandClaude Sonnet 4.6 2ab0a61eb9 fix(install): handle nested skills/ subdirectory (e.g. dev-test)
resolve_skills_src() detects when SKILL.md is one level deeper than skills/
and uses that subdirectory as rsync source instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 00:00:01 +09:30
qiudlandClaude Sonnet 4.6 de25f096e7 feat(sync): add install-skills.sh + install metadata to all 62 plugins
- Add install_name, install_type, dir_category fields to all 62 plugin.json files
  to resolve name-mapping and skill-vs-command routing issues
- Add install-skills.sh: idempotent cross-machine skill sync script
  - Routes skill→~/.claude/skills/<name>/, command→~/.claude/commands/<name>.md
  - rsync full skills/ directory (preserves multi-file skills like dev-test, req-deploy)
  - State file ~/.claude/.installed-skills.json tracks installed versions
  - Conflict detection: warns before overwriting locally modified files
  - --dry-run, --category, --force, --cleanup, --list flags
- Add 9 new plugins migrated from local ~/.claude (agent-swarm, ai-chat,
  defect-analysis, executing-plans, finishing-branch, frontend-design,
  req-audit, req-lookback, req-retro)
- Add update-plugin-meta.py helper used to bulk-update plugin.json
- Fix siyuan SKILL.md: remove hardcoded server credentials, use env vars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 23:55:26 +09:30
qiudlandClaude Sonnet 4.6 84d4e35a42 feat(req-prototype): 新增 HTML 上传模式,版本升至 v2.0.0
- 添加 /req prototype upload 子命令(推荐模式)
- 含完整 curl 上传流程、HTML 设计规范及模板
- 更新错误处理与版本管理说明
- marketplace 更新(49 个插件)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 18:06:32 +09:30
qiudl e5805cbb51 feat: P1-10/12/13/14 风险扫描 + 粒度判断 + Issue 集成 + PRD 校验 (REQ-20260416-0017)
P1-10: pm-risk skill — 三维度风险扫描
  需求层: 停滞/草稿滞留/开发无提交/测试超期/批准未开发
  代码层: 未合并分支/频繁修复文件/提交频率下降
  流程层: 跳过评审/PR 无 review/测试门禁跳过/直接推 main
  三级风险: 🔴 严重 / 🟡 警告 / 🔵 提示

P1-12: req-prd 需求粒度 AI 判断
  创建前启发式检查:标题过宽建议拆分、过窄建议合并或改 task
  粒度参考表 + 已有需求扩展决策表 + 前后端拆分规则

P1-13: dev-commit issue 集成规范
  分支名 -iN 后缀传递 issue 编号
  commit message 自动追加 closes #N

P1-14: hooks/validate-prd.sh — PRD 章节校验
  PostToolUse hook 自动检查 10 个必需章节
  缺失时给出明确提示

marketplace: 48 → 49 plugins (新增 pm-risk-plugin)
2026-04-19 13:33:26 +09:30
95 changed files with 5143 additions and 618 deletions
+168 -68
View File
@@ -35,6 +35,18 @@
],
"strict": false
},
{
"name": "pm-risk-plugin",
"source": "./skills-core/pm-risk-plugin",
"description": "三维度项目风险扫描:需求层/代码层/流程层。当用户说'/risk'、'风险扫描'、'有什么风险'时自动激活",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "publish-plugin",
"source": "./skills-core/publish-plugin",
@@ -59,6 +71,56 @@
],
"strict": false
},
{
"name": "agent-swarm-plugin",
"source": "./skills-dev/agent-swarm-plugin",
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "ai-chat-plugin",
"source": "./skills-dev/ai-chat-plugin",
"description": "AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "ai-proj-cicd-release-plugin",
"source": "./skills-dev/ai-proj-cicd-release-plugin",
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "ai-proj-macos-release-plugin",
"source": "./skills-dev/ai-proj-macos-release-plugin",
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "db-migration-plugin",
"source": "./skills-dev/db-migration-plugin",
@@ -71,6 +133,18 @@
],
"strict": false
},
{
"name": "defect-analysis-plugin",
"source": "./skills-dev/defect-analysis-plugin",
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
"version": "1.1.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "deploy-rollback-plugin",
"source": "./skills-dev/deploy-rollback-plugin",
@@ -253,6 +327,55 @@
],
"strict": false
},
{
"name": "executing-plans-plugin",
"source": "./skills-dev/executing-plans-plugin",
"description": "Use when you have a written implementation plan to execute in a separate session with review checkpoints.",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "finishing-branch-plugin",
"source": "./skills-dev/finishing-branch-plugin",
"description": "Use when implementation is complete and all tests pass - verifies and creates PR.",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "frontend-design-plugin",
"source": "./skills-dev/frontend-design-plugin",
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
"version": "1.0.1",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "karpathy-guidelines-plugin",
"source": "./skills-dev/karpathy-guidelines-plugin",
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
"version": "1.0.1",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "pull-request-plugin",
"source": "./skills-dev/pull-request-plugin",
@@ -270,7 +393,7 @@
"name": "review-checklist-plugin",
"source": "./skills-dev/review-checklist-plugin",
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
"version": "1.0.0",
"version": "1.1.0",
"category": "utility",
"keywords": [
"utility",
@@ -278,6 +401,19 @@
],
"strict": false
},
{
"name": "req-audit-plugin",
"source": "./skills-req/req-audit-plugin",
"description": "部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-compare-plugin",
"source": "./skills-req/req-compare-plugin",
@@ -317,6 +453,19 @@
],
"strict": false
},
{
"name": "req-lookback-plugin",
"source": "./skills-req/req-lookback-plugin",
"description": "回归测试。部署后自动验证变更涉及的功能是否正常。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-plugin",
"source": "./skills-req/req-plugin",
@@ -333,8 +482,8 @@
{
"name": "req-prd-plugin",
"source": "./skills-req/req-prd-plugin",
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
"version": "2.0.0",
"description": "产品需求设计技能。覆盖问答访谈、PRD、缺陷收敛及 HTML 原型验证闭环。纯产品视角,不含技术实现。",
"version": "2.1.0",
"category": "productivity",
"keywords": [
"project-management",
@@ -346,8 +495,8 @@
{
"name": "req-prototype-plugin",
"source": "./skills-req/req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。",
"version": "1.0.0",
"description": "原型生成与关联。支持 HTML 正式交付、Requirement 关联、iframe 验证闭环及 Stitch AI 视觉探索。",
"version": "2.1.0",
"category": "productivity",
"keywords": [
"project-management",
@@ -369,6 +518,19 @@
],
"strict": false
},
{
"name": "req-retro-plugin",
"source": "./skills-req/req-retro-plugin",
"description": "复盘总结。自动采集数据、计算质量评分、跨需求模式识别、技能自动进化。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-review-plugin",
"source": "./skills-req/req-review-plugin",
@@ -424,7 +586,7 @@
"name": "doubao-voice-plugin",
"source": "./skills-integration/doubao-voice-plugin",
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
"version": "1.0.0",
"version": "1.0.1",
"category": "utility",
"keywords": [
"utility",
@@ -560,68 +722,6 @@
"tools"
],
"strict": false
},
{
"name": "gitea-plugin",
"source": "./skills-personal/gitea-plugin",
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "openclaw-plugin",
"source": "./skills-personal/openclaw-plugin",
"description": "OpenClaw (龙虾) 远程 AI 计算调度系统 - 概念设计与运维管理",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "ops-tools-plugin",
"source": "./skills-personal/ops-tools-plugin",
"description": "Plugin for ops-tools",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "qiudl-personal-plugin",
"source": "./skills-personal/qiudl-personal-plugin",
"description": "Plugin for qiudl-personal",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "req-deploy-plugin",
"source": "./skills-personal/req-deploy-plugin",
"description": "Plugin for req-deploy",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
}
]
}
+9 -9
View File
@@ -1,14 +1,14 @@
# ai-proj-helper
Claude Code 技能市场 + MCP 配置管理工具。
Codex 优先、兼容 Claude Code 的 Agent Skills 市场与 MCP 配置管理工具。
## 快速开始
```bash
./init.sh
./install-skills.sh
```
交互式配置 MCP 连接(默认 SSE 模式)+ 自动注册技能市场到 `~/.claude/plugins/known_marketplaces.json`。支持命令行参数
默认安装到 Codex 标准目录 `~/.agents/skills`。Claude Code 的 MCP 与 marketplace 初始化使用
```bash
./init.sh --mode sse --token aiproj_pk_xxx
@@ -18,11 +18,11 @@ Claude Code 技能市场 + MCP 配置管理工具。
```
ai-proj-helper/
├── skills-core/ # 基础设施 (1): ai-proj
├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
├── skills-core/ # 基础设施技能
├── skills-dev/ # 开发与发布技能
├── skills-req/ # 需求管理技能
├── skills-integration/ # 第三方集成技能
├── skills-biz/ # 商务技能
├── skills-personal/ # 个人(.gitignore 排除)
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
├── init.sh # MCP 初始化
@@ -51,4 +51,4 @@ skills:
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
- 其余 `skills-*` 目录均由 Git 版本控制
- 所有目录会被 `generate-marketplace.py` 自动扫描并加入 marketplace.json
- 只有受 Git 跟踪的分类目录会被 `generate-marketplace.py` 扫描并加入公开 marketplace`skills-personal/` 始终排除
+14 -11
View File
@@ -1,6 +1,6 @@
# ai-proj-helper — 让 Claude Code 变成你的项目经理
# ai-proj-helper — 让 Codex / Claude Code 变成你的项目经理
> 一套开箱即用的 Claude Code 技能包 + MCP 服务,帮你用自然语言管理需求、写代码、做评审、同步飞书,把 AI 助手变成真正的项目经理
> 一套遵循 Agent Skills 标准的技能包 + MCP 服务,支持 Codex,并兼容 Claude Code
## 它能帮你做什么
@@ -66,7 +66,7 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
### 前置条件
- **Claude Code** 已安装([安装指南](https://docs.anthropic.com/en/docs/claude-code/overview)
- **Codex**[Skills 文档](https://developers.openai.com/codex/skills))或 **Claude Code** 已安装
- **ai-proj 账号 + MCP API Key**:联系管理员获取(Key 格式: `aiproj_pk_xxx`
### 一键部署(2 步搞定)
@@ -76,17 +76,16 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
cd ai-proj-helper
# 2. 运行初始化(按提示输入 API Key 即可)
./init.sh
# 2. 默认安装到 Codex 的用户级标准目录 ~/.agents/skills
./install-skills.sh
```
脚本会自动完成:
- 配置 MCP 服务器连接(`~/.claude/.mcp.json`
- 注册技能市场到 Claude Code`~/.claude/plugins/known_marketplaces.json`
安装器会复制完整技能目录,包括 `SKILL.md`、references、scripts 和 assets。Codex 会自动发现 `~/.agents/skills` 中的技能;若没有出现,重启 Codex。
也支持命令行参数跳过交互
Claude Code 用户显式选择 Claude 目标;需要同时配置 MCP 和 marketplace 时运行 `init.sh`
```bash
./install-skills.sh --agent claude
./init.sh --mode sse --token aiproj_pk_xxx
```
@@ -163,7 +162,7 @@ skills:
- **mode**: MCP 连接模式。`sse` 直连远程服务器(推荐),`stdio` 在本地启动 Node.js 进程
- **disabled**: 不需要的技能可以加到这里,重新运行 `./init.sh` 生效
- **personal_dir**: 个人技能目录,默认不被 Git 跟踪
- **personal_dir**: 本机个人技能目录,默认不被 Git 跟踪,也不会写入公开 marketplace
## 常见问题
@@ -171,13 +170,17 @@ skills:
A: 需要先联系管理员获取 MCP API Key(格式 `aiproj_pk_xxx`),然后在提示处输入。
**Q: 安装后 Codex 没有识别到技能?**
A: 确认技能位于 `~/.agents/skills/<name>/SKILL.md`,然后重启 Codex。Codex CLI 也可用 `/skills` 查看。
**Q: 安装后 Claude Code 没有识别到技能?**
A: 重启 Claude Code 后生效。如果仍不生效,检查 `~/.claude/plugins/known_marketplaces.json` 中是否包含 `ai-proj-helper` 条目。
**Q: 如何更新到最新版本?**
A: 进入项目目录执行 `git pull`,然后重新运行 `./init.sh`
A: 进入项目目录执行 `git pull`,然后运行 `./install-skills.sh`Claude Code 用户增加 `--agent claude`
**Q: 如何禁用不需要的技能?**
+25 -32
View File
@@ -1,28 +1,23 @@
# Setup Guide
# Claude Code Marketplace Setup
## 1. Create Repository on Gitea
本页只描述 Claude Code marketplace。Codex 用户直接运行 `./install-skills.sh`,技能默认安装到 `~/.agents/skills`
Go to https://gitea.pipexerp.com and create a new repository:
- Name: `claude-marketplace`
- Visibility: Private or Public (your choice)
- **Do NOT** initialize with README (we already have one)
## 2. Push to Gitea
## 1. Clone the Gitea Repository
```bash
cd /Users/junhuang/coolbuy/claude-marketplace
git push -u origin main
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
cd ai-proj-helper
```
## 3. Test Installation
## 2. Test Installation
### Add the marketplace
```bash
# SSH (recommended)
/plugin marketplace add git@gitea.pipexerp.com:huangjun/claude-marketplace.git
# SSH
/plugin marketplace add ssh://git@gitea.pipexerp.com:10022/pipexerp/ai-proj-helper.git
# OR HTTPS (requires credential configuration)
/plugin marketplace add https://gitea.pipexerp.com/huangjun/claude-marketplace.git
/plugin marketplace add https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
```
### List available plugins
@@ -42,12 +37,12 @@ git push -u origin main
# Check for your installed plugins
```
## 4. Update Plugins Later
## 3. Update Plugins Later
When you make changes and push updates:
```bash
cd /Users/junhuang/coolbuy/claude-marketplace
cd /path/to/ai-proj-helper
# Make changes to plugins
# ...
@@ -67,7 +62,7 @@ Users update with:
/plugin update ai-proj-plugin@coolbuy-claude-plugins
```
## 5. Private Repository Setup
## 4. Repository Authentication
If your Gitea repo is private, users need authentication:
@@ -87,30 +82,28 @@ To create a Gitea token:
3. Give it "Read repository" permissions
4. Copy the token and add to your environment
## 6. Structure Overview
## 5. Structure Overview
```
claude-marketplace/
ai-proj-helper/
├── .claude-plugin/
│ └── marketplace.json # Catalog of all plugins
├── plugins/
│ ├── ai-proj-plugin/
├── .claude-plugin/
│ │ │ └── plugin.json # Plugin metadata
│ │ └── skills/
│ │ └── SKILL.md # Skill definition
│ └── [33 more plugins...]
├── skills-core/ # Core plugins
├── skills-dev/ # Development and release plugins
├── skills-req/ # Requirement plugins
├── skills-integration/ # Integration plugins
├── skills-biz/ # Business plugins
├── README.md # User documentation
├── SETUP.md # This file
── convert-skills.sh # Conversion script (reference)
── generate-marketplace.py # Marketplace generator
└── install-skills.sh # Versioned local installer
```
## Next Steps
1.Push to Gitea: `git push -u origin main`
2.Test locally: `/plugin marketplace add <url>`
3.Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
4. ✅ Share with team: Send them the repository URL
1.Test locally: `/plugin marketplace add <url>`
2.Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
3.Share with team: Send them the repository URL
## Troubleshooting
@@ -123,7 +116,7 @@ claude-marketplace/
- Check plugin name is correct
- Ensure marketplace.json is valid: `cat .claude-plugin/marketplace.json | jq`
**"Skills not working"**
**"Skills not working in Claude Code"**
- Skills are Agent Skills (auto-invoked by Claude when relevant)
- They don't create slash commands
- Check plugin installation: `/plugin list`
+41 -190
View File
@@ -1,218 +1,69 @@
# Skill Sync Guide
## Overview
仓库中的插件是团队技能的发布源。默认安装目标是 Codex 的用户级标准目录 `~/.agents/skills/`。个人技能保留在
`skills-personal/` 或其他本机目录,不会进入公开 marketplace。
This guide explains how to keep your local skills (`~/.claude/skills/`) synchronized with the marketplace plugins.
## Quick Sync
## 从仓库更新本机
```bash
cd /path/to/claude-marketplace
./sync-skills.sh
git pull
./install-skills.sh --dry-run
./install-skills.sh
```
This will:
1. ✅ Compare local skills with marketplace plugins
2. Add new skills as plugins
3. 📝 Update changed skills
4. ✓ Skip unchanged plugins
## Sync Workflow
### 1. Edit Skills Locally
Work on your skills in `~/.claude/skills/`:
```bash
code ~/.claude/skills/my-skill/SKILL.md
```
### 2. Run Sync Script
Claude Code 需要显式选择目标:
```bash
cd ~/path/to/claude-marketplace
./sync-skills.sh
./install-skills.sh --agent claude
```
### 3. Review Changes
安装器会复制完整技能目录,包括 `SKILL.md``references/``scripts/``assets/`。它用内容摘要区分仓库升级和本地修改:
- 目标未修改时,版本升级会自动安装。
- 旧版只安装了 `SKILL.md` 时,会安全补齐仓库中的其他同源文件。
- 目标存在本地修改时会跳过;确认覆盖后才使用 `--force`
- `--cleanup` 会删除状态文件记录中已从仓库移除的技能,使用前先运行 `--dry-run --cleanup`
按分类安装或查看清单:
```bash
git status
git diff
./install-skills.sh --list
./install-skills.sh --category dev
./install-skills.sh --exclude ai-proj-cicd-release
```
### 4. Commit & Push
## 将本机技能发布到仓库
```bash
git add .
git commit -m "Update skill: description of changes"
git push
```
不要批量复制整个 `~/.agents/skills/` 或其他 Agent 的安装目录。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
### 5. Team Updates
1. 选择确实属于本仓库、可供团队复用的技能。
2. 在对应 `skills-*/<name>-plugin/` 下放置 `.claude-plugin/plugin.json` 和完整 `skills/` 目录。
3. 清除用户名、绝对路径、内网地址、密钥标识和历史凭据;把环境差异改为从仓库配置解析。
4. 更新插件版本并运行:
Team members update with:
```bash
/plugin marketplace update coolbuy-claude-plugins
/plugin update <plugin-name>@coolbuy-claude-plugins
```
```bash
python3 generate-marketplace.py
claude plugin validate .
git diff --check
```
## Automated Sync (Optional)
5. 审核变更后通过分支和 PR 发布。
### Git Hook (Pre-commit)
## 本地个人技能
Auto-sync when committing changes to skills:
`skills-personal/` 受 `.gitignore` 保护,仅供当前机器使用。生成器明确排除此目录,避免
`marketplace.json` 引用公开克隆中不存在的文件。若个人技能要转为团队技能,应先按上面的发布流程完成脱敏和审核。
```bash
# In your dotfiles/skills repo
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Auto-sync skills to marketplace
~/path/to/claude-marketplace/sync-skills.sh
EOF
## 常见问题
chmod +x .git/hooks/pre-commit
```
**本地修改被跳过怎么办?**
### Cron Job (Scheduled)
先比较仓库源和 `~/.agents/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。Claude 目标改查 `~/.claude/skills/`。
Sync daily at 9 AM:
**marketplace 没更新?**
```bash
crontab -e
运行 `python3 generate-marketplace.py`,然后检查 `.claude-plugin/marketplace.json` 是否只包含受 Git 跟踪且真实存在的 source。
# Add this line:
0 9 * * * cd ~/path/to/claude-marketplace && ./sync-skills.sh && git add . && git commit -m "Daily sync" && git push
```
**如何移除技能?**
## Skill Splitting Guidelines
From `~/.claude/CLAUDE.md`:
- **Token Limit**: Single skill ≤ 10,000 tokens
- **Check Size**: `wc -w ~/.claude/skills/<skill>/SKILL.md`
- **When to Split**: If > 7,500 words (≈10,000 tokens)
### Split Strategy
When a skill grows too large:
1. **Entry Skill** - Overview + command routing (<100 lines)
- Example: `req/SKILL.md`
2. **Command Reference** - Detailed commands (<200 lines)
- Example: `req-commands/SKILL.md`
3. **Workflow Guide** - Complete processes (<200 lines)
- Example: `req-workflow/SKILL.md`
4. **Methodology** - Complex concepts (<150 lines)
- Example: `req-review/SKILL.md`
## Troubleshooting
### Sync Script Fails
```bash
# Check permissions
ls -la sync-skills.sh
# Make executable
chmod +x sync-skills.sh
# Check paths
echo $HOME/.claude/skills
```
### marketplace.json Not Updated
```bash
# Manually regenerate
python3 generate-marketplace.py
# Or edit directly
code .claude-plugin/marketplace.json
```
### Git Conflicts
```bash
# Discard local changes
git checkout .claude-plugin/marketplace.json
# Or merge manually
git mergetool
```
## Best Practices
### 1. Descriptive Frontmatter
Always include in `SKILL.md`:
```yaml
---
name: skill-name
description: Clear, concise description of what this skill does
---
```
### 2. Version Bumping
When making significant changes:
```bash
# Update version in plugin.json
{
"version": "1.1.0" # was 1.0.0
}
```
### 3. Testing Before Sync
```bash
# Test skill locally first
/skill-name
# Then sync to marketplace
./sync-skills.sh
```
### 4. Commit Messages
Use clear, descriptive messages:
```bash
git commit -m "Add feishu-bitable plugin for table operations"
git commit -m "Update req-workflow with new approval process"
git commit -m "Fix: Correct PRD template in req-prd"
```
## Monitoring
### Check Sync Status
```bash
# Compare local vs marketplace
diff -qr ~/.claude/skills /tmp/claude-marketplace/plugins
```
### List Differences
```bash
# Find skills not in marketplace
comm -23 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
# Find plugins not in local
comm -13 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
```
## FAQ
**Q: Can I sync in reverse (marketplace → local)?**
A: Not recommended. Treat local skills as the source of truth.
**Q: What about binary files (images, scripts)?**
A: Copy them manually to the plugin directory, then commit.
**Q: How do I remove a plugin?**
A: Delete the plugin directory, regenerate marketplace.json, commit, and push.
**Q: Can I sync specific skills only?**
A: Modify `sync-skills.sh` to accept a skill name parameter.
删除插件目录、重新生成 marketplace、提交变更。使用者随后执行 `./install-skills.sh --dry-run --cleanup`,确认后再去掉 `--dry-run`。
+6 -13
View File
@@ -14,28 +14,27 @@ script_dir = Path(__file__).parent.resolve()
config_file = script_dir / "claude-config.yaml"
marketplace_file = script_dir / ".claude-plugin" / "marketplace.json"
# Skill directories (label, directory name)
# Public marketplace skill directories. skills-personal is deliberately
# excluded: it is gitignored and must never produce sources that disappear from
# a public clone of this repository.
SKILL_DIRS = [
("core", "skills-core"),
("dev", "skills-dev"),
("req", "skills-req"),
("integration", "skills-integration"),
("biz", "skills-biz"),
("personal", "skills-personal"),
]
def load_config():
"""Load claude-config.yaml and return disabled list + personal_dir."""
"""Load claude-config.yaml and return the disabled plugin list."""
disabled = []
personal = "skills-personal"
if config_file.exists() and HAS_YAML:
with open(config_file) as f:
cfg = yaml.safe_load(f) or {}
skills_cfg = cfg.get("skills", {})
disabled = skills_cfg.get("disabled", []) or []
personal = skills_cfg.get("personal_dir", personal)
elif config_file.exists():
# Fallback: parse disabled list without PyYAML
in_disabled = False
@@ -54,10 +53,7 @@ def load_config():
disabled.append(val)
elif stripped and not stripped.startswith("#"):
break
if stripped.startswith("personal_dir:"):
personal = stripped.split(":", 1)[1].strip().strip('"').strip("'")
return disabled, personal
return disabled
# Category mapping
@@ -116,15 +112,12 @@ def scan_plugins(directory, source_prefix, disabled):
# Load config
disabled_skills, personal_dir_name = load_config()
disabled_skills = load_config()
# Collect plugins from all skill directories
plugins = []
counts = {}
for label, dir_name in SKILL_DIRS:
# personal_dir may be overridden by config
if label == "personal":
dir_name = personal_dir_name
skill_path = script_dir / dir_name
if not skill_path.is_dir():
continue
+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
# validate-prd.sh
# PostToolUse Hook: PRD 文档写入/编辑后自动校验章节完整性
#
# 检查标准 PRD 模板的必需章节是否存在。
# 借鉴 devflow-claude validate-requirement.sh。
# REQ-20260416-0017 P1-14
#
# 安装方式(可选,加到 ~/.claude/settings.json:
# hooks.PostToolUse:
# - matcher: "Write|Edit"
# hooks:
# - type: command
# command: "<path>/hooks/validate-prd.sh"
# timeout: 5
#
# 也可由 skill 脚本在 PRD 写完后手动调用:
# bash validate-prd.sh /path/to/PRD.md
set -e
# ============ 1. 获取文件路径 ============
FILE_PATH="$1"
# 如果没有参数,从 stdin JSON 提取(PostToolUse hook 模式)
if [ -z "$FILE_PATH" ] && command -v jq >/dev/null 2>&1; then
INPUT=$(cat 2>/dev/null || echo "")
if [ -n "$INPUT" ]; then
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.content // empty' 2>/dev/null)
fi
fi
# 没有文件路径,静默退出
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# 不是 .md 文件,跳过
case "$FILE_PATH" in
*.md) ;;
*) exit 0 ;;
esac
# 文件不存在,跳过
if [ ! -f "$FILE_PATH" ]; then
exit 0
fi
# 不含 PRD / 需求 关键词的文件名,跳过
BASENAME=$(basename "$FILE_PATH")
case "$BASENAME" in
*PRD*|*prd*|*需求*|*requirement*|*REQ*) ;;
*) exit 0 ;;
esac
# ============ 2. 检查章节 ============
# 标准 PRD 必需章节(来自 req-prd SKILL.md 的模板)
REQUIRED_SECTIONS=(
"## 1. 概述"
"### 1.1 背景"
"### 1.2 目标"
"### 1.4 客户原始诉求"
"## 2. 用户分析"
"## 3. 功能需求"
"## 4. 交互设计"
"## 5. 技术要求"
"## 6. 上线计划"
"## 7. 风险评估"
)
MISSING=()
CONTENT=$(cat "$FILE_PATH")
for section in "${REQUIRED_SECTIONS[@]}"; do
# 模糊匹配:忽略空格差异和标点
PATTERN=$(echo "$section" | sed 's/[[:space:]]*//g')
CONTENT_CLEAN=$(echo "$CONTENT" | sed 's/[[:space:]]*//g')
if ! echo "$CONTENT_CLEAN" | grep -qi "$(echo "$PATTERN" | sed 's/#//g')"; then
MISSING+=("$section")
fi
done
# ============ 3. 输出 ============
if [ ${#MISSING[@]} -gt 0 ]; then
echo ""
echo "⚠️ PRD 章节检查:${BASENAME}"
echo ""
echo "缺少 ${#MISSING[@]} 个必需章节:"
for m in "${MISSING[@]}"; do
echo "$m"
done
echo ""
echo "💡 请参考 req-prd skill 的 PRD 模板补充缺失章节。"
echo " 章节结构不可变:不得新增、删除、合并或重命名模板中的章节。"
fi
exit 0
+8 -27
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# ai-proj-helper 初始化脚本
# 配置 MCP 连接 + 安装技能到 ~/.claude/skills/
# 配置 Claude MCP 连接 + 安装 Claude 技能
set -e
@@ -183,32 +183,13 @@ EOF
fi
fi
# ── Install skills to ~/.claude/skills/ ──────────────────────────────
# ── Install complete skill packages ──────────────────────────────────
# Use the versioned installer as the single installation path so references,
# scripts and assets stay beside SKILL.md and local edits are not overwritten.
echo "📦 安装技能到 ~/.claude/skills/ ..."
SKILLS_DIR="$HOME/.claude/skills"
mkdir -p "$SKILLS_DIR"
SKILL_COUNT=0
for plugin_dir in "$SCRIPT_DIR"/skills-*/; do
for skill_path in "$plugin_dir"*-plugin/; do
[ -d "$skill_path" ] || continue
skill_md="$skill_path/skills/SKILL.md"
[ -f "$skill_md" ] || continue
# Extract skill name: ai-proj-plugin -> ai-proj
dir_name=$(basename "$skill_path")
skill_name="${dir_name%-plugin}"
target_dir="$SKILLS_DIR/$skill_name"
mkdir -p "$target_dir"
# Copy SKILL.md (overwrite if exists)
cp "$skill_md" "$target_dir/SKILL.md"
SKILL_COUNT=$((SKILL_COUNT + 1))
done
done
echo " 已安装 $SKILL_COUNT 个技能"
echo "✅ 技能安装完成 → $SKILLS_DIR"
"$SCRIPT_DIR/install-skills.sh" --agent claude
SKILL_COUNT=$(python3 -c 'import json, os; p=os.path.expanduser("~/.claude/.installed-skills.json"); print(len(json.load(open(p))) if os.path.exists(p) else 0)' 2>/dev/null || echo 0)
echo "✅ 技能安装完成"
# ── Verify MCP connection ────────────────────────────────────────────
echo ""
@@ -270,7 +251,7 @@ if $HAS_CLAUDE; then
else
echo " ✅ MCP 服务器 → $MCP_CONFIG"
fi
echo " ✅ 技能 ($SKILL_COUNT 个) → $SKILLS_DIR"
echo " ✅ 技能 ($SKILL_COUNT 个) → ~/.claude/skills"
echo ""
echo "重启 Claude Code 即可使用。"
echo "如需更改配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
+456
View File
@@ -0,0 +1,456 @@
#!/usr/bin/env bash
# install-skills.sh — Cross-agent skill sync from ai-proj-helper
#
# Usage:
# ./install-skills.sh [options]
#
# Options:
# --agent <agent> Install target: codex (default) or claude
# --dry-run Preview changes without writing anything
# --category <cat> Only install plugins in dir_category=<cat>
# Valid values: biz, core, dev, integration, personal, req
# --exclude <name> Skip one install_name (repeatable)
# --force Overwrite even if local files were modified
# --cleanup Remove locally installed skills that are no longer in repo
# --list List all available plugins without installing
# --help Show this help
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILLS_DIR=""
COMMANDS_DIR=""
STATE_FILE=""
AGENT_TARGET="codex"
DRY_RUN=false
CATEGORY_FILTER=""
EXCLUDED_NAMES=()
FORCE=false
CLEANUP=false
LIST_ONLY=false
INSTALL_ACTION=false
# ── Colour helpers ─────────────────────────────────────────────────────────────
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
RESET='\033[0m'
info() { echo -e "${BLUE}[info]${RESET} $*"; }
ok() { echo -e "${GREEN}[ok]${RESET} $*"; }
warn() { echo -e "${YELLOW}[warn]${RESET} $*"; }
error() { echo -e "${RED}[error]${RESET} $*" >&2; }
dry() { echo -e "${YELLOW}[dry]${RESET} $*"; }
# ── Argument parsing ───────────────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
case "$1" in
--agent)
[[ $# -ge 2 ]] || { error "--agent requires codex or claude"; exit 1; }
AGENT_TARGET="$2"; shift ;;
--dry-run) DRY_RUN=true ;;
--force) FORCE=true ;;
--cleanup) CLEANUP=true ;;
--list) LIST_ONLY=true ;;
--category)
[[ $# -ge 2 ]] || { error "--category requires a value"; exit 1; }
CATEGORY_FILTER="$2"; shift ;;
--exclude)
[[ $# -ge 2 ]] || { error "--exclude requires an install_name"; exit 1; }
EXCLUDED_NAMES+=("$2"); shift ;;
--help|-h)
grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//'
exit 0 ;;
*)
error "Unknown argument: $1"
exit 1 ;;
esac
shift
done
case "$AGENT_TARGET" in
codex)
# ~/.agents/skills is the current user-level Codex discovery location and
# is intentionally agent-neutral. Commands are installed as normal skills.
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}"
;;
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)"
exit 1
;;
esac
# ── State helpers (plain JSON via python3) ─────────────────────────────────────
state_get() {
# state_get <install_name> -> prints version or empty string
local name="$1"
if [[ -f "$STATE_FILE" ]]; then
python3 -c "
import json,sys
try:
d=json.load(open('$STATE_FILE'))
print(d.get('$name',{}).get('version',''))
except: pass
" 2>/dev/null || true
fi
}
state_digest() {
# state_digest <install_name> -> prints installed content digest or empty string
local name="$1"
if [[ -f "$STATE_FILE" ]]; then
python3 -c "
import json
try:
d=json.load(open('$STATE_FILE'))
print(d.get('$name',{}).get('content_digest',''))
except: pass
" 2>/dev/null || true
fi
}
state_set() {
# state_set <install_name> <version> <install_type> <content_digest>
local name="$1" ver="$2" itype="$3" digest="$4"
python3 -c "
import json,os
f='$STATE_FILE'
d=json.load(open(f)) if os.path.exists(f) else {}
d['$name']={'version':'$ver','install_type':'$itype','content_digest':'$digest','agent':'$AGENT_TARGET'}
json.dump(d,open(f,'w'),indent=2)
" 2>/dev/null
}
state_remove() {
local name="$1"
python3 -c "
import json,os
f='$STATE_FILE'
if not os.path.exists(f): exit()
d=json.load(open(f))
d.pop('$name',None)
json.dump(d,open(f,'w'),indent=2)
" 2>/dev/null
}
state_all_names() {
if [[ -f "$STATE_FILE" ]]; then
python3 -c "
import json
d=json.load(open('$STATE_FILE'))
for k in d: print(k)
" 2>/dev/null || true
fi
}
# ── Plugin discovery ───────────────────────────────────────────────────────────
find_plugins() {
find "$REPO_DIR" -path "*/skills-*/*-plugin/.claude-plugin/plugin.json" | sort
}
read_field() {
# read_field <json_file> <field>
python3 -c "import json,sys; d=json.load(open('$1')); print(d.get('$2',''))" 2>/dev/null || true
}
content_digest() {
# Stable digest for one command file or a complete skill directory.
python3 - "$1" <<'PY'
import hashlib
import os
import pathlib
import sys
target = pathlib.Path(sys.argv[1])
if not target.exists():
print("")
raise SystemExit
digest = hashlib.sha256()
files = [target] if target.is_file() else sorted(
path for path in target.rglob("*") if path.is_file() or path.is_symlink()
)
for path in files:
# A single-file command is renamed when installed for Claude. Hash its
# content under a stable logical name so source and target compare equally.
relative = "." if target.is_file() else path.relative_to(target).as_posix()
digest.update(relative.encode("utf-8"))
digest.update(b"\0")
if path.is_symlink():
digest.update(b"link\0")
digest.update(os.readlink(path).encode("utf-8"))
else:
digest.update(path.read_bytes())
digest.update(b"\0")
print(digest.hexdigest())
PY
}
is_compatible_subset() {
# True when every file in an existing legacy target also exists unchanged in
# the repository source. This safely upgrades old SKILL.md-only installs.
python3 - "$1" "$2" <<'PY'
import pathlib
import sys
source = pathlib.Path(sys.argv[1])
target = pathlib.Path(sys.argv[2])
if not source.is_dir() or not target.is_dir():
raise SystemExit(1)
for target_path in target.rglob("*"):
if target_path.is_dir():
continue
source_path = source / target_path.relative_to(target)
if not source_path.is_file() or target_path.is_symlink() != source_path.is_symlink():
raise SystemExit(1)
if target_path.is_symlink():
if target_path.readlink() != source_path.readlink():
raise SystemExit(1)
elif target_path.read_bytes() != source_path.read_bytes():
raise SystemExit(1)
raise SystemExit(0)
PY
}
# Resolve the actual source directory to rsync from.
# If skills/ has SKILL.md at the top level, use it directly.
# If skills/ has a single subdirectory (e.g. skills/dev-test/SKILL.md), use that subdirectory.
resolve_skills_src() {
local skills_dir="$1"
if [[ -f "$skills_dir/SKILL.md" ]]; then
echo "$skills_dir"
return
fi
# Find the first subdirectory that contains SKILL.md
local sub
sub="$(find "$skills_dir" -maxdepth 2 -name 'SKILL.md' | head -1)"
if [[ -n "$sub" ]]; then
echo "$(dirname "$sub")"
return
fi
echo "$skills_dir"
}
# ── Install a single plugin ────────────────────────────────────────────────────
install_plugin() {
INSTALL_ACTION=false
local json_path="$1"
local plugin_dir
plugin_dir="$(dirname "$(dirname "$json_path")")" # strip /.claude-plugin/plugin.json
local skills_dir="$plugin_dir/skills"
local install_name install_type dir_category version
install_name="$(read_field "$json_path" install_name)"
install_type="$(read_field "$json_path" install_type)"
dir_category="$(read_field "$json_path" dir_category)"
version="$(read_field "$json_path" version)"
local excluded
for excluded in ${EXCLUDED_NAMES[@]+"${EXCLUDED_NAMES[@]}"}; do
[[ "$install_name" == "$excluded" ]] && return
done
# Skip if no install metadata (legacy plugin without our new fields)
if [[ -z "$install_name" || -z "$install_type" ]]; then
warn "$(basename "$plugin_dir"): missing install_name/install_type, skipping"
return
fi
# Category filter
if [[ -n "$CATEGORY_FILTER" && "$dir_category" != "$CATEGORY_FILTER" ]]; then
return
fi
# Verify skills directory exists
if [[ ! -d "$skills_dir" ]]; then
warn "$install_name: no skills/ directory in plugin, skipping"
return
fi
local effective_install_type="$install_type"
if [[ "$AGENT_TARGET" == "codex" ]]; then
effective_install_type="skill"
fi
if [[ "$LIST_ONLY" == true ]]; then
echo " [$dir_category] $effective_install_type:$install_name v$version"
return
fi
# Resolve actual source (handles plugins where content sits one level deeper,
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md).
local src_dir
src_dir="$(resolve_skills_src "$skills_dir")"
local source_path target_path
if [[ "$effective_install_type" == "command" ]]; then
source_path="$src_dir/SKILL.md"
target_path="$COMMANDS_DIR/${install_name}.md"
else
source_path="$src_dir"
target_path="$SKILLS_DIR/$install_name"
fi
if [[ ! -e "$source_path" ]]; then
warn "$install_name: install source not found, skipping"
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.
local current_version recorded_digest source_digest target_digest
current_version="$(state_get "$install_name")"
recorded_digest="$(state_digest "$install_name")"
source_digest="$(content_digest "$source_path")"
target_digest="$(content_digest "$target_path")"
if [[ "$FORCE" == false && -n "$target_digest" && "$target_digest" == "$source_digest" ]]; then
if [[ "$DRY_RUN" == false && ( "$current_version" != "$version" || "$recorded_digest" != "$source_digest" ) ]]; then
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
fi
return
fi
local legacy_subset=false
if [[ "$effective_install_type" == "skill" && -z "$recorded_digest" && -n "$target_digest" ]]; then
if is_compatible_subset "$source_path" "$target_path"; then
legacy_subset=true
fi
fi
if [[ "$FORCE" == false && -n "$target_digest" && "$legacy_subset" == false ]]; then
if [[ -z "$recorded_digest" || "$target_digest" != "$recorded_digest" ]]; then
warn "$install_name: local files were modified or have legacy unverified state — skipping (use --force once to adopt repository content)"
return
fi
fi
# Perform install
if [[ "$effective_install_type" == "command" ]]; then
# Single-file command → ~/.claude/commands/<name>.md
local src_md="$src_dir/SKILL.md"
if [[ ! -f "$src_md" ]]; then
warn "$install_name: SKILL.md not found, skipping"
return
fi
if [[ "$DRY_RUN" == true ]]; then
dry "$install_name$COMMANDS_DIR/${install_name}.md"
INSTALL_ACTION=true
else
mkdir -p "$COMMANDS_DIR"
cp "$src_md" "$COMMANDS_DIR/${install_name}.md"
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
ok "$install_name → command (v$version)"
INSTALL_ACTION=true
fi
else
# Standard skill directory → the selected agent's discovery root.
local dst_dir="$SKILLS_DIR/$install_name"
if [[ "$DRY_RUN" == true ]]; then
dry "$install_name$dst_dir/"
INSTALL_ACTION=true
else
mkdir -p "$dst_dir"
# rsync resolved source (handles nested skills/ structures)
rsync -a --delete "$src_dir/" "$dst_dir/"
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
ok "$install_name → skill (v$version)"
INSTALL_ACTION=true
fi
fi
}
# ── Cleanup removed plugins ────────────────────────────────────────────────────
cleanup_removed() {
if [[ "$CLEANUP" == false ]]; then
return
fi
info "Checking for removed plugins to clean up..."
# Collect all install_names still in repo
local repo_names=()
while IFS= read -r json_path; do
local name
name="$(read_field "$json_path" install_name)"
[[ -n "$name" ]] && repo_names+=("$name")
done < <(find_plugins)
# Check state file for installed plugins no longer in repo
while IFS= read -r installed_name; do
local found=false
for repo_name in "${repo_names[@]}"; do
[[ "$repo_name" == "$installed_name" ]] && found=true && break
done
if [[ "$found" == false ]]; then
local itype
itype="$(python3 -c "import json; d=json.load(open('$STATE_FILE')); print(d.get('$installed_name',{}).get('install_type',''))" 2>/dev/null || true)"
if [[ "$DRY_RUN" == true ]]; then
dry "Would remove: $installed_name ($itype)"
else
if [[ "$itype" == "command" ]]; then
rm -f "$COMMANDS_DIR/${installed_name}.md"
else
rm -rf "${SKILLS_DIR:?}/$installed_name"
fi
state_remove "$installed_name"
ok "Removed: $installed_name"
fi
fi
done < <(state_all_names)
}
# ── Main ───────────────────────────────────────────────────────────────────────
main() {
if [[ "$LIST_ONLY" == true ]]; then
info "Available plugins in $REPO_DIR:"
local count=0
while IFS= read -r json_path; do
install_plugin "$json_path"
((count++)) || true
done < <(find_plugins)
echo ""
info "Total: $count plugins"
return
fi
info "Installing skills for $AGENT_TARGET from: $REPO_DIR"
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
local installed=0
while IFS= read -r json_path; do
install_plugin "$json_path"
if [[ "$INSTALL_ACTION" == true ]]; then
((installed++)) || true
fi
done < <(find_plugins)
cleanup_removed
echo ""
if [[ "$DRY_RUN" == true ]]; then
info "Dry run complete. $installed plugins would be installed/updated."
else
info "Done. $installed plugins installed/updated."
info "State saved to: $STATE_FILE"
fi
}
main "$@"
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "biz-contract",
"install_type": "skill",
"dir_category": "biz"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "biz-ops",
"install_type": "skill",
"dir_category": "biz"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "biz-plan",
"install_type": "skill",
"dir_category": "biz"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "finance",
"install_type": "skill",
"dir_category": "biz"
}
@@ -4,5 +4,8 @@
"version": "2.0.1",
"author": {
"name": "qiudl"
}
},
"install_name": "ai-proj",
"install_type": "skill",
"dir_category": "core"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "pm-ask",
"install_type": "skill",
"dir_category": "core"
}
@@ -0,0 +1,11 @@
{
"name": "pm-risk-plugin",
"description": "三维度项目风险扫描:需求层/代码层/流程层。当用户说'/risk'、'风险扫描'、'有什么风险'时自动激活",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "pm-risk",
"install_type": "skill",
"dir_category": "core"
}
+154
View File
@@ -0,0 +1,154 @@
---
name: pm-risk
description: 三维度项目风险扫描(需求层/代码层/流程层)。当用户说"/risk"、"风险扫描"、"有什么风险"、"哪些需求停滞了"、"分支健康"时自动激活。
---
# pm-risk Skill — 三维度风险扫描
借鉴自 devflow-claude `/pm:risk`。源自 REQ-20260416-0017 P1-10。
## 命令
```
/risk [--save]
```
- 不加参数:扫描并展示报告
- `--save`:保存到思源笔记
## 扫描维度
### 维度 1: 需求层
通过 ai-proj MCP 查询需求状态:
| 检测项 | 数据源 | 严重 | 警告 | 提示 |
|--------|--------|------|------|------|
| 需求停滞 | `list_requirements` + `updated_at` | >14 天无更新 | >7 天无更新 | >3 天无更新 |
| 草稿滞留 | `list_requirements --status=draft` | >30 天 | >14 天 | >7 天 |
| 开发中无提交 | 需求关联分支 + `git log` | >7 天无 commit | >3 天 | - |
| 测试中超期 | `list_requirements --delivery_stage=testing` | >14 天 | >7 天 | - |
| 已批准未开发 | `list_requirements --status=approved` | >30 天 | >14 天 | - |
**查询方式**
```
mcp__ai-proj__list_requirements(status=in_progress)
→ 遍历每个需求的 updated_at,计算距今天数
```
### 维度 2: 代码层
通过 git 命令分析:
| 检测项 | 命令 | 严重 | 警告 |
|--------|------|------|------|
| 未合并分支过久 | `git branch -r --no-merged origin/develop` + `git log -1` | >14 天无 commit | >7 天 |
| 频繁修复文件 | `git log --diff-filter=M --name-only` 近 30 天 | 同文件 >5 次 fix commit | >3 次 |
| 提交频率下降 | 本周 vs 上周 commit 数 | 下降 >70% | 下降 >50% |
| 大文件提交 | `git log --diff-filter=A --name-only` | >10MB 文件 | >5MB |
**查询方式**
```bash
# 未合并分支
git for-each-ref --sort=-committerdate --format='%(refname:short) %(committerdate:short)' refs/remotes/origin/ | grep -v 'main\|develop\|HEAD'
# 频繁修复
git log --since='30 days ago' --grep='fix' --diff-filter=M --name-only --pretty=format:'' | sort | uniq -c | sort -rn | head -10
# 提交频率
THIS_WEEK=$(git log --since='7 days ago' --oneline | wc -l)
LAST_WEEK=$(git log --since='14 days ago' --until='7 days ago' --oneline | wc -l)
```
### 维度 3: 流程层
通过 MCP + git 交叉分析:
| 检测项 | 检测方法 | 级别 |
|--------|---------|------|
| 跳过评审直接开发 | 需求 status 从 draft 直接跳到 in_progress(没有 approved 记录) | 警告 |
| PR 无评审直接合并 | Gitea API 查 PR 无 review approve 就 merge | 警告 |
| 测试门禁跳过 | delivery_stage 从 dev 跳到 released(没有 testing | 严重 |
| 直接推 main | `git log --first-parent origin/main` 非 merge commit | 严重 |
## 风险级别定义
| 级别 | 图标 | 含义 | 响应 |
|------|------|------|------|
| 严重 | 🔴 | 立即关注 | 当天处理 |
| 警告 | 🟡 | 近期需处理 | 3 天内处理 |
| 提示 | 🔵 | 值得留意 | 下次迭代关注 |
## 输出模板
```markdown
# 🔍 风险扫描报告
**扫描时间**: YYYY-MM-DD HH:MM CST
**扫描范围**: 项目 ai-proj
## 概览
| 维度 | 🔴 严重 | 🟡 警告 | 🔵 提示 |
|------|---------|---------|---------|
| 需求层 | X | X | X |
| 代码层 | X | X | X |
| 流程层 | X | X | X |
## 🔴 严重风险
### [S1] REQ-20260410-0001 停滞 18 天
- **需求**: REQ-20260410-0001 用户积分管理
- **状态**: in_progress
- **最后更新**: 2026-04-01
- **建议**: 联系负责人确认是否阻塞,必要时降级或暂停
### [S2] ...
## 🟡 警告
### [W1] 分支 feat/xxx 14 天未合并
- **分支**: feat/old-feature
- **最后 commit**: 2026-04-05
- **建议**: 确认是否放弃,清理或合并
## 🔵 提示
...
## ✅ 一切正常的维度
- (无严重/警告时显示此段)
---
**下次扫描建议**: 每周一早会前执行 `/risk`
```
## 无风险时的输出
```
✅ 风险扫描完成 — 一切正常
扫描了 X 个需求、Y 个分支、Z 条提交,未发现风险项。
下次扫描建议:下周一
```
## 定期执行建议
- **手动**:每周一早会前 `/risk`
- **自动**:可配合 `/loop 7d /risk --save` 定期扫描并保存到思源笔记
## 与其他 skill 的关系
| skill | 协作 |
|-------|------|
| `pm-ask` | risk 发现问题后,用 `/ask` 深入分析 |
| `req-workflow` | risk 发现流程违规后,用 `/req` 修正 |
| `ai-proj` | 底层 MCP 数据查询 |
## 参考
- devflow-claude: `plugins/pm/commands/risk.md`
- REQ-20260416-0017 P1-10
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "publish",
"install_type": "skill",
"dir_category": "core"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "agent-browser",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,11 @@
{
"name": "agent-swarm-plugin",
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "agent-swarm",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,406 @@
---
name: agent-swarm
description: Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.
---
# Agent Swarm - Multi-Agent Orchestration
基于 OpenAI Swarm 设计模式的多智能体协作系统,用于复杂开发任务的智能分解与协调。
## 核心概念
### 1. Agent(智能体)
每个 Agent 是具有特定职责的专家:
- **Instructions**: Agent 的角色定义和行为准则
- **Functions**: Agent 可以调用的工具函数
- **Handoffs**: 何时移交给其他 Agent
### 2. Handoff(任务移交)
Agent 之间的控制权转移机制:
- 当前 Agent 完成自己的职责
- 识别需要其他专长
- 移交给最合适的 Agent
### 3. Context Variables(上下文变量)
跨 Agent 共享的状态:
- 项目目录
- 技术栈信息
- 当前进度
- 发现的问题
---
## 预定义 Agent
### 1. Architect Agent(架构师)
**职责**: 理解需求、技术选型、设计系统架构
**何时使用**:
- 用户描述新功能或系统
- 需要技术方案设计
- 需要架构评审
**工具**:
- Read codebase
- Grep patterns
- 设计文档生成
**Handoff to**:
- Coder Agent(开始编码)
- Reviewer Agent(评审设计)
---
### 2. Coder Agent(编码者)
**职责**: 实现功能、编写代码、修复 bug
**何时使用**:
- 架构师完成设计
- 用户提出 bug 修复
- 需要代码重构
**工具**:
- Edit files
- Write files
- Git operations
**Handoff to**:
- Tester Agent(代码完成后)
- Architect Agent(遇到设计问题)
---
### 3. Tester Agent(测试员)
**职责**: 编写测试、运行测试、验证功能
**何时使用**:
- 代码编写完成
- 需要测试覆盖
- 验证 bug 修复
**工具**:
- Run tests
- Write test cases
- Coverage reports
**Handoff to**:
- Deployer Agent(测试通过)
- Coder Agent(发现问题)
---
### 4. Deployer Agent(部署员)
**职责**: 构建镜像、部署服务、监控上线
**何时使用**:
- 测试全部通过
- 需要发布到环境
- 需要回滚版本
**工具**:
- Docker build
- SSH deployment
- Health checks
**Handoff to**:
- Monitor Agent(部署完成)
- Coder Agent(部署失败)
---
### 5. Reviewer Agent(评审员)
**职责**: 代码审查、文档审查、安全检查
**何时使用**:
- PR 创建后
- 重要功能完成
- 需要质量把关
**工具**:
- Diff analysis
- Security scan
- Best practices check
**Handoff to**:
- Coder Agent(需要修改)
- Deployer Agent(审查通过)
---
## 使用方法
### 基本调用
```bash
/swarm start "在 new-ai-proj 中实现任务批量删除功能"
```
**执行流程**:
1. **Architect** 分析需求 → 设计 API 和前端交互
2. **Coder** 实现后端 API → 实现前端 UI
3. **Tester** 编写单元测试 → 运行测试
4. **Reviewer** 代码审查 → 安全检查
5. **Deployer** 部署到 staging → 验证功能
---
### 指定起始 Agent
```bash
/swarm coder "修复 backend/handlers/task_handler.go 的空指针 bug"
```
直接从 Coder Agent 开始,跳过架构设计阶段。
---
### 传递上下文
```bash
/swarm start "优化数据库查询性能" \
--context project=/Users/coolbuy-dev/coding/new-ai-proj \
--context stack=Go,PostgreSQL,Redis \
--context module=backend/services
```
---
### 查看执行轨迹
```bash
/swarm trace
```
显示 Agent 调用链:
```
Architect → analyzed requirements (3 min)
↓ handoff: "Design complete, ready for implementation"
Coder → implemented 5 files (12 min)
↓ handoff: "Code complete, needs testing"
Tester → wrote 8 test cases, all passed (5 min)
↓ handoff: "Tests passed, ready for review"
Reviewer → approved with 2 suggestions (2 min)
↓ handoff: "Approved, ready for deployment"
Deployer → deployed to staging, health check OK (3 min)
```
---
## 配置文件
### swarm.yaml
在项目根目录创建 `swarm.yaml` 自定义 Agent 行为:
```yaml
agents:
architect:
instructions: |
你是系统架构师,专注于 Go + Vue.js 技术栈。
遵循 RESTful API 设计原则。
考虑性能、安全性、可维护性。
max_turns: 5
coder:
instructions: |
你是 Go 后端工程师和 Vue.js 前端工程师。
编写清晰、简洁、高性能的代码。
遵循项目现有代码风格。
tools:
- Edit
- Write
- Bash
max_turns: 10
tester:
instructions: |
你是测试工程师,编写全面的测试用例。
确保边界条件、错误处理、并发安全。
tools:
- Bash
- Write
test_command: "go test ./... -v"
max_turns: 5
context_variables:
project_root: /Users/coolbuy-dev/coding/new-ai-proj
backend_lang: Go 1.21
frontend_framework: Vue 3
database: PostgreSQL 15
deployment_target: staging.ai.pipexerp.com
```
---
## 高级功能
### 1. 自定义 Agent
```yaml
agents:
database-optimizer:
instructions: |
你是数据库性能优化专家。
分析慢查询、优化索引、设计缓存策略。
functions:
- explain_analyze
- create_index
- cache_design
handoff_to:
- coder # 实现优化方案
```
---
### 2. 条件 Handoff
```yaml
handoff_rules:
- from: tester
to: coder
condition: "test_pass_rate < 90%"
message: "测试失败率超过 10%,需要修复"
- from: tester
to: deployer
condition: "test_pass_rate == 100%"
message: "所有测试通过,可以部署"
```
---
### 3. 并行 Agent
对于独立任务,多个 Agent 可以并行工作:
```bash
/swarm parallel \
"coder: 实现后端 API" \
"coder: 实现前端 UI" \
"tester: 编写 API 测试"
```
---
## 与 Remote Coding 集成
在 OpenClaw 中调用本地 Claude Code 执行 Swarm 工作流:
```bash
# OpenClaw 调用 Melbourne Claude Code
ssh melbourne "cd /Users/coolbuy-dev/coding/new-ai-proj && \
/opt/homebrew/bin/claude --dangerously-skip-permissions \
-p '/swarm start 实现任务批量删除功能'"
```
---
## 实际案例
### 案例 1: 新功能开发
**任务**: "为 AI-Proj 实现需求批量导出功能"
**执行过程**:
1. **Architect**:
- 分析需求:导出格式(Excel/PDF)、筛选条件、数据脱敏
- 设计 API: `POST /api/v1/requirements/export`
- 设计前端:导出按钮、进度条、下载链接
2. **Coder**:
- 后端实现 export service
- 前端实现导出 UI 组件
- 集成 file download 功能
3. **Tester**:
- 测试大量数据导出(1000+ 需求)
- 测试并发导出
- 测试下载失败重试
4. **Reviewer**:
- 检查文件大小限制
- 检查内存泄漏风险
- 检查数据权限控制
5. **Deployer**:
- 部署到 staging
- 验证导出功能
- 监控资源使用
---
### 案例 2: Bug 修复
**任务**: "修复任务详情页加载缓慢问题"
**执行过程**:
1. **Architect**:
- 分析性能瓶颈:N+1 查询问题
- 设计优化方案:使用 JOIN 和预加载
2. **Coder**:
- 优化数据库查询
- 添加 Redis 缓存
- 更新前端数据获取逻辑
3. **Tester**:
- 性能测试:加载时间从 3s → 300ms
- 并发测试:100 用户同时访问
- 缓存一致性测试
4. **Deployer**:
- 灰度发布到 10% 用户
- 监控性能指标
- 全量发布
---
## 最佳实践
1. **明确任务范围**: 复杂任务交给 Swarm,简单任务直接执行
2. **合理设置 max_turns**: 避免 Agent 陷入死循环
3. **记录 Handoff 原因**: 便于追溯和调试
4. **定期审查轨迹**: 优化 Agent 协作流程
5. **利用 Context Variables**: 避免重复传递信息
---
## 故障排查
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| Agent 一直循环 | max_turns 设置过大 | 降低 max_turns,添加明确的 handoff 条件 |
| Handoff 失败 | 目标 Agent 未定义 | 检查 swarm.yaml 配置 |
| 上下文丢失 | Context Variables 未传递 | 在 handoff 时显式传递 context |
| 执行太慢 | 串行执行可并行任务 | 使用 `/swarm parallel` |
---
## 与其他 Skills 集成
- **dev-coding**: Coder Agent 使用 dev-coding 的编码规范
- **dev-test**: Tester Agent 使用 dev-test 的测试策略
- **ops-tools**: Deployer Agent 使用 ops-tools 进行部署
- **ai-proj**: 所有 Agent 使用 ai-proj MCP 进行任务同步
---
## 命令速查
| 命令 | 功能 |
|------|------|
| `/swarm start <task>` | 启动 Swarm 工作流(从 Architect 开始) |
| `/swarm <agent> <task>` | 从指定 Agent 开始 |
| `/swarm parallel <tasks>` | 并行执行多个任务 |
| `/swarm trace` | 查看执行轨迹 |
| `/swarm config` | 显示当前配置 |
| `/swarm agents` | 列出所有可用 Agent |
| `/swarm stop` | 终止当前 Swarm 执行 |
---
## 参考资料
- [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)
@@ -0,0 +1,11 @@
{
"name": "ai-chat-plugin",
"description": "AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "ai-chat",
"install_type": "skill",
"dir_category": "dev"
}
+537
View File
@@ -0,0 +1,537 @@
---
name: ai-chat
description: AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。
arguments: <subcommand> [args]
---
# AI Chat Skill
测试和管理 Coolbuy PaaS AI Chat 服务的 Claude Code skill。
## Quick Reference
| 命令 | 用途 |
|------|------|
| `/ai-chat send <message>` | 发送消息到 AI Chat,实时显示工具调用 + AI 回复 |
| `/ai-chat env [local\|staging]` | 切换/查看目标环境(默认 local) |
| `/ai-chat tools [category]` | 列出当前环境已注册的工具 |
| `/ai-chat config` | 查看 AI 配置(Provider、工具开关等) |
| `/ai-chat history` | 显示本次会话的历史消息 |
---
## Environment Config
两套环境,通过 `/ai-chat env` 切换:
| 环境 | Auth URL | AI URL | 登录账号 |
|------|----------|--------|----------|
| **local** (默认) | `http://localhost:7089` | `http://localhost:7092` | lining_admin / admin123 |
| **staging** | `http://39.105.150.219:7089` | `http://39.105.150.219:7092` | lining_admin / admin123 |
### 状态文件
环境状态保存在 `/tmp/ai-chat-state.json`,格式:
```json
{
"env": "local",
"token": "eyJ...",
"token_env": "local",
"history": []
}
```
---
## Commands
### /ai-chat env
**切换或查看当前环境。**
用法:
- `/ai-chat env` — 显示当前环境
- `/ai-chat env local` — 切换到本地环境
- `/ai-chat env staging` — 切换到 staging 环境
实现步骤:
1. 读取 `/tmp/ai-chat-state.json`(不存在则默认 `{"env":"local","history":[]}`
2. 如果提供了参数,更新 `env` 字段并清空 `token`(环境变了 token 失效)
3. 写回状态文件
4. 输出当前环境信息表格
---
### /ai-chat send
**发送消息到 AI Chat 并实时显示流式响应。**
用法:`/ai-chat send <message>`
实现步骤:
#### Step 1: 读取状态
```bash
# 读取状态文件
cat /tmp/ai-chat-state.json 2>/dev/null || echo '{"env":"local","history":[]}'
```
确定环境变量:
- **local**: `AUTH_URL=http://localhost:7089`, `AI_URL=http://localhost:7092`
- **staging**: `AUTH_URL=http://39.105.150.219:7089`, `AI_URL=http://39.105.150.219:7092`
#### Step 2: 获取 Token
如果状态文件中没有 token 或 `token_env` 与当前 `env` 不匹配,执行登录:
```bash
curl -s -X POST "$AUTH_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"lining_admin","password":"admin123"}'
```
从响应中提取 `access_token`
```bash
# 响应格式
# {"access_token":"eyJ...","refresh_token":"...","token_type":"Bearer","expires_in":7200,"user_info":{...}}
```
`python3 -c "import json,sys; print(json.load(sys.stdin)['access_token'])"` 提取 token。
将 token 和 token_env 保存到状态文件。
#### Step 3: 构造请求并发送 SSE 流
```bash
curl -s -N -X POST "$AI_URL/api/v1/ai/chat/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"message\":\"$MSG\",\"history\":$HISTORY}" 2>&1
```
**重要**: `history` 字段传入之前的会话历史(从状态文件读取),实现多轮对话。
#### Step 4: 解析 SSE 事件
用 Python 脚本解析 SSE 流(比 bash while read 更可靠):
```python
#!/usr/bin/env python3
"""解析 AI Chat SSE 流并格式化输出"""
import sys, json
full_content = ""
tool_calls = []
for line in sys.stdin:
line = line.strip()
if not line.startswith("data:"):
continue
data_str = line[5:].strip()
if not data_str:
continue
try:
event = json.loads(data_str)
except json.JSONDecodeError:
continue
evt_type = event.get("type", "")
if evt_type == "content":
chunk = event.get("content", "")
full_content += chunk
# 实时输出内容片段
sys.stdout.write(chunk)
sys.stdout.flush()
elif evt_type == "tool_call":
tc = event.get("tool_call", {})
tool_name = tc.get("name", "unknown")
tool_args = tc.get("arguments", {})
tool_id = tc.get("id", "")
tool_calls.append({"id": tool_id, "name": tool_name})
# 输出工具调用标记
args_str = json.dumps(tool_args, ensure_ascii=False)
if len(args_str) > 200:
args_str = args_str[:200] + "..."
print(f"\n🔧 Tool Call: {tool_name}", file=sys.stderr)
print(f" Args: {args_str}", file=sys.stderr)
elif evt_type == "tool_result":
tr = event.get("tool_result", {})
tool_name = tr.get("name", "unknown")
content = tr.get("content", "")
is_error = tr.get("is_error", False)
# 截断长结果
if len(content) > 500:
content = content[:500] + f"... ({len(content)} chars total)"
status = "❌ Error" if is_error else "✅ Result"
print(f" {status} [{tool_name}]: {content}", file=sys.stderr)
elif evt_type == "done":
usage = event.get("usage") or {}
prompt_t = usage.get("prompt_tokens", 0)
completion_t = usage.get("completion_tokens", 0)
total_t = usage.get("total_tokens", 0)
print(f"\n\n--- Done ---", file=sys.stderr)
if total_t > 0:
print(f"Tokens: {prompt_t} prompt + {completion_t} completion = {total_t} total", file=sys.stderr)
if tool_calls:
print(f"Tool calls: {len(tool_calls)} ({', '.join(tc['name'] for tc in tool_calls)})", file=sys.stderr)
elif evt_type == "error":
err = event.get("error", "unknown error")
print(f"\n❌ Error: {err}", file=sys.stderr)
# 输出换行
print()
# 将 full_content 输出到 fd 3 用于状态更新(如果 fd 3 打开)
try:
with open("/tmp/ai-chat-response.txt", "w") as f:
f.write(full_content)
except:
pass
```
#### Step 5: 更新会话历史
发送完成后,将用户消息和 AI 回复追加到状态文件的 `history` 数组中:
```json
[
{"role": "user", "content": "<用户消息>"},
{"role": "assistant", "content": "<AI 完整回复>"}
]
```
#### 完整 bash 执行流程
```bash
#!/usr/bin/env bash
set -euo pipefail
MSG="$1"
STATE_FILE="/tmp/ai-chat-state.json"
# 1. 读取状态
if [ -f "$STATE_FILE" ]; then
STATE=$(cat "$STATE_FILE")
else
STATE='{"env":"local","history":[]}'
fi
ENV=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('env','local'))")
TOKEN=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('token',''))")
TOKEN_ENV=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('token_env',''))")
HISTORY=$(echo "$STATE" | python3 -c "import json,sys; print(json.dumps(json.load(sys.stdin).get('history',[])))")
# 2. 确定 URL
if [ "$ENV" = "staging" ]; then
AUTH_URL="http://39.105.150.219:7089"
AI_URL="http://39.105.150.219:7092"
else
AUTH_URL="http://localhost:7089"
AI_URL="http://localhost:7092"
fi
# 3. 获取 token(如果需要)
if [ -z "$TOKEN" ] || [ "$TOKEN_ENV" != "$ENV" ]; then
echo "🔐 Logging in to $ENV environment..."
LOGIN_RESP=$(curl -s -X POST "$AUTH_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"lining_admin","password":"admin123"}')
TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('access_token',d.get('data',{}).get('access_token','')))")
if [ -z "$TOKEN" ]; then
echo "❌ Login failed: $LOGIN_RESP"
exit 1
fi
echo "✅ Login successful"
# 更新状态中的 token
STATE=$(echo "$STATE" | python3 -c "
import json,sys
s=json.load(sys.stdin)
s['token']='$TOKEN'
s['token_env']='$ENV'
print(json.dumps(s,ensure_ascii=False))
")
fi
# 4. 发送 SSE 请求并解析
echo ""
echo "📤 Sending to $ENV: $MSG"
echo "---"
# 转义消息中的特殊字符
MSG_JSON=$(python3 -c "import json; print(json.dumps('$MSG'))")
curl -s -N -X POST "$AI_URL/api/v1/ai/chat/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"message\":$MSG_JSON,\"history\":$HISTORY}" 2>&1 | python3 -c "
import sys, json
full_content = ''
tool_calls = []
for line in sys.stdin:
line = line.strip()
if not line.startswith('data:'):
continue
data_str = line[5:].strip()
if not data_str:
continue
try:
event = json.loads(data_str)
except json.JSONDecodeError:
continue
evt_type = event.get('type', '')
if evt_type == 'content':
chunk = event.get('content', '')
full_content += chunk
sys.stdout.write(chunk)
sys.stdout.flush()
elif evt_type == 'tool_call':
tc = event.get('tool_call', {})
tool_name = tc.get('name', 'unknown')
tool_args = tc.get('arguments', {})
tool_calls.append({'name': tool_name})
args_str = json.dumps(tool_args, ensure_ascii=False)
if len(args_str) > 200:
args_str = args_str[:200] + '...'
print(f'\n🔧 Tool Call: {tool_name}', file=sys.stderr)
print(f' Args: {args_str}', file=sys.stderr)
elif evt_type == 'tool_result':
tr = event.get('tool_result', {})
tool_name = tr.get('name', 'unknown')
content = tr.get('content', '')
is_error = tr.get('is_error', False)
if len(content) > 500:
content = content[:500] + f'... ({len(content)} chars total)'
status = '❌' if is_error else '✅'
print(f' {status} [{tool_name}]: {content}', file=sys.stderr)
elif evt_type == 'done':
usage = event.get('usage') or {}
pt = usage.get('prompt_tokens', 0)
ct = usage.get('completion_tokens', 0)
tt = usage.get('total_tokens', 0)
print(f'\n\n--- Done ---', file=sys.stderr)
if tt > 0:
print(f'Tokens: {pt} prompt + {ct} completion = {tt} total', file=sys.stderr)
if tool_calls:
names = ', '.join(tc['name'] for tc in tool_calls)
print(f'Tool calls: {len(tool_calls)} ({names})', file=sys.stderr)
elif evt_type == 'error':
err = event.get('error', 'unknown error')
print(f'\n❌ Error: {err}', file=sys.stderr)
print()
with open('/tmp/ai-chat-response.txt', 'w') as f:
f.write(full_content)
"
# 5. 更新历史
RESPONSE=$(cat /tmp/ai-chat-response.txt 2>/dev/null || echo "")
python3 -c "
import json
state_file = '$STATE_FILE'
try:
with open(state_file) as f:
state = json.load(f)
except:
state = {'env': 'local', 'history': []}
msg = $MSG_JSON
resp = '''$RESPONSE'''
state['history'].append({'role': 'user', 'content': msg})
if resp:
state['history'].append({'role': 'assistant', 'content': resp})
state['token'] = '$TOKEN'
state['token_env'] = '$ENV'
with open(state_file, 'w') as f:
json.dump(state, f, ensure_ascii=False, indent=2)
"
echo ""
echo "💬 History: $(echo "$STATE" | python3 -c "import json,sys; h=json.load(sys.stdin).get('history',[]); print(len(h)//2 + 1)") messages in session"
```
**重要注意事项**
- 上面的脚本是逻辑参考,**不要**原样执行。Claude Code 应按步骤逐一执行 bash 命令。
- 消息中的引号和特殊字符需要用 python3 json.dumps 转义。
- 如果 token 过期(401 响应),自动重新登录。
- SSE 超时设置 `--max-time 120`
---
### /ai-chat tools
**列出当前环境已注册的工具。**
用法:
- `/ai-chat tools` — 列出所有工具
- `/ai-chat tools <category>` — 按分类过滤
实现步骤:
1. 读取状态获取环境和 token(必要时先登录)
2. 发送请求:
```bash
# 列出所有工具
curl -s "$AI_URL/api/v1/ai/tools" \
-H "Authorization: Bearer $TOKEN"
# 按分类过滤
curl -s "$AI_URL/api/v1/ai/tools?category=order" \
-H "Authorization: Bearer $TOKEN"
```
3. 响应格式:
```json
{
"tools": [
{
"name": "list_orders",
"description": "查询订单列表",
"category": "order",
"enabled": true,
"parameters": {...}
}
]
}
```
4. 按 category 分组,输出表格:
```
📋 AI Tools (142 total)
order (15 tools)
├── list_orders 查询订单列表
├── get_order_detail 获取订单详情
└── ...
product (12 tools)
├── list_products 查询商品列表
└── ...
```
已知工具分类:order, product, sku, inventory, task, brand, requirement, customer, dashboard, distribution, finance, discount, channel, approval, organization, feature_gap
---
### /ai-chat config
**查看 AI 服务配置。**
实现步骤:
1. 根据当前环境读取对应配置文件:
- **local**: 读取 `ai-service/api/etc/ai-api-local.yaml`
- **staging**: SSH 到 staging 读取 `/opt/coolbuy/configs/ai-api.yaml`
2. 显示关键配置项:
- AI Provider 和 Model
- 各工具分类的开关状态
- API 端口
3. 输出格式:
```
⚙️ AI Config (local)
Provider: deepseek
Model: deepseek-chat
Port: 7092
Tool Categories:
✅ order ✅ product ✅ sku
✅ inventory ✅ task ✅ brand
✅ requirement ✅ customer ✅ dashboard
✅ distribution ✅ finance ✅ discount
✅ channel ✅ approval ✅ organization
✅ feature_gap
```
---
### /ai-chat history
**显示当前会话的历史消息。**
实现步骤:
1. 读取 `/tmp/ai-chat-state.json``history` 数组
2. 按时间顺序显示:
```
💬 Chat History (3 messages)
[1] 👤 User: 你好
🤖 AI: 你好!我是 AI 助手...
[2] 👤 User: 搜索组织架构找到大客户部
🤖 AI: 我来帮你搜索... (used: search_organizations)
[3] 👤 User: 最近的订单
🤖 AI: 以下是最近的订单列表...
```
3. 如果需要清空历史:`/ai-chat history clear`
- 删除状态文件中的 history 数组,重置为空
---
## SSE Event Format Reference
AI Chat SSE 流使用 `event: message` + `data: {json}` 格式:
| type | 数据字段 | 说明 |
|------|---------|------|
| `content` | `content: "<text>"` | 增量文本内容 |
| `tool_call` | `tool_call: {id, name, arguments}` | AI 请求调用工具 |
| `tool_result` | `tool_result: {tool_call_id, name, content, is_error}` | 工具执行结果 |
| `done` | `usage: {prompt_tokens, completion_tokens, total_tokens}` (可能为 null), `finish_reason` | 流结束 |
| `error` | `error: "<message>"` | 错误 |
---
## Troubleshooting
### Token 过期 (401)
如果请求返回 401,删除缓存 token 重新登录:
```bash
# 清除 token 强制重新登录
python3 -c "
import json
with open('/tmp/ai-chat-state.json') as f: s=json.load(f)
s['token']=''
with open('/tmp/ai-chat-state.json','w') as f: json.dump(s,f)
"
```
### 连接失败
- **local**: 确认本地服务已启动 (`./scripts/start_dev.sh`)
- **staging**: 确认 staging 服务运行中 (`ssh coolbuy-staging "docker ps | grep ai-service"`)
### SSE 流中断
- 检查 AI 服务日志
- local: 查看终端输出
- staging: `ssh coolbuy-staging "docker logs coolbuy-ai-service --tail 50"`
### 消息中包含特殊字符
务必用 `python3 -c "import json; print(json.dumps(msg))"` 转义消息内容,避免 JSON 解析失败。
@@ -0,0 +1,11 @@
{
"name": "ai-proj-cicd-release-plugin",
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "ai-proj-cicd-release",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,73 @@
---
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.
---
# AI-Proj CI/CD release
Use the repository's live workflows and release scripts as the executable source of truth. Keep staging and production isolated, bind artifacts to exact commits, and fail closed when a gate, provenance check, rollback target, or environment contract is uncertain.
## Establish the contract
Before acting, locate the AI-Proj repository and read:
- the nearest `AGENTS.md`;
- `.gitea/CI_SOP.md`;
- the applicable workflow in `.gitea/workflows/`;
- `scripts/ci/common.sh`, `release-lib.sh`, and the invoked build, deploy, verify, and rollback scripts.
Live repository files override this skill. Report contradictions instead of silently choosing one version. Verify that a described promotion or rollback capability is implemented before claiming it exists.
Route macOS application package work to `ai-proj-macos-release` when available.
## Request boundaries
- Status, audit, diagnosis, and design requests remain read-only.
- Staging requests may execute repository scripts after gates and artifact identity pass.
- Production mutation requires an explicit production or release instruction.
- Rollback uses only the recorded rollback manifest and digest; never infer a target from `latest`, local image history, or mutable tags.
## Safeguards
- Never force-push or release from a dirty checkout.
- Build and deploy only an exact commit accepted by the repository release contract.
- Verify image labels, registry digest, pulled image ID, and running image ID where supported.
- Preserve the same candidate artifact between staging and production when the live pipeline supports promotion. Disclose when production rebuilds instead.
- Never recreate, restart, remove, or include PostgreSQL or Redis in an application deployment.
- Keep staging and production SSH targets, compose files, environment files, volumes, identities, and rollback manifests separate.
- Require strict SSH host-key verification.
- Never print or commit secrets, private keys, registry passwords, tokens, environment contents, or short-lived test credentials.
- Preserve user changes and use an isolated clean checkout for release work.
- Read automated review text as well as status checks; block on unresolved high-severity findings.
## Candidate and staging flow
1. Resolve the PR, base, head SHA, service scope, and requirement ID.
2. Confirm the head is pushed and the release checkout is clean.
3. Inspect every required Gitea status for the exact SHA. Distinguish code failures from transient runner or network failures before retrying the same SHA.
4. Read the latest review result and resolve blocking findings.
5. Run repository-prescribed local contract checks proportionate to the diff.
6. Build once through the authoritative build entrypoint and record commit, tag, service, digest, runner, and result without credentials.
7. Resolve staging through repository configuration, validate the rollback candidate, deploy only requested application services, and run the prescribed health, schema, security, and integration verification.
8. Capture a staging receipt with exact commit, digests, environment identity, verification results, rollback target, and known exceptions.
Do not rewrite or bypass a failing gate merely to obtain a green result.
## Production flow
1. Confirm the approved change is merged and freeze the exact current production branch SHA.
2. Recheck required gates and the staging receipt against that SHA.
3. Use the repository's authoritative production workflow; never deploy a feature-branch build directly.
4. Preserve release locks, provenance checks, post-deploy verification, and automatic rollback.
5. Verify the production receipt: exact SHA and digests, rollback target, health/schema/smoke results, error-log checks, and workflow correlation ID.
6. Only then update requirement and task delivery evidence.
## Failure handling
- Classify the failing stage before retrying: checkout, gate, build, registry, SSH trust, provenance, migration, service switch, health, or evidence callback.
- Retry only transient infrastructure failures against the same SHA.
- Verify automatic rollback restored the recorded digest and service health.
- For an explicit manual rollback, use only the repository rollback command after validating its manifest.
- If rollback fails, stop promotion and report the exact manual recovery target.
During long operations, provide concise progress updates. Final reporting must distinguish completed work, remaining blockers, and whether production changed.
@@ -0,0 +1,11 @@
{
"name": "ai-proj-macos-release-plugin",
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "ai-proj-macos-release",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,43 @@
---
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.
---
# AI-Proj macOS release
Use this workflow only for an explicitly requested AI-Proj macOS package release. Repository scripts and current project instructions are authoritative; stop and report any contradiction.
## Resolve the release contract
Before building, read the nearest `AGENTS.md`, the desktop package configuration, and the repository's macOS build, publish, and verification scripts. Resolve from those files:
- application version and architecture;
- production API configuration;
- signing identity and notarization mechanism;
- object-storage bucket, endpoint, release prefix, and public manifest;
- required website or download-manifest fallback version.
Do not copy machine-specific credential paths or identifiers into source control. Use the operator's configured secure credential provider without printing secret values.
## Release flow
1. Confirm the requested release version is unused. Keep package metadata, native application metadata, artifact filename, public manifest, and website fallback aligned.
2. Use a clean checkout of the exact approved commit. Run the repository's production desktop build script with the production API mode.
3. Require a valid Developer ID signature. If the repository's default notarization profile is unavailable, use another already-authorized App Store Connect credential source only after confirming its key, key ID, and issuer belong together.
4. Submit the final package to Apple notarization, wait for acceptance, staple the ticket, and validate it.
5. Mount the package read-only and verify the nested application with `codesign`, `spctl`, and the repository's smoke checks. Require Gatekeeper to report a notarized Developer ID.
6. Publish through the repository script. Use its configured object-storage credentials and upload mode; never handcraft a mutable public path when the script provides immutable versioned objects.
7. Require remote read-back verification of size and SHA-256. Upload artifacts first and update the public manifest last.
8. Download the public artifact independently and repeat signature, notarization, Gatekeeper, size, and checksum verification.
9. Confirm the manifest's latest version and asset URL, then update the website entry if the request includes it.
## Failure boundaries
- Missing signing or storage credentials: stop and report the missing configured provider; do not search broadly through personal files.
- Notarization authentication failure: stop and correct the credential tuple; never publish an unnotarized package.
- Gatekeeper reports an unnotarized or invalid application: do not publish.
- Upload stalls or fails: use only an alternative mode supported by the repository script, then repeat remote checksum verification.
- A public version already exists: do not overwrite it unless the user explicitly authorizes replacement and the repository permits it.
- Never expose signing keys, API keys, keychain passwords, storage credentials, or token values in logs, commits, manifests, or bundles.
Record the exact commit, version, artifact checksum and size, Apple result, public URL, manifest result, and verification outcome. Do not mark the release complete until the independently downloaded artifact passes all checks.
@@ -2,5 +2,10 @@
"name": "db-migration-plugin",
"description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时激活。",
"version": "1.0.0",
"author": { "name": "qiudl" }
"author": {
"name": "qiudl"
},
"install_name": "db-migration",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,11 @@
{
"name": "defect-analysis-plugin",
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
"version": "1.1.0",
"author": {
"name": "qiudl"
},
"install_name": "defect-analysis",
"install_type": "command",
"dir_category": "dev"
}
@@ -0,0 +1,161 @@
---
name: defect-analysis
description: 系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。
---
# 设计缺陷分析 Skill(通用版)
你是资深架构审计师。对给定的需求方案或代码实现,执行系统性的多维度缺陷检查,**反复迭代直到收敛**(连续一轮无新发现即停止)。
## 检查维度(按严重度排序)
### 1. 致命级:架构不可行
- **异步/同步冲突**:异步操作被当作同步使用?长时间操作阻塞了请求?
- **框架限制**v-html 无法绑定事件、WebSocket/SSE 超时、API 轮数限制
- **数据格式不匹配**:前后端约定的 ID 格式/字段名/序列化方式不一致?
- **循环依赖**:模块 A 内部调 B,B 又依赖 A 的结果?嵌套调用超时?
### 2. 高级:运行时崩溃
- **资源生命周期**DB session/连接/文件句柄在回调中过期?
- **并发冲突**:多个异步操作同时修改共享状态?用户操作和自动流程冲突?
- **超时/死锁**:链式调用累计超时?轮询无限等待?重试风暴?
- **内存泄漏**:大数据未释放?事件监听器未清理?闭包持有旧引用?
### 3. 中级:数据错误
- **状态覆盖**:多次回调覆盖同一变量?最后一次覆盖前面的?
- **上下文丢失**:对话/会话截断导致关键信息丢失?
- **参数传递断裂**:A 组件的输出无法完整传递给 B 组件?
- **类型不安全**JSON.parse 可能失败?nullable 字段未处理?双重编码?
- **初始化缺失**:变量未赋初值?首次使用时为 undefined/NaN
### 4. 低级:体验/维护问题
- **重复触发**watcher/callback 多次触发同一操作?
- **维护成本**:硬编码路径/行号/ID 需要手动同步?
- **XSS/注入**:用户输入或外部输出被直接渲染为 HTML?
- **状态清理**:组件卸载/页面切换时未清理进行中的请求/定时器?
## 检查流程
1. **读取方案描述**(需求文档或代码)
2. **画数据流图**(从用户操作 → 前端 → API → 后端 → DB/外部服务 → 返回)
3. **沿数据流逐节点检查**:每个节点问 5 个问题:
- 输入从哪来?可能为 null/异常吗?
- 输出给谁?接收方能处理所有情况吗?
- 耗时多久?会超时吗?
- 资源(session/连接/监听器)何时释放?
- 并发执行 N 次会怎样?
4. **检查边界**
- 前后端交界(API 格式/认证/超时/序列化)
- 同步/异步交界(await/callback/轮询/SSE
- 组件生命周期交界(mount/unmount/路由切换)
- AI/LLM 输出交界(结构化 vs 自由文本,幻觉风险,token 限制)
5. **从用户旅程检查**
- 首次使用(服务未就绪?数据为空?)
- 正常使用(N 次重复操作后状态累积?)
- 异常使用(断网/超时/并发/快速切换)
- 边界数据(空列表/超大数据/特殊字符)
## 迭代收敛规则
- 每轮检查一个维度,输出发现的缺陷列表
- 如果某轮发现 0 个新缺陷 → **收敛,停止**
- 如果 5 轮后仍有新发现 → 继续;20 轮作为阶段复盘点,不得误报为已收敛
- 达到 20 轮仍有新发现时,汇总剩余风险面并请求用户确认是否继续;用户已明确要求持续审计时可继续下一阶段
- 只有出现一轮 0 个新缺陷时才标记收敛;达到授权范围、时间或预算边界时应报告“尚未收敛”,不得伪装完成
- 每个缺陷标注严重度和轮次
## 输出格式
对每个缺陷:
```
### 缺陷 #N: {标题}{致命/高/中/低}
**问题**{一句话描述}
**场景**{触发条件}
**后果**{不修复会怎样}
**解决**{具体方案}
**验收**:- [ ] {如何确认已修复}
```
最后输出汇总表:
```
| 轮次 | 维度 | 缺陷数 | 关键发现 |
|---|---|---|---|
| 1 | 架构 | N | ... |
| ... | ... | ... | ... |
| K | 收敛 | 0 | 无新发现 |
```
## 端到端验证方法论
设计方案发现的缺陷可能在实际运行时不存在,反之亦然。对关键功能执行以下分层验证:
### 层 1:单元验证(后端隔离测试)
直接调用目标函数,绕过 API/前端,确认核心逻辑可用:
```python
# 示例:验证 AI 工具是否正常返回数据
docker exec app python3 -c "
import asyncio, json
from app.services.ai_tools import ai_tool_registry
from app.models.base import async_session_factory
async def test():
async with async_session_factory() as db:
result = await ai_tool_registry.execute('tool_name', {args}, user_id=1, db=db)
print(json.loads(result))
asyncio.run(test())
"
```
**如果这层失败**:代码逻辑错误或依赖缺失。
### 层 2:AI 行为验证(LLM 是否正确调用工具)
直接调用 AI 非流式接口,验证 LLM 是否输出了预期的工具调用标签:
```python
# 示例:验证 DeepSeek 是否输出 [TOOL_CALL]
result = await ai_gateway.chat([
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "分析回测 LB-xxx"}
])
print("[TOOL_CALL] found:", "[TOOL_CALL]" in result["content"])
```
**如果这层失败**SYSTEM_PROMPT 不够强,LLM 不遵循指令。加"必须"/"绝不能"等强制词。
### 层 3:SSE 流式验证(前后端数据管道)
用 curl 模拟前端 SSE 请求,检查事件流格式:
```bash
curl -N "http://localhost:8000/api/ai/chat" \
-H "Authorization: Bearer $TOKEN" \
-d '{"message":"测试","model":"v3"}' | head -20
```
检查是否有 `type: "tool_call"``type: "tool_result"` 事件。
**如果这层失败**:SSE 流解析/工具执行/事件格式问题。
### 层 4:前端渲染验证(浏览器实际效果)
打开 F12 → Network → 找到 SSE 请求 → EventStream 选项卡:
-`tool_call` 事件?→ 后端正常
-`tool_result` 事件?→ 工具执行正常
- 页面渲染了结果?→ 前端正常
**如果这层失败**:前端缓存(Cmd+Shift+R)、v-html 渲染、事件委托问题。
### 层 5:部署验证(CI/CD + 远端环境)
```bash
# 检查 CI 绿否
gh run list --limit 1 --branch main
# 检查远端容器是否加载了新代码
ssh server "docker exec app grep 'key_function' /app/path/to/file.py"
# 检查远端日志
ssh server "docker logs app 2>&1 | tail -20"
```
**如果这层失败**PR 未合并、CI 失败、Docker 缓存旧镜像、.env 缺配置。
### 常见的"设计没问题但实际不工作"的原因
| 症状 | 通常原因 | 排查方法 |
|---|---|---|
| AI 不调用工具 | SYSTEM_PROMPT 用"可以"而非"必须" | 层 2 验证 |
| 工具返回空 | DB 中无数据 / 权限隔离 user_id 不匹配 | 层 1 验证 |
| 前端无反应 | 浏览器缓存旧 JS / SSE 事件未解析 | 层 4 + Cmd+Shift+R |
| 远端不生效 | PR 未合并 / Docker 用了旧镜像 | 层 5 验证 |
| 数据格式错 | 双重 JSON 编码 / 字段名不一致 | 层 3 验证 |
| 按钮点不了 | v-html 无法绑 Vue 事件 | 层 4 + 事件委托 |
@@ -2,5 +2,10 @@
"name": "deploy-rollback-plugin",
"description": "回滚方案插件。部署后发现问题时的回滚策略、数据修复、灰度回退。挂载在 deploy 阶段。",
"version": "1.0.0",
"author": { "name": "qiudl" }
"author": {
"name": "qiudl"
},
"install_name": "deploy-rollback",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1 +1,11 @@
{"name":"dev-android-plugin","description":"Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}
{
"name": "dev-android-plugin",
"description": "Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。按需加载。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "dev-android",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-arch",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-cicd",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "2.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-coding",
"install_type": "skill",
"dir_category": "dev"
}
@@ -73,6 +73,72 @@ ai-proj task append-doc --id <taskId> --content "实现说明"
---
## Step 0:验证优先(Karpathy: Goal-Driven Execution
**编写任何代码前,必须先写验证脚本。** 规则来源:Karpathy "Goal-Driven Execution" 原则。
> "Define success criteria. Loop until verified."
> "Fix the bug" → "Write a test that reproduces it, then make it pass"
### 执行流程
```
① 写验证脚本(按类型选择)
② 运行一遍,确认全部 FAIL(证明功能确实不存在 / bug 确实存在)
③ 编码实现
④ 再次运行验证脚本,全部 PASS → 完成
```
### 后端验证脚本模板
实现 API 前,先写好所有 curl 命令并标注期望结果:
```bash
# 验证脚本:REQ-XXXX [功能名]
BASE="http://localhost:8080"
TOKEN="<JWT>"
echo "=== T1: 正常创建 ==="
curl -s -X POST "$BASE/api/v1/xxx" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"test"}' | jq '.code'
# 期望: 0
echo "=== T2: 缺少必填字段 ==="
curl -s -X POST "$BASE/api/v1/xxx" \
-H "Authorization: Bearer $TOKEN" \
-d '{}' | jq '.code'
# 期望: 非 0(参数错误)
echo "=== T3: 跨租户访问 ==="
curl -s -X GET "$BASE/api/v1/xxx/999" \
-H "Authorization: Bearer $TOKEN_OTHER_TENANT" | jq '.code'
# 期望: 403
```
**先运行 → 全部 FAIL → 编码 → 再次运行 → 全部 PASS**
### 前端验证脚本模板
实现页面前,先列出所有 `data-testid` 和期望的 DOM 状态:
```
验证清单(编码前先确认这些状态不存在 / 行为不正确):
- data-testid="xxx-btn-submit" 点击 → 列表刷新,行数增加 1
- data-testid="xxx-table" 行数 === API 返回 total
- data-testid="xxx-input-name" 空值提交 → 显示「请输入名称」提示
```
### 与 VP 三件套的关系
| VP 协议 | 验证优先对应 |
|---------|------------|
| VP-Data | 先在环境建好测试数据(curl 确认成功) |
| VP-Steps | **即为本节验证脚本** — 编码前写好,编码后执行 |
| VP-Pass | 验证脚本每条命令的期望输出值 |
---
## Go 后端开发
### 分层架构
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-commit",
"install_type": "skill",
"dir_category": "dev"
}
@@ -114,6 +114,48 @@ feat/REQ-xxx-i42 + commit → commit message 自动加 "closes #42"
确认提交?(y/n)
```
## Issue 集成规范(REQ-20260416-0017 P1-13
借鉴 devflow-claude 的 issue 关联机制。
### 分支名 `-iN` 后缀
当任务/需求来自 Gitea/GitHub issue 时,分支名末尾追加 `-iN`
```
feat/REQ-20260416-0017-user-points-i12 ← issue #12
fix/login-token-expired-i5 ← issue #5
```
**规则**
- `-iN` 仅当 issue 关联存在时追加
- `N` 为纯数字(不带 `#`
- 位于分支名最末尾
### commit message 自动追加 `closes #N`
当分支名含 `-iN` 后缀时,commit message 末尾自动追加 `closes #N`
```
feat(user): 实现积分规则管理 (REQ-20260416-0017) closes #12
fix(auth): 修复 token 过期未刷新 closes #5
```
**效果**PR 合并后 Gitea/GitHub 自动关闭关联 issue。
### Issue 编号读取优先级
| 优先级 | 来源 | 说明 |
|-------|------|------|
| 1 | `--from-issue=#N` 参数 | 用户显式指定 |
| 2 | 分支名 `-iN` 后缀 | 自动解析 `(-i(\d+))$` |
| 3 | MCP 需求文档关联的 issue | (预留) |
### 不触发的情况
- 分支名不含 `-iN` → 不追加 `closes`
- 用户显式说"不关联 issue" → 跳过
## 与 ai-proj 集成
- **查询当前需求**:通过 MCP `mcp__ai-proj__find_requirement``list_requirements` 找 user 进行中的
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-deploy",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-integration",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1 +1,11 @@
{"name":"dev-ios-plugin","description":"iOS 开发插件。Swift/SwiftUI + MVVM 架构、TestFlight 部署、Xcode 构建。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}
{
"name": "dev-ios-plugin",
"description": "iOS 开发插件。Swift/SwiftUI + MVVM 架构、TestFlight 部署、Xcode 构建。按需加载。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "dev-ios",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1 +1,11 @@
{"name":"dev-mcp-plugin","description":"MCP Bridge 开发插件。TypeScript MCP 服务开发、Token 管理、HTTP 客户端模式。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}
{
"name": "dev-mcp-plugin",
"description": "MCP Bridge 开发插件。TypeScript MCP 服务开发、Token 管理、HTTP 客户端模式。按需加载。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "dev-mcp",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1 +1,11 @@
{"name":"dev-pda-plugin","description":"PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先模式。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}
{
"name": "dev-pda-plugin",
"description": "PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先模式。按需加载。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "dev-pda",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-review",
"install_type": "skill",
"dir_category": "dev"
}
+31 -6
View File
@@ -1,13 +1,13 @@
---
name: dev-review
description: 代码评审技能。视角对抗性扫描法,用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。
description: 代码评审技能。视角对抗性扫描法(含 Karpathy Scope 审计),用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。
---
# 代码评审 Skill (dev-review)
## 概述
独立的代码评审技能,核心方法论是**视角对抗性扫描法**。
独立的代码评审技能,核心方法论是**视角对抗性扫描法**(五个传统安全/健壮性视角 + Karpathy Scope 审计视角)
**适用场景**
- `/req cr [REQ-ID]` — 需求流程中的代码评审阶段
@@ -22,7 +22,7 @@ description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码
| 上游 | 本技能输入 | 本技能输出 | 下游 |
|------|-----------|-----------|------|
| dev-coding | PR diff + 开发设计文档 | CR 报告(视角扫描 + 发现汇总 + 结论) | dev-test |
| dev-coding | PR diff + 开发设计文档 | CR 报告(视角扫描 + 发现汇总 + 结论) | dev-test |
---
@@ -67,7 +67,7 @@ description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码
---
## 视角对抗性扫描法
## 视角对抗性扫描法
### 总览
@@ -146,6 +146,28 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
- [ ] Redis 不可用时是否有降级方案?(缓存穿透到数据库)
- [ ] token 过期/刷新逻辑是否正确?(access vs refresh 不同策略)
### 视角6Scope 审计者(Karpathy: Simplicity + Surgical
**思维模式**:每一行变更,需求有没有要求它?
> "Touch only what you must. Clean up only your own mess."
> "Every changed line should trace directly to the user's request."
扫描清单:
- [ ] diff 中变更的**每个文件**,是否都在 req-design 变更文件清单中?(超出清单 = 疑似顺手重构)
- [ ] 新增的函数/方法/结构体,每个都有对应 AC 需要它?
- [ ] 是否引入了"未来可能用到"的参数、配置项、可选字段、接口抽象?
- [ ] 是否修改了本次 AC 无关的注释、格式、变量名、import 顺序?
- [ ] 代码量是否合理?实现简单 AC 超过 200 行须说明必要性
"If you write 200 lines and it could be 50, rewrite it"
- [ ] 错误处理是否只覆盖真实会发生的场景?不为不可能的情况写防御代码
**典型发现示例**
```
backend/services/user_service.go:45 — 新增了 WithRetry 参数,但 AC 中无重试需求。
建议:移除该参数,AC 有需要时再添加。严重度:Low
```
---
## CR 报告模板
@@ -160,7 +182,7 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
### 变更概要
{1-3 句描述本次变更的目的和范围}
### 视角扫描结果
### 视角扫描结果
#### 1. 攻击者视角
{扫描发现,或 "未发现问题"}
@@ -177,6 +199,9 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
#### 5. 依赖者视角
{扫描发现,或 "未发现问题"}
#### 6. Scope 审计者视角(Karpathy
{扫描发现,或 "所有变更文件均在设计清单范围内,无过度实现"}
### 审查发现汇总
| # | 严重度 | 文件:行号 | 角 | 描述 | 建议 |
@@ -221,7 +246,7 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
| 文档存在 | CR 任务有附加文档 |
| 字数 | ≥ 500 字 |
| 代码引用 | 含 `file:line` 格式的引用 |
| 视角扫描 | 含全部 5 个视角章节 |
| 视角扫描 | 含全部 6 个视角章节(含 Scope 审计者) |
| 结论章节 | 含明确的通过/不通过结论 |
---
@@ -2,5 +2,10 @@
"name": "dev-scaffold-plugin",
"description": "模块脚手架插件。新建模块时自动生成分层代码骨架(Model/Repository/Service/Handler/Route)。挂载在 dev 阶段。",
"version": "1.0.0",
"author": { "name": "qiudl" }
"author": {
"name": "qiudl"
},
"install_name": "dev-scaffold",
"install_type": "skill",
"dir_category": "dev"
}
@@ -4,5 +4,8 @@
"version": "2.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "dev-test",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,11 @@
{
"name": "executing-plans-plugin",
"description": "Use when you have a written implementation plan to execute in a separate session with review checkpoints.",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "executing-plans",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,96 @@
---
name: executing-plans
description: Use when you have a written implementation plan to execute in a separate session with review checkpoints
---
# Executing Plans
## Overview
Load plan, review critically, create branch, execute tasks in batches, report for review between batches.
**Core principle:** Batch execution with checkpoints for architect review.
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
## The Process
### Step 1: Load and Review Plan
1. Read plan file
2. Review critically - identify any questions or concerns about the plan
3. If concerns: Raise them with your human partner before starting
4. If no concerns: Proceed to branch setup
### Step 2: Setup Branch
**Before any implementation, ensure proper branch isolation.**
1. Check if already on a feature branch for this task
2. If not, use `/pr start` to create one:
```bash
/pr start <type> <REQ-id> <name>
# Example: /pr start feature REQ-123 user-login
```
3. If no REQ-id available, ask user or create branch manually:
```bash
git fetch origin
git checkout -b <type>/<descriptive-name> origin/main
```
4. Confirm branch is ready before proceeding
**Branch types:** `feature`, `fix`, `refactor`
### Step 3: Create Tasks and Execute Batch
**Default: First 3 tasks**
1. Create TodoWrite tasks from plan
2. For each task in batch:
- Mark as in_progress
- Follow each step exactly (plan has bite-sized steps)
- Run verifications as specified
- Mark as completed
### Step 4: Report
When batch complete:
- Show what was implemented
- Show verification output
- Say: "Ready for feedback."
### Step 5: Continue
Based on feedback:
- Apply changes if needed
- Execute next batch
- Repeat until complete
### Step 6: Complete Development
After all tasks complete and verified:
- Announce: "I'm using the finishing-a-development-branch skill to complete this work."
- **REQUIRED SUB-SKILL:** Use superpowers:finishing-a-development-branch
- Follow that skill to verify tests, present options, execute choice
## When to Stop and Ask for Help
**STOP executing immediately when:**
- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
- Plan has critical gaps preventing starting
- You don't understand an instruction
- Verification fails repeatedly
**Ask for clarification rather than guessing.**
## When to Revisit Earlier Steps
**Return to Review (Step 1) when:**
- Partner updates the plan based on your feedback
- Fundamental approach needs rethinking
**Don't force through blockers** - stop and ask.
## Remember
- Review plan critically first
- **Create feature branch before implementation**
- Follow plan steps exactly
- Don't skip verifications
- Reference skills when plan says to
- Between batches: just report and wait
- Stop when blocked, don't guess
@@ -0,0 +1,11 @@
{
"name": "finishing-branch-plugin",
"description": "Use when implementation is complete and all tests pass - verifies and creates PR.",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "finishing-a-development-branch",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,104 @@
---
name: finishing-a-development-branch
description: Use when implementation is complete and all tests pass - verifies and creates PR
---
# Finishing a Development Branch
## Overview
Verify tests pass, then push and create PR.
**Core principle:** Verify tests → Create PR → Done.
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
## The Process
### Step 1: Verify Tests
**Before creating PR, verify tests pass:**
```bash
# Run project's test suite
npm test / cargo test / pytest / go test ./... / mvn test
```
**If tests fail:**
```
Tests failing (<N> failures). Must fix before completing:
[Show failures]
Cannot proceed with PR until tests pass.
```
Stop. Fix tests first.
**If tests pass:** Continue to Step 2.
### Step 2: Push and Create PR
Use the `/pr create` command which will:
1. **Check for existing PR first** - avoids duplicates
2. If PR exists: Report existing PR URL and skip
3. If no PR: Analyze commits, generate title/description, push, create PR
```bash
/pr create
```
**Duplicate prevention:** The `/pr create` command checks for existing open PRs on the current branch before creating a new one.
Report the PR URL when complete (whether existing or newly created).
### Step 3: Cleanup Worktree (if applicable)
Check if working in a worktree:
```bash
git worktree list | grep $(git branch --show-current)
```
If yes, ask user:
```
Worktree at <path>. Remove it now? (y/n)
```
If confirmed:
```bash
git worktree remove <worktree-path>
```
## Quick Reference
```
Tests Pass?
↓ yes
/pr create
PR URL returned
Cleanup worktree (optional)
Done
```
## Red Flags
**Never:**
- Create PR with failing tests
- Skip test verification
- Force-push without explicit request
**Always:**
- Verify tests before creating PR
- Use `/pr create` for consistent PR format
- Report the PR URL
## Integration
**Called by:**
- **executing-plans** (Step 6) - After all batches complete
**Uses:**
- **/pr create** - For pushing and PR creation
@@ -0,0 +1,11 @@
{
"name": "frontend-design-plugin",
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
"version": "1.0.1",
"author": {
"name": "qiudl"
},
"install_name": "frontend-design",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,695 @@
---
name: frontend-design
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.
arguments: "[component|page|storybook] <description>"
---
# Frontend Design 前端设计技能
创建高质量、有设计感的前端界面和组件,支持 Storybook 组件开发。
---
## 命令格式
| 命令 | 功能 | 示例 |
|------|------|------|
| `/frontend-design component <描述>` | 创建 React/Vue 组件 | `/frontend-design component 产品卡片` |
| `/frontend-design page <描述>` | 创建完整页面 | `/frontend-design page 登录页` |
| `/frontend-design storybook <描述>` | 创建带 Storybook 的组件 | `/frontend-design storybook 按钮组件` |
---
## 设计原则
### 1. 设计思维先行
在编码前,明确以下问题:
- **目的**:这个界面解决什么问题?谁在使用?
- **调性**:选择一个明确的美学方向
- **差异化**:什么让这个设计令人难忘?
### 2. 美学方向选择
| 风格 | 特点 | 适用场景 |
|------|------|----------|
| 极简主义 | 大量留白、精炼元素 | 工具类、专业平台 |
| 现代商务 | 清晰层次、专业配色 | 企业官网、B2B |
| 活力年轻 | 鲜艳色彩、动感动画 | 消费品、社交 |
| 奢华精致 | 深色调、金属质感 | 高端品牌、金融 |
| 自然有机 | 柔和曲线、自然色系 | 健康、环保 |
| 复古怀旧 | 经典字体、做旧质感 | 文化、艺术 |
| 未来科技 | 渐变、玻璃拟态 | 科技、创新 |
### 3. 避免的设计陷阱
**禁止使用**
- 过度使用的字体:Inter、Roboto、Arial
- 陈词滥调的配色:紫色渐变白底
- 千篇一律的布局
- 缺乏个性的通用组件
**应该追求**
- 独特的字体组合
- 有意图的配色方案
- 打破常规的布局
- 有记忆点的细节
---
## Storybook 组件开发
### 项目结构
```
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.stories.tsx
│ │ ├── Button.module.css
│ │ └── index.ts
│ ├── Card/
│ │ ├── Card.tsx
│ │ ├── Card.stories.tsx
│ │ ├── Card.module.css
│ │ └── index.ts
│ └── index.ts
├── styles/
│ ├── variables.css
│ ├── typography.css
│ └── animations.css
└── .storybook/
├── main.ts
└── preview.ts
```
### 组件模板
#### 1. 组件文件 (Component.tsx)
```tsx
import React from 'react';
import styles from './Component.module.css';
export interface ComponentProps {
/** 组件变体 */
variant?: 'primary' | 'secondary' | 'outline';
/** 尺寸 */
size?: 'sm' | 'md' | 'lg';
/** 是否禁用 */
disabled?: boolean;
/** 子元素 */
children: React.ReactNode;
/** 点击事件 */
onClick?: () => void;
}
export const Component: React.FC<ComponentProps> = ({
variant = 'primary',
size = 'md',
disabled = false,
children,
onClick,
}) => {
return (
<div
className={`${styles.component} ${styles[variant]} ${styles[size]}`}
data-disabled={disabled}
onClick={disabled ? undefined : onClick}
>
{children}
</div>
);
};
```
#### 2. Storybook Stories (Component.stories.tsx)
```tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Component } from './Component';
const meta: Meta<typeof Component> = {
title: 'Components/Component',
component: Component,
tags: ['autodocs'],
parameters: {
layout: 'centered',
docs: {
description: {
component: '组件描述文档',
},
},
},
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline'],
description: '组件变体样式',
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
description: '组件尺寸',
},
disabled: {
control: 'boolean',
description: '是否禁用',
},
},
};
export default meta;
type Story = StoryObj<typeof Component>;
/** 默认状态 */
export const Default: Story = {
args: {
children: '默认组件',
},
};
/** 主要变体 */
export const Primary: Story = {
args: {
variant: 'primary',
children: '主要按钮',
},
};
/** 次要变体 */
export const Secondary: Story = {
args: {
variant: 'secondary',
children: '次要按钮',
},
};
/** 不同尺寸 */
export const Sizes: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Component size="sm"></Component>
<Component size="md"></Component>
<Component size="lg"></Component>
</div>
),
};
/** 禁用状态 */
export const Disabled: Story = {
args: {
disabled: true,
children: '禁用状态',
},
};
```
#### 3. 样式文件 (Component.module.css)
```css
.component {
/* 基础样式 */
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
font-family: var(--font-sans);
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
/* 变体 */
.primary {
background: var(--color-primary);
color: white;
}
.primary:hover {
background: var(--color-primary-dark);
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--color-primary-shadow);
}
.secondary {
background: var(--color-secondary);
color: var(--color-text);
}
.outline {
background: transparent;
border: 2px solid var(--color-border);
color: var(--color-text);
}
/* 尺寸 */
.sm {
padding: 0.5rem 1rem;
font-size: 0.875rem;
}
.md {
padding: 0.75rem 1.5rem;
font-size: 1rem;
}
.lg {
padding: 1rem 2rem;
font-size: 1.125rem;
}
/* 状态 */
[data-disabled="true"] {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
```
---
## 设计系统变量
### CSS 变量模板
```css
:root {
/* 颜色 */
--color-primary: #0066ff;
--color-primary-dark: #0052cc;
--color-primary-light: #4d94ff;
--color-primary-shadow: rgba(0, 102, 255, 0.25);
--color-secondary: #f0f4f8;
--color-accent: #ff6b35;
--color-text: #1a1a2e;
--color-text-muted: #64748b;
--color-text-inverse: #ffffff;
--color-background: #ffffff;
--color-surface: #f8fafc;
--color-border: #e2e8f0;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* 字体 */
--font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-display: 'Clash Display', var(--font-sans);
--font-mono: 'JetBrains Mono', monospace;
/* 字号 */
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--text-4xl: 2.5rem;
/* 间距 */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
--space-16: 4rem;
/* 圆角 */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-xl: 1.5rem;
--radius-full: 9999px;
/* 阴影 */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
/* 动画 */
--duration-fast: 150ms;
--duration-normal: 300ms;
--duration-slow: 500ms;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* 暗色主题 */
[data-theme="dark"] {
--color-text: #f1f5f9;
--color-text-muted: #94a3b8;
--color-background: #0f172a;
--color-surface: #1e293b;
--color-border: #334155;
}
```
---
## 常用组件示例
### 1. 产品卡片 (ProductCard)
```tsx
// ProductCard.tsx
import React from 'react';
import styles from './ProductCard.module.css';
export interface ProductCardProps {
image: string;
title: string;
location: string;
rating: number;
reviewCount: number;
price: number;
originalPrice?: number;
tags?: string[];
onAddToCart?: () => void;
}
export const ProductCard: React.FC<ProductCardProps> = ({
image,
title,
location,
rating,
reviewCount,
price,
originalPrice,
tags = [],
onAddToCart,
}) => {
return (
<article className={styles.card}>
<div className={styles.imageWrapper}>
<img src={image} alt={title} className={styles.image} />
{tags.length > 0 && (
<div className={styles.tags}>
{tags.map((tag) => (
<span key={tag} className={styles.tag} data-tag={tag}>
{tag}
</span>
))}
</div>
)}
</div>
<div className={styles.content}>
<h3 className={styles.title}>{title}</h3>
<p className={styles.location}>📍 {location}</p>
<div className={styles.rating}>
<span className={styles.stars}> {rating.toFixed(1)}</span>
<span className={styles.reviewCount}>({reviewCount})</span>
</div>
<div className={styles.priceRow}>
<div className={styles.price}>
<span className={styles.currency}>¥</span>
<span className={styles.amount}>{price}</span>
<span className={styles.suffix}></span>
</div>
{originalPrice && (
<span className={styles.originalPrice}>¥{originalPrice}</span>
)}
</div>
<button className={styles.addButton} onClick={onAddToCart}>
</button>
</div>
</article>
);
};
```
```tsx
// ProductCard.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { ProductCard } from './ProductCard';
const meta: Meta<typeof ProductCard> = {
title: 'Components/ProductCard',
component: ProductCard,
tags: ['autodocs'],
parameters: {
layout: 'centered',
backgrounds: {
default: 'light',
},
},
};
export default meta;
type Story = StoryObj<typeof ProductCard>;
export const Default: Story = {
args: {
image: 'https://images.unsplash.com/photo-1494947665470-20322015e3a8',
title: '袋鼠岛一日游',
location: '阿德莱德出发',
rating: 4.8,
reviewCount: 126,
price: 389,
tags: ['热卖', '含午餐'],
},
};
export const WithDiscount: Story = {
args: {
...Default.args,
originalPrice: 499,
tags: ['特惠', '限时'],
},
};
export const Grid: Story = {
render: () => (
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 300px)',
gap: '1.5rem'
}}>
<ProductCard
image="https://images.unsplash.com/photo-1494947665470-20322015e3a8"
title="袋鼠岛一日游"
location="阿德莱德出发"
rating={4.8}
reviewCount={126}
price={389}
tags={['热卖']}
/>
<ProductCard
image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
title="巴罗莎谷酒庄之旅"
location="阿德莱德出发"
rating={4.9}
reviewCount={89}
price={299}
originalPrice={399}
tags={['特惠', '含品酒']}
/>
<ProductCard
image="https://images.unsplash.com/photo-1540202403-b7abd6747a18"
title="海豚巡航体验"
location="格雷尔海滩"
rating={4.7}
reviewCount={234}
price={159}
tags={['亲子']}
/>
</div>
),
};
```
### 2. 按钮组件 (Button)
```tsx
// Button.tsx
import React from 'react';
import styles from './Button.module.css';
export interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
fullWidth?: boolean;
loading?: boolean;
disabled?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
children: React.ReactNode;
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
fullWidth = false,
loading = false,
disabled = false,
leftIcon,
rightIcon,
children,
onClick,
}) => {
return (
<button
className={`
${styles.button}
${styles[variant]}
${styles[size]}
${fullWidth ? styles.fullWidth : ''}
`}
disabled={disabled || loading}
onClick={onClick}
>
{loading ? (
<span className={styles.spinner} />
) : (
<>
{leftIcon && <span className={styles.icon}>{leftIcon}</span>}
<span>{children}</span>
{rightIcon && <span className={styles.icon}>{rightIcon}</span>}
</>
)}
</button>
);
};
```
---
## Storybook 配置
### .storybook/main.ts
```ts
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
```
### .storybook/preview.ts
```ts
import type { Preview } from '@storybook/react';
import '../src/styles/variables.css';
import '../src/styles/typography.css';
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#ffffff' },
{ name: 'gray', value: '#f8fafc' },
{ name: 'dark', value: '#0f172a' },
],
},
},
globalTypes: {
theme: {
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
title: 'Theme',
icon: 'circlehollow',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
},
};
export default preview;
```
---
## 快速启动命令
### 创建新组件
```bash
# 创建组件目录
mkdir -p src/components/ComponentName
# 创建文件
touch src/components/ComponentName/{ComponentName.tsx,ComponentName.stories.tsx,ComponentName.module.css,index.ts}
```
### 安装 Storybook
```bash
# 初始化 Storybook
npx storybook@latest init
# 安装额外插件
npm install -D @storybook/addon-a11y @storybook/addon-interactions
# 启动 Storybook
npm run storybook
```
---
## 设计检查清单
### 组件质量检查
- [ ] Props 接口定义完整,带 JSDoc 注释
- [ ] 支持必要的变体(variant)和尺寸(size
- [ ] 处理禁用和加载状态
- [ ] 支持自定义 className
- [ ] 键盘可访问性
- [ ] 屏幕阅读器友好
### Storybook 质量检查
- [ ] 所有变体都有对应 Story
- [ ] argTypes 配置完整
- [ ] 包含组件文档描述
- [ ] 交互状态可测试
- [ ] 响应式展示
### 视觉质量检查
- [ ] 字体选择有特色
- [ ] 配色方案协调
- [ ] 动画流畅自然
- [ ] 间距一致
- [ ] 暗色主题支持
@@ -0,0 +1,11 @@
{
"name": "karpathy-guidelines",
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
"version": "1.0.1",
"author": {
"name": "qiudl"
},
"install_name": "karpathy-guidelines",
"install_type": "skill",
"dir_category": "dev"
}
@@ -0,0 +1,97 @@
---
name: karpathy-guidelines
description: Karpathy 四原则编码行为守则。减少 LLM 常见编码错误:过度实现、静默假设、顺手重构、无验证标准。在任意编码场景激活。
---
# Karpathy Guidelines Skill
> 来源:[andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills)
> 在本项目中已深度融合到 req 技能工作流各阶段。
## 四原则
### 1. Think Before Coding(编前推理)
> "Don't assume. Don't hide confusion. Surface tradeoffs."
**在写第一行代码前:**
- 显式列出本次实现的假设(数据格式、边界条件、依赖接口)
- 如存在多种解读,列出所有方案(附估算),不要静默选择
- 如有更简单的实现方式,说出来
- 遇到不清晰的地方,停下来,指出混乱点,提问
**在 req 工作流中:** → 已嵌入 `req-prd` 的「Phase 0 假设倾倒协议」
---
### 2. Simplicity First(简单优先)
> "Minimum code that solves the problem. Nothing speculative."
**禁止:**
- 添加未被需求要求的功能
- 为单次使用的代码添加抽象
- 添加未被请求的"灵活性"或"可配置性"
- 为不可能发生的场景写错误处理
- 写了 200 行但 50 行就够的代码 → 重写
**自检:** "一个高级工程师看这段代码会觉得过度设计吗?" 如果是 → 简化
**在 req 工作流中:** → 已嵌入 `req-design` 过度设计检查 + `dev-review` 第六视角
---
### 3. Surgical Changes(手术式修改)
> "Touch only what you must. Clean up only your own mess."
**修改现有代码时:**
- 不要"顺手改进"相邻代码、注释或格式
- 不要重构没有损坏的代码
- 匹配现有代码风格,即使你会做不同的选择
- 发现不相关的死代码 → 提及但不删除
**你的变更造成的孤儿:**
- 删除你的变更导致的无用 import/变量/函数
- 不要删除已存在的死代码(除非被要求)
**铁律:** diff 中每一行修改都应该可以追溯到用户的需求
**在 req 工作流中:** → 已嵌入 `dev-review` 第六视角 + `check-surgical.sh` Harness 脚本
---
### 4. Goal-Driven Execution(目标驱动执行)
> "Define success criteria. Loop until verified."
**将请求转化为可验证目标:**
- "加验证" → "为无效输入写测试,然后让它通过"
- "修 bug" → "写一个复现 bug 的测试,然后让它通过"
- "重构 X" → "确保测试在重构前后都通过"
**多步任务需要说明计划:**
```
1. [步骤] → 验证: [检查项]
2. [步骤] → 验证: [检查项]
3. [步骤] → 验证: [检查项]
```
**在 req 工作流中:** → 已嵌入 `dev-coding` 的「Step 0 验证优先」+ VP 三件套协议
---
## 与 req 工作流的映射
| 原则 | 生效阶段 | 落地机制 |
|------|---------|---------|
| Think Before Coding | req-prd 启动前 | Phase 0 假设倾倒协议 |
| Simplicity First | req-design + dev-review | 过度设计检查 + 第六视角 |
| Surgical Changes | dev-review + CI | 第六视角 + check-surgical.sh |
| Goal-Driven Execution | dev-coding | Step 0 验证优先 + VP 三件套 |
## 反模式速查
| 场景 | ❌ LLM 常犯 | ✅ 正确做法 |
|------|-----------|-----------|
| "做个导出功能" | 静默假设格式/字段,直接实现 | 列出3种解读,等用户确认 |
| "让搜索更快" | 同时加缓存+索引+async | 列出3种"更快"含义,确认再做 |
| "加折扣计算" | Strategy+Abstract+Enum50行 | 一个函数,3行 |
| "修空邮件bug" | 顺手加用户名校验+类型注解 | 只改空邮件的那2行 |
| "修认证bug" | 直接修改,无验证标准 | 先写复现测试,修复后验证通过 |
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "pull-request",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1,8 +1,11 @@
{
"name": "review-checklist-plugin",
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
"version": "1.0.0",
"version": "1.1.0",
"author": {
"name": "qiudl"
}
},
"install_name": "review-checklist",
"install_type": "skill",
"dir_category": "dev"
}
@@ -1,23 +0,0 @@
# 通用代码评审检查清单
适用于所有项目,补充五视角扫描法。
## API 设计
- [ ] RESTful 命名是否规范?(复数名词、无动词)
- [ ] 分页参数是否有默认值和上限?
- [ ] 响应格式是否统一?(code/message/data
## 错误处理
- [ ] 错误是否被正确传播?(不要吞掉错误)
- [ ] 用户可见的错误消息是否友好?(不暴露技术细节)
- [ ] 是否有 panic recover 兜底?
## 性能
- [ ] 列表查询是否有分页?(不允许无限制查询)
- [ ] N+1 查询问题?(循环内查数据库)
- [ ] 是否有不必要的全表扫描?(缺少索引)
## 可维护性
- [ ] 魔法数字是否提取为常量?
- [ ] 复杂业务逻辑是否有注释说明?
- [ ] 函数是否过长?(超过 100 行考虑拆分)
@@ -13,16 +13,17 @@ description: 项目级代码评审检查清单。按项目积累特定检查项
## 使用方式
1. `dev-review` 执行五视角扫描时,自动加载当前项目的检查清单
2. 扫描完成后,逐条检查清单项
3. 检查结果附加到 CR 报告的「项目检查清单」章节
1. `dev-review` 执行五视角扫描时,先读取 `references/general.md`
2. 如果仓库是 AI-Proj,读取 `references/ai-proj.md`;如果是 Coolbuy PaaS,读取 `references/coolbuy-paas.md`
3. 扫描完成后,逐条检查适用的清单项
4. 检查结果附加到 CR 报告的「项目检查清单」章节
## 检查清单文件
```
review-checklist-plugin/
├── skills/SKILL.md # 本文件
└── checklists/
review-checklist/
├── SKILL.md # 本文件
└── references/
├── ai-proj.md # AI-Proj 项目清单
├── coolbuy-paas.md # 酷采3.0 项目清单
└── general.md # 通用清单(所有项目适用)
@@ -32,7 +33,7 @@ review-checklist-plugin/
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
1. 打开对应项目的检查清单文件
1. 打开 `references/`对应项目的检查清单文件
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
3. 标注严重度和适用范围
@@ -18,6 +18,14 @@
- [ ] JWT token 类型是否区分 access/refresh?— 教训:token 混用导致安全漏洞
- [ ] bcrypt cost 是否使用 12?— 教训:默认 cost 10 导致登录失败
### 租户隔离(多企业安全,源自 REQ-20260711-0004
- [ ] 隔离/权限类修复是否枚举了威胁模型的**所有读取面**?— list 枚举 + 单条直读 + 按 ID/pattern 查 + count + 关联子查询。教训:P1 只修 list 面漏了 find_task/get-by-id 直读面,直读即绕过枚举防护,audit 才逮到高危残留
- [ ] 同一威胁在**镜像面**是否一并处理?— 一个对象类型(task)漏,同类(project/document/manual/history)大概率同漏
- [ ] MCP 裸 SQL(不走仓储层)是否应用 `ResolveTenantScope` / scope 片段?— SSE 面 list_tasks/list_projects 曾裸 SQL 无企业过滤
- [ ] context 注入的是**类型化 key**`EnterpriseIDContextKey{}`)而非字符串 key?— 字符串 key 与 `ResolveTenantScope` 读的类型化 key 不通,静默失效
- [ ] scope 解析不出 / 依赖为 nil 时是否 **fail-closed**(空哨兵拒绝)而非跳过(退化全量)?
- [ ] MCP endpoint 参数是否 snake_case + camelCase 双绑?— CLI 发 snake、bridge 发 camelgin 静默忽略不匹配参数(REQ-20260711-0003
### Redis
- [ ] Redis key 是否有 TTL?— 缺少 TTL 导致内存泄露
- [ ] Redis 不可用时是否降级到数据库?
@@ -37,6 +45,6 @@
## 通用
- [ ] `.env` 凭据文件是否被意外加入 git
- [ ] `.env` 凭据文件是否被意外加入 git
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
- [ ] 错误日志是否包含足够的上下文信息?(user_id, tenant_id, request_id
@@ -8,7 +8,7 @@
### 数据迁移
- [ ] 从酷采2.0迁移的字段映射是否正确?(varchar ID → bigint ID
- [ ] 迁移脚本是否处理了酷采2.0软删除标记(is_delete → deleted_at)?
- [ ] 迁移脚本是否处理了酷采2.0软删除标记(is_delete → deleted_at)?
## 前端(Vue 3 + Ant Design Vue
@@ -0,0 +1,46 @@
# 通用代码评审检查清单
每次代码审查都应加载本清单。
适用于所有项目,补充六视角扫描法(五传统视角 + Karpathy Scope 视角)。
## Karpathy 反模式速查(Scope 审计者视角辅助)
基于 [andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) EXAMPLES.md 提炼。
### ❌ 反模式 → ✅ 正确做法
| 场景 | 反模式(LLM 常犯) | 正确做法 |
|------|-----------------|---------|
| "做个导出功能" | 静默假设文件格式/字段/分页,直接实现 | 列出3种解读(API/文件/任务队列),问用户选哪种 |
| "让搜索更快" | 同时加缓存+索引+async200行 | 列出3种"更快"含义+估算,等确认再做 |
| "加个折扣计算" | Strategy+Abstract+Enum+DataClass50行 | `def calc_discount(amount, pct): return amount * pct / 100` |
| "修保存偏好的bug" | 顺手加 merge/validate/notify/cache | 只改最小范围,加注释"其他特性按需再加" |
| "修空邮件校验bug" | 顺手加用户名校验+类型注解+docstring | 只改空邮件的那2行 |
| "加日志到上传函数" | 改引号风格+加类型注解+重构return逻辑 | 只加日志,保持原有代码风格 |
| "修认证bug" | "我会检查代码并做改进"(无标准) | 先写测试复现bug,再实现修复,再跑测试 |
| "加限流" | 一次提交Redis+多策略+配置系统+监控 | 分4步,每步独立可验证可部署 |
### 触发关键词(出现时加强 Scope 审计)
`export/导出` `faster/更快` `manage/管理` `notify/通知` `fix/修复` `improve/改进` `refactor/重构` `add/添加`
## API 设计
- [ ] RESTful 命名是否规范?(复数名词、无动词)
- [ ] 分页参数是否有默认值和上限?
- [ ] 响应格式是否统一?(code/message/data
## 错误处理
- [ ] 错误是否被正确传播?(不要吞掉错误)
- [ ] 用户可见的错误消息是否友好?(不暴露技术细节)
- [ ] 是否有 panic recover 兜底?
## 性能
- [ ] 列表查询是否有分页?(不允许无限制查询)
- [ ] N+1 查询问题?(循环内查数据库)
- [ ] 是否有不必要的全表扫描?(缺少索引)
## 可维护性
- [ ] 魔法数字是否提取为常量?
- [ ] 复杂业务逻辑是否有注释说明?
- [ ] 函数是否过长?(超过 100 行考虑拆分)
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "data-excel",
"install_type": "skill",
"dir_category": "integration"
}
@@ -1,14 +1,11 @@
{
"name": "doubao-voice-plugin",
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
"version": "1.0.0",
"version": "1.0.1",
"author": {
"name": "qiudl"
},
"skills": [
{
"name": "doubao-voice",
"path": "./skills/SKILL.md"
}
]
"install_name": "doubao-voice",
"install_type": "skill",
"dir_category": "integration"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "feishu-bitable",
"install_type": "skill",
"dir_category": "integration"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "feishu-docx",
"install_type": "skill",
"dir_category": "integration"
}
@@ -4,5 +4,8 @@
"version": "1.1.0",
"author": {
"name": "qiudl"
}
},
"install_name": "feishu",
"install_type": "skill",
"dir_category": "integration"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "siyuan",
"install_type": "skill",
"dir_category": "integration"
}
+60 -150
View File
@@ -5,128 +5,35 @@ description: 思源笔记 API 集成。通过自然语言创建、编辑、搜
# 思源笔记 API 集成 Skill
## 服务配置
## 环境变量配置(必须)
### 阿里云生产环境 (推荐)
本 skill 通过环境变量读取思源笔记连接信息,不同用户/组织配置不同的值。
| 配置项 | 值 |
|--------|-----|
| 服务地址 | `https://siyuan.pipexerp.com` (HTTPS) |
| HTTP访问 | `http://47.93.23.182` (重定向到HTTPS) |
| SSH 别名 | `siyuan` |
| 访问码 | `SiYuan@2026` |
| 版本 | **3.1.11** (2026-02-16 升级) |
| 部署位置 | 阿里云 Ubuntu 24.04 (Docker) |
| 容器名称 | `siyuan` |
| 镜像 | `b3log/siyuan:v3.1.11` |
| 数据目录 | `/opt/siyuan/workspace` |
| 反向代理 | Caddy (HTTPS + SSL证书) |
| SSL证书 | Let's Encrypt (自动续期) |
**在 `~/.claude/settings.json` 中配置:**
### Tailscale 内网环境 (备用)
```json
{
"env": {
"SIYUAN_URL": "${SIYUAN_URL}",
"SIYUAN_TOKEN": "your-api-token-here"
}
}
```
| 配置项 | 值 |
|--------|-----|
| 服务地址 | `http://47.93.23.182` (Tailscale) |
| 局域网地址 | `http://192.168.1.50:6806` |
| API Token | `nfnycjb1g8vbexb2` |
| 版本 | 3.1.5 |
| 部署位置 | 飞牛OS (Docker) |
或在项目级 `.claude/settings.json` 中配置(优先级更高)。
**检查配置是否就绪:** 执行任何思源操作前,先确认环境变量已设置:
```bash
echo "URL: ${SIYUAN_URL:-未配置}"
echo "TOKEN: ${SIYUAN_TOKEN:+已配置}"
```
如果未配置,提示用户在 `~/.claude/settings.json``env` 中添加 `SIYUAN_URL``SIYUAN_TOKEN`
---
## 服务器管理 (阿里云)
### SSH 连接
```bash
# 快捷连接
ssh siyuan
# 完整连接命令
ssh -i /Users/donglinlai/Downloads/siyuan.pem root@47.93.23.182
```
### Docker 管理
```bash
# 查看容器状态
ssh siyuan "docker ps | grep siyuan"
# 查看日志
ssh siyuan "docker logs -f siyuan --tail 100"
# 重启服务
ssh siyuan "docker restart siyuan"
# 停止服务
ssh siyuan "docker stop siyuan"
# 启动服务
ssh siyuan "docker start siyuan"
# 升级到特定版本(推荐)
ssh siyuan "docker stop siyuan && docker rm siyuan"
ssh siyuan "docker pull b3log/siyuan:v3.1.11"
ssh siyuan "docker run -d --name siyuan --restart=always \
-p 127.0.0.1:6806:6806 \
-v /opt/siyuan/workspace:/siyuan/workspace \
-e LANG=en_US.UTF-8 \
b3log/siyuan:v3.1.11 \
--workspace=/siyuan/workspace \
--accessAuthCode=SiYuan@2026"
```
### 数据备份与恢复
```bash
# 查看数据目录大小
ssh siyuan "du -sh /opt/siyuan/workspace"
# 备份数据到服务器
ssh siyuan "tar -czf /root/siyuan-backup-\$(date +%Y%m%d).tar.gz /opt/siyuan/workspace"
# 下载备份到本地
scp siyuan:/root/siyuan-backup-*.tar.gz ~/Downloads/
# 恢复数据(先停止容器)
ssh siyuan "docker stop siyuan && \
tar -xzf /root/siyuan-backup-YYYYMMDD.tar.gz -C / && \
docker start siyuan"
```
### 访问测试
```bash
# 测试 HTTPS 访问
curl -I https://siyuan.pipexerp.com
# 测试认证 API
curl -s -X POST https://siyuan.pipexerp.com/api/system/version | jq .
# 浏览器访问
open https://siyuan.pipexerp.com
```
### Caddy 反向代理管理
```bash
# 查看 Caddy 状态
ssh siyuan "systemctl status caddy"
# 重启 Caddy
ssh siyuan "systemctl restart caddy"
# 查看 Caddy 配置
ssh siyuan "cat /etc/caddy/Caddyfile"
# 查看 SSL 证书
ssh siyuan "journalctl -u caddy | grep certificate"
```
---
## 🔐 保存门禁:敏感信息脱敏
## 🔐 保存禁:敏感息脱敏
**保存任何内容到思源笔记前,必须先完成脱敏处理。**
@@ -201,8 +108,8 @@ api.upsert_doc(notebook_id, "/文档路径", content)
所有 API 请求使用 POST 方法,需携带 Token
```bash
curl -X POST https://siyuan.pipexerp.com/api/xxx \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/xxx \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"param": "value"}'
```
@@ -239,8 +146,8 @@ curl -X POST https://siyuan.pipexerp.com/api/xxx \
#### 列出所有笔记本
```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/lsNotebooks \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/notebook/lsNotebooks \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{}'
```
@@ -248,8 +155,8 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/lsNotebooks \
#### 创建笔记本
```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/createNotebook \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/notebook/createNotebook \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"name": "笔记本名称"}'
```
@@ -257,8 +164,8 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/createNotebook \
#### 删除笔记本
```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/removeNotebook \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/notebook/removeNotebook \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID"}'
```
@@ -276,22 +183,22 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/removeNotebook \
```bash
# 1. 先查询是否存在(按路径精确匹配)
DOC_PATH="/网络管理/家庭Tailscale网络"
EXISTING=$(curl -s -X POST https://siyuan.pipexerp.com/api/query/sql \
-H "Authorization: Token nfnycjb1g8vbexb2" \
EXISTING=$(curl -s -X POST ${SIYUAN_URL}/api/query/sql \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"stmt\": \"SELECT id FROM blocks WHERE type='d' AND hpath='${DOC_PATH}' LIMIT 1\"}" \
| jq -r '.data[0].id // empty')
if [ -n "$EXISTING" ]; then
# 2a. 存在则更新
curl -s -X POST https://siyuan.pipexerp.com/api/block/updateBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -s -X POST ${SIYUAN_URL}/api/block/updateBlock \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"id\": \"${EXISTING}\", \"dataType\": \"markdown\", \"data\": \"# 更新的内容\"}"
else
# 2b. 不存在则创建
curl -s -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -s -X POST ${SIYUAN_URL}/api/filetree/createDocWithMd \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/网络管理/家庭Tailscale网络", "markdown": "# 新内容"}'
fi
@@ -300,8 +207,8 @@ fi
#### 创建文档 (仅新建时使用)
```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/filetree/createDocWithMd \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"notebook": "笔记本ID",
@@ -313,8 +220,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \
#### 获取文档内容
```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/getDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/filetree/getDoc \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"id": "文档ID"}'
```
@@ -322,8 +229,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/getDoc \
#### 删除文档
```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/removeDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/filetree/removeDoc \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/文档路径"}'
```
@@ -331,8 +238,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/removeDoc \
#### 重命名文档
```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/renameDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/filetree/renameDoc \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/旧路径", "title": "新标题"}'
```
@@ -344,8 +251,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/renameDoc \
#### 插入块
```bash
curl -X POST https://siyuan.pipexerp.com/api/block/insertBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/block/insertBlock \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dataType": "markdown",
@@ -357,8 +264,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/insertBlock \
#### 更新块
```bash
curl -X POST https://siyuan.pipexerp.com/api/block/updateBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/block/updateBlock \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dataType": "markdown",
@@ -370,8 +277,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/updateBlock \
#### 删除块
```bash
curl -X POST https://siyuan.pipexerp.com/api/block/deleteBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/block/deleteBlock \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"id": "块ID"}'
```
@@ -383,8 +290,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/deleteBlock \
#### 全文搜索
```bash
curl -X POST https://siyuan.pipexerp.com/api/search/fullTextSearchBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/search/fullTextSearchBlock \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "搜索关键词",
@@ -395,8 +302,8 @@ curl -X POST https://siyuan.pipexerp.com/api/search/fullTextSearchBlock \
#### SQL 查询
```bash
curl -X POST https://siyuan.pipexerp.com/api/query/sql \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/query/sql \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"stmt": "SELECT * FROM blocks WHERE content LIKE '\''%关键词%'\'' LIMIT 10"
@@ -410,8 +317,8 @@ curl -X POST https://siyuan.pipexerp.com/api/query/sql \
#### 导出 Markdown
```bash
curl -X POST https://siyuan.pipexerp.com/api/export/exportMdContent \
-H "Authorization: Token nfnycjb1g8vbexb2" \
curl -X POST ${SIYUAN_URL}/api/export/exportMdContent \
-H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"id": "文档ID"}'
```
@@ -421,13 +328,16 @@ curl -X POST https://siyuan.pipexerp.com/api/export/exportMdContent \
## Python 封装
```python
import os
import requests
from typing import Optional, Dict, Any
class SiYuanAPI:
"""思源笔记 API 封装"""
def __init__(self, base_url: str = "https://siyuan.pipexerp.com", token: str = "nfnycjb1g8vbexb2"):
def __init__(self, base_url: str = None, token: str = None):
base_url = base_url or os.environ.get("SIYUAN_URL", "")
token = token or os.environ.get("SIYUAN_TOKEN", "")
self.base_url = base_url
self.headers = {
"Authorization": f"Token {token}",
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "siyuan-to-feishu",
"install_type": "skill",
"dir_category": "integration"
}
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "wecom",
"install_type": "skill",
"dir_category": "integration"
}
@@ -0,0 +1,11 @@
{
"name": "req-audit-plugin",
"description": "部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "req-audit",
"install_type": "command",
"dir_category": "req"
}
+105
View File
@@ -0,0 +1,105 @@
---
name: req-audit
description: 部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。
---
# 部署后审计 (audit)
对本次部署执行三维度审计:运行时行为、代码缺陷、设计偏移。
## 执行流程
### 2a. 运行时检查
检查部署后是否有新增错误。
**优先 SSH**
```bash
ssh -o ConnectTimeout=3 ${EC2_USER}@${EC2_HOST} \
"docker logs ${APP_CONTAINER} --since 10m 2>&1 | grep -i 'error\|panic\|fatal\|traceback'"
```
**降级 1CI 日志**
```bash
RUN_ID=$(gh run list --repo ${OWNER}/${REPO} --limit 1 --json databaseId -q '.[0].databaseId')
gh run view ${RUN_ID} --repo ${OWNER}/${REPO} --log 2>&1 | grep -i 'error\|panic\|fatal'
```
**降级 2N/A + 警告**
```
⚠️ 无法获取运行时日志(SSH 不可达 + CI 日志无异常信息),2a 标记为 N/A。
运行时问题可能未被发现,建议手动检查服务器日志。
```
### 2b. 静态分析
调用现有 `/defect-analysis` command,传入变更文件:
```
对以下变更文件执行缺陷分析:
{变更文件列表}
重点关注:运行时行为(不是合并前 CR 的重复,而是部署后复查)
```
输出:缺陷清单(按致命/高/中/低分级)
### 2c. 设计偏移检测
1. 读取需求的 PRD 文档(linkRole=prd 的任务文档)
2. 读取本次变更的源码
3. AI 对比分析:
```
请对比以下 PRD 功能点和实际代码实现:
PRD 功能点:
{从 PRD 提取的功能清单}
实际代码变更:
{变更文件的关键逻辑}
检查:
- 遗漏的功能(PRD 有但代码没实现)
- 多做的功能(代码有但 PRD 没提)
- 实现方式与 PRD 描述不一致
```
输出:偏移项列表
### 合并报告
```markdown
## 部署后审计报告
### 2a 运行时检查
| 检查项 | 结果 | 详情 |
| 新增错误 | ✅ 无 / ❌ 有 N 条 | ... |
### 2b 静态分析
| 缺陷 | 严重度 | 描述 |
(来自 defect-analysis 输出)
### 2c 设计偏移
| 偏移项 | 类型 | 说明 |
### 结论
- 致命/高级缺陷: N 个 → {阻断/通过}
- 中/低级缺陷: N 个 → 已创建 backlog
- 设计偏移: N 项 → {建议处理方式}
```
### 缺陷分级处理
| 级别 | 处理 |
|------|------|
| 致命 | 阻断归档 + 回滚建议 + `ai-proj task create` 创建修复任务并关联需求 |
| 高级 | 阻断归档 + 回滚建议 + 创建修复任务 |
| 中级 | 警告不阻断 + 创建 backlog 任务 |
| 低级 | 记录到报告,不创建任务 |
## 任务关联
- linkRole: `code_review`
- 任务标题: `【审计】部署后审计: {需求标题}`
- 报告附加到任务文档
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-compare",
"install_type": "skill",
"dir_category": "req"
}
@@ -4,5 +4,8 @@
"version": "2.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-design",
"install_type": "skill",
"dir_category": "req"
}
@@ -5,5 +5,8 @@
"deprecated": true,
"author": {
"name": "qiudl"
}
},
"install_name": "req-dev",
"install_type": "skill",
"dir_category": "req"
}
@@ -0,0 +1,11 @@
{
"name": "req-lookback-plugin",
"description": "回归测试。部署后自动验证变更涉及的功能是否正常。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "req-lookback",
"install_type": "command",
"dir_category": "req"
}
@@ -0,0 +1,87 @@
---
name: req-lookback
description: 回归测试。部署后自动验证变更涉及的功能是否正常。可独立调用或由 /req done 自动触发。
---
# 回归测试 (lookback)
对本次部署变更的功能执行自动化验证。
## 执行流程
### 1. 获取变更文件列表
```bash
# 优先从最近合并的 PR 获取(覆盖 merge 多 commit 场景)
gh pr list --state merged --base main --limit 1 --json number,files
# 回退:git diff
git diff HEAD~1..HEAD --name-only
```
### 2. 自动发现验证项(动态推断)
读取变更文件,按类型推断需要验证什么:
| 文件类型 | 推断方式 | 验证命令 |
|----------|---------|---------|
| `*.vue` / `*.tsx` | grep router 配置,提取对应路由路径 | `curl -sf -o /dev/null -w "%{http_code}" ${SERVER}${ROUTE}` |
| `app/api/*.py` | grep 路由装饰器 `@router.get/post`,提取 API 路径 | `curl -sf -o /dev/null -w "%{http_code}" ${SERVER}/api${PATH}` |
| `app/services/*.py` | 找到引用该 service 的 api 文件,提取关联 API | 同上 |
| `nginx.conf` | 提取 location 块 | `curl` 各路径检查状态码 |
| `docker-compose.yml` | 提取服务列表 | `docker ps` 检查容器状态 |
| `alembic/*.py` | 提取表名 | `psql -c "\d table_name"` |
| `*.md` / `*.txt` / `SKILL.md` | 纯文档 | **N/A(自动通过)** |
| `*.css` / `*.scss` | 纯样式 | 轻量验证:页面可达即可 |
### 3. 执行验证
**远端模式**SSH 可达时):
```bash
# 3 秒超时检测
ssh -o ConnectTimeout=3 ${EC2_USER}@${EC2_HOST} "echo ok" 2>/dev/null
# 成功 → 执行完整验证(docker ps + curl + docker logs
```
**降级模式**SSH 不可达时):
```bash
# 检查最近 CI run 是否成功
gh run list --repo ${OWNER}/${REPO} --limit 1 --json conclusion
# conclusion=success → PASS
```
### 4. 输出报告
```markdown
## 回归测试报告
### 变更范围
| 文件 | 类型 | 推断的验证项 |
### 测试结果
| 测试项 | 方式 | 预期 | 实际 | 状态 |
### 结论: ✅ PASS / ❌ FAIL / N/A
```
### 5. 失败处理
```
⚠️ 回归测试失败:{失败项描述}
建议操作:
1. [回滚] git revert HEAD~1 + /req deploy(推荐,影响最小)
2. [修复] 创建 hotfix 分支修复后重新部署
3. [忽略] 标记为已知问题,继续归档
输入 1/2/3:
```
- 选 1 → 执行 `git revert`,提示用户运行 `/req deploy`
- 选 2 → 创建 hotfix 任务(ai-proj create_task),阻断归档
- 选 3 → 记录到报告,继续
## 任务关联
- linkRole: `test`
- 任务标题: `【回归】回归测试: {需求标题}`
- 报告附加到任务文档
@@ -4,5 +4,8 @@
"version": "2.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req",
"install_type": "skill",
"dir_category": "req"
}
+12 -1
View File
@@ -41,7 +41,8 @@ analysis → design → dev → review → testing → [待部署池] → releas
- PRD 文档是提交评审的前置条件;代码评审是测试的前置条件
- **force=true 禁止自动使用** — 门禁未通过时必须 AskUserQuestion 确认 + 记录跳过原因
- **评审必须用户确认** — 禁止 AI 自审批
- **归档前门禁检查** — `/req done` 按需求类型(code/skill/ops)动态检查
- **归档前 AC 逐条验收(Gate 0,强制)** — `/req done` 必须先提取需求描述中的验收标准逐条确认,无 AC 或有未确认项均阻断,用户必须提供证据或说明跳过原因
- **归档前类型化门禁检查** — Gate 0 通过后,`/req done` 再按需求类型(code/skill/ops)动态检查
- **部署是项目级动作**,由 `/req deploy` 统一触发
- **需求完成后必须 git 提交并 push** — commit 格式:`feat(skill): REQ-XXXX 需求标题`
- **操作前先确认实际 ID** — 从 URL 提取 ID(如 `/requirements/897` → ID=897
@@ -393,6 +394,16 @@ Deploy Gate 3: 证据完整 ── 验收任务有文档,含检查项表格 +
9. `ai-proj req advance --id <id> --to released` 批量推进(仅 Gate 1-3 全部通过的需求)
**`/req done [REQ-ID]`** — 类型化归档门禁 + git commit + push + `ai-proj req archive --id <id>`
**Gate 0(强制):AC 验收逐条确认** — 在所有类型检查之前执行:
1. `ai-proj req get --id <id>` 获取需求描述
2. 提取 `## 验收标准` 章节下的所有 `- [ ]` / `- [x]` 条目
3. **无验收标准**AskUserQuestion 警告并要求用户确认为何无 AC,必须说明跳过原因才能继续
4. **有未勾选项(`- [ ]`**:逐条列出,AskUserQuestion 请用户对每条提供验证证据(截图/curl 输出/日志)或明确标记为 N/A + 说明原因
5. **全部已勾选(`- [x]`**:展示 AC 摘要,直接继续
6. AC 确认通过后,将每条 AC 的验证结果追加到需求描述(`ai-proj req update`),格式:`- [x] {原AC内容}(验证于 YYYY-MM-DD`
**类型检查(Gate 0 通过后)**
- **推断类型**:有 implementation → code;无 implementation 有 prd/test → skill;仅 deploy → ops
- **code 检查**delivery_stage=released + deploy 任务完成 + verification 任务完成(PDV 通过) + 部署文档 + 所有任务完成
- **skill 检查**delivery_stage≥testing + 所有任务完成
@@ -1,8 +1,11 @@
{
"name": "req-prd-plugin",
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
"version": "2.0.0",
"description": "产品需求设计技能。覆盖问答访谈、PRD、缺陷收敛及 HTML 原型验证闭环。纯产品视角,不含技术实现。",
"version": "2.1.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-prd",
"install_type": "skill",
"dir_category": "req"
}
+213 -10
View File
@@ -16,7 +16,36 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
**插件扩展**
- `req-compare` — 对比式 PRD 编写(系统平移/竞品借鉴时激活)
- `req-prototype` — UI 原型生成
- `req-prototype` — UI 模块在 PRD/缺陷收敛后生成、上传并关联 HTML 原型
- `defect-analysis` — 设计访谈确认后,对最新版 PRD 反复审计和修订直至收敛
## 模块设计访谈模式
设计模块、系统、跨域流程,或目标/边界/业务规则尚未确定时,必须先执行问答式设计访谈,不得直接补全假设后生成 PRD。用户明确要求“你问我答”时也进入此模式。范围小、规则已完整确认的需求可以直接编写 PRD。
进入此模式后,**完整读取并执行** [references/design-interview-and-defect-loop.md](references/design-interview-and-defect-loop.md)。该协议定义:
- 每轮只问一个会改变方案的关键问题;
- 将问题、AI 建议、用户原话、决策和未决项逐轮写入 ai-proj 需求的讨论文档;
- 讨论结论经用户确认后,才能创建或更新 PRD;
- 使用 `defect-analysis` 对最新版 PRD 执行“审计 → 修订 → 全量重审”循环;
- UI 模块在 PRD 收敛后使用 `req-prototype` 生成独立 HTML 原型、上传关联 Requirement、回填 PRD 并完成可访问性与关键状态校验;
- 原型评审改变产品行为时,回到问答、PRD 修订和 `defect-analysis` 全量重审,再生成新原型版本;
- 讨论文档缺失、写入失败、用户未确认、原型未验证,或仍有未处置的致命/高严重度缺陷时,不得宣称设计完成或提交评审。
## HTML 原型完成闸门
模块包含用户界面、用户操作流程或可视状态时,HTML 原型是产品设计交付物,不是评审后的可选补充。默认执行 `/req prototype upload [REQ-ID]`,具体生成、上传、iframe 回填和验证规则由 `req-prototype` 定义。
必须满足:
1. 原型基于最新版、已完成缺陷收敛的 PRD,并记录 PRD 文档标识、版本或内容摘要;
2. 覆盖核心入口、主流程以及 PRD 明确要求的空态、失败态、无权限态和确认/撤销反馈;
3. 上传后重新读取 Requirement,确认原型 URL/版本已关联,并验证 URL 可访问、iframe 可展示、核心交互可操作;
4. 将 iframe、原型版本、版本说明和验证结果回填 PRD `4.2 界面原型`,并把生成、反馈、修订和确认写入同一讨论文档;
5. 用户明确确认最终 PRD 与原型表达的是同一方案。
纯后端、批处理、基础设施等确实没有用户界面的模块可以跳过,但必须在讨论文档和 PRD `4.2` 中记录“无 UI,原型不适用”的理由及用户确认,不得静默省略。
## 客户原话原则(REQ-20260416-0017 P1-8
@@ -108,10 +137,21 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
### 4.2 界面原型
> 使用 `/req prototype [REQ-ID]` 基于 PRD 自动生成 Stitch 原型。
> 生成后截图将自动回填到此章节
> UI 模块使用 `/req prototype upload [REQ-ID]` 基于最新版 PRD 生成并上传 HTML 原型。
> 原型必须用 iframe 展示;Stitch 可作为视觉探索的可选输入,不能代替最终 HTML 原型闭环
[执行 `/req prototype` 后自动填充]
**原型基线**
- PRD 文档/版本:...
- 原型版本与说明:...
- Requirement 关联状态:已验证 | 未验证
- 可访问性/关键交互验证:...
<iframe src="[prototype_url]"
width="100%" height="600" frameborder="0"
style="border-radius:8px;border:1px solid #e5e7eb;">
</iframe>
[无 UI 模块填写:原型不适用的理由、讨论记录位置和用户确认原话]
## 5. 技术要求
### 5.1 性能要求
@@ -136,12 +176,49 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
### 6.2 灰度策略
[灰度发布计划]
## 7. 风险评估
## 7. 验收标准 ⭐ 强制包含 VP 三件套
> **规则(源自 REQ-20260421-0002**:每条 AC 必须附带 VP-Data / VP-Steps / VP-Pass,缺一项评审不通过。
### AC1: [验收条件标题]
**目标**[一句话描述期望结果]
**VP-Data(前置测试数据)**
- 环境:localhost / production(二选一,明确注明)
- 数据:[字段、值、状态,例如:需求状态=approved,关联任务 3 个,task_project_id 非空]
- 建数据方式:[curl localhost:8080/... 或 MCP 工具,禁止混用]
**VP-Steps(验证步骤)**
1. [工具 + 操作,例如:agent-browser open http://localhost:3000/xxx]
2. [检查指标,例如:eval `document.querySelector('.xxx').textContent`]
3. [确认值,例如:返回值包含"期望字符串"]
**VP-Pass(通过判定)**
- ✅ [具体期望值,例如:eval 返回数组长度 = 3]
- ✅ [第二个判定条件]
- ❌ [明确的不通过条件,例如:仅靠代码分析得出结论 = 不通过]
---
### AC2: [第二条验收条件]
**目标**...
**VP-Data**...
**VP-Steps**...
**VP-Pass**
- ✅ ...
- ❌ ...
## 8. 风险评估
| 风险 | 影响 | 概率 | 应对措施 |
|------|------|------|----------|
| ... | 高/中/低 | 高/中/低 | ... |
## 8. 附录
## 9. 附录
- 相关文档链接
- 参考资料
```
@@ -172,6 +249,81 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
---
## 需求粒度判断(REQ-20260416-0017 P1-12
**创建需求前,AI 必须先对标题做粒度预判。** 借鉴 devflow-claude `/req:split`
### 核心问题
> **"这个需求完成后,用户能感知到一个完整的功能变化吗?"**
> - 能 → 粒度合适
> - 不能(太大或太小)→ 需调整
### 粒度参考表
| 标题示例 | 粒度 | 建议 |
|---------|------|------|
| "用户积分系统"(含规则+查询+兑换+排行) | 太大 | 拆为 4 个需求 |
| "用户积分-积分规则管理"(含 CRUD+校验) | 合适 | 直接创建 |
| "用户积分-新增积分接口"(仅一个 API) | 太小 | 合并到功能级需求,或用任务(task) |
| "用户积分-新增 model 层"(按技术层拆) | 错误 | 按功能拆,不按技术层拆 |
### AI 自动检测规则
**标题过宽信号**(建议拆分):
- 含"系统"/"模块"/"平台"/"管理"等宏观词
- 描述中功能点 > 5 个
- 预估涉及文件 > 15 个
**标题过窄信号**(建议合并或改 task):
- 含"新增XX接口"/"修改XX字段"/"加一个按钮"
- 单个 CRUD 操作
- 预估涉及文件 ≤ 2 个
**错误拆分信号**(按技术层拆了):
- 标题含"model 层"/"service 层"/"handler 层"/"前端样式"
- 同一业务被拆为"后端接口"和"前端页面"两个独立需求
### 执行时机
1. **创建需求时**`/req new``create_requirement`):检查标题,给出建议
2. **编辑需求时**:功能清单超 8 项时提醒"是否应拆分"
3. **独立评估**:用 `/req split <标题>` 预判粒度
### 三种输出
1. **粒度合适** → 正常创建
2. **建议拆分** → 列出子功能建议,用户确认后批量创建
3. **建议改 task/QUICK** → 提示"这个用任务更合适"
### 已有需求扩展功能的决策
> **"去掉这个新功能点,原需求还能独立交付吗?"**
> - 能 → 新建需求
> - 不能 → 修改原需求(`/req edit`
| 场景 | 建议 |
|------|------|
| 新功能是原需求的自然延伸 | 修改原需求 |
| 新功能可独立上线 | 新建需求 |
| 原需求已完成/归档 | 必须新建 |
| 原需求开发中,新增会影响已有代码 | 新建(防范围蔓延) |
### 前后端拆分规则
```
✅ 正确:
REQ-001 用户积分规则管理-后端(含 CRUD 全部接口)
REQ-002 用户积分规则管理-前端(含 CRUD 全部页面)
❌ 错误:
REQ-001 用户积分规则-新增接口
REQ-002 用户积分规则-查询接口
REQ-003 用户积分规则-修改接口
```
---
## 用户故事编写
### 标准格式
@@ -283,6 +435,8 @@ mcp__ai-proj__export_task_document_to_file
- 需求池(ai-proj 需求列表)
```
若命中“模块设计访谈模式”,本阶段改为执行访谈协议并持续写入 ai-proj 讨论文档;访谈未确认前不进入 PRD 定稿。
### 2. 需求分析
```
@@ -307,10 +461,44 @@ mcp__ai-proj__export_task_document_to_file
输出:
- PRD 文档
- 原型设计
- 可生成原型的界面状态与交互规格
```
### 4. 评审验证
### 4. 缺陷收敛
```
输入:
- 已确认讨论结论
- 最新版完整 PRD
执行:
- defect-analysis 全维度审计
- 接受项修订 PRD
- 对修订后的完整 PRD 重新审计,直至一轮 0 个新缺陷
输出:
- 已收敛 PRD
- 缺陷处置记录
```
### 5. HTML 原型与反馈闭环
```
适用:
- 所有包含界面、用户操作或可视状态的模块
执行:
- 调用 req-prototype 的 upload 模式生成独立 HTML
- 上传并关联 Requirement
- iframe 回填 PRD,验证访问和关键交互
- 请用户评审;行为性反馈回到问答 → PRD → defect-analysis → 新原型版本
输出:
- 已验证、已关联的 HTML 原型
- PRD 与讨论文档中的版本/反馈/确认记录
```
### 6. 评审验证
```
评审维度:
@@ -324,6 +512,10 @@ mcp__ai-proj__export_task_document_to_file
- 修改意见
```
模块设计访谈模式下,本阶段必须调用 `defect-analysis`,并按访谈协议将每轮发现、处置、PRD 修订和收敛结论回写到同一讨论文档。
UI 模块还必须核对最终 HTML 原型与最新版 PRD 一致,并取得用户对二者的联合确认;无 UI 模块则核对已记录的不适用理由和用户确认。
---
## 竞品分析
@@ -368,10 +560,18 @@ mcp__ai-proj__export_task_document_to_file
### PRD 完整性检查
- [ ] 模块/系统设计已完成单轮单问访谈,且全过程已写入 ai-proj 讨论文档
- [ ] 讨论结论已由用户明确确认
- [ ] `defect-analysis` 已基于最新版 PRD 收敛到一轮 0 个新缺陷
- [ ] 无未处置的致命/高严重度缺陷
- [ ] UI 模块 HTML 原型已生成、上传并关联 Requirement;无 UI 模块已记录不适用理由和用户确认
- [ ] 原型基线指向最新版 PRDPRD `4.2` 已回填 iframe、版本说明和验证结果
- [ ] 原型反馈导致的行为变更已回到问答、PRD 和 defect 全量重审,并生成新原型版本
- [ ] 用户已联合确认最终 PRD 与 HTML 原型
- [ ] 背景与目标明确
- [ ] 用户群体定义清晰
- [ ] 功能需求完整
- [ ] 验收标准可测试
- [ ] 验收标准可测试(每条 AC 附带 VP-Data / VP-Steps / VP-Pass
- [ ] 异常情况已考虑
- [ ] 性能要求已定义
- [ ] 上线计划合理
@@ -380,6 +580,8 @@ mcp__ai-proj__export_task_document_to_file
### 交互设计检查
- [ ] 用户流程完整
- [ ] HTML 原型覆盖核心入口、主流程及 PRD 指定的关键状态
- [ ] 原型 URL 可访问,Requirement 关联可读取,iframe 可展示,核心交互可操作
- [ ] 边界情况处理
- [ ] 错误提示友好
- [ ] 反馈及时
@@ -400,7 +602,8 @@ mcp__ai-proj__export_task_document_to_file
## 常用工具
### 原型设计
- **Stitch** (Google AI) — 集成在 `/req prototype`,自动从 PRD 生成原型
- **HTML upload(默认交付)** — `/req prototype upload` 生成可交互独立 HTML,上传后以 iframe 关联 Requirement 和 PRD
- **Stitch** (Google AI) — `/req prototype` 视觉探索与多屏草图,可作为 HTML 原型输入但不替代最终闭环
- Figma — 手动精细设计
- Sketch
- Axure
@@ -0,0 +1,245 @@
# 模块设计访谈、缺陷收敛与 HTML 原型闭环协议
本协议用于模块、系统、跨域流程等需要先澄清关键产品决策的设计任务。目标是让设计依据可追溯,让 PRD 在提交评审前经过可验证的缺陷收敛,并让 UI 模块通过可访问的 HTML 原型完成交互验证。
## 1. 进入与退出条件
满足任一条件时进入访谈模式:
- 用户明确要求“你问我答”、逐项讨论或产品访谈;
- 设计对象是模块、系统、跨域流程或涉及多个角色/组织;
- 目标、范围、数据归属、权限、状态流转、冲突优先级、异常策略中存在关键未决项。
需求范围小、上述决策均已明确时,可以直接编写 PRD。不要为了流程而重复询问用户已经回答的问题。
访谈模式只有同时满足以下条件才可结束:
1. 未决问题已清零,或明确列为非目标/后续项;
2. AI 已给出结构化讨论结论;
3. 用户明确确认讨论结论;
4. PRD 已按结论创建或更新;
5. `defect-analysis` 已对最新版 PRD 收敛;
6. UI 模块的 HTML 原型已生成、上传、关联、回填和验证;无 UI 模块已记录不适用理由并获得用户确认;
7. 用户联合确认收敛后的最终 PRD 与原型(或无 UI 的跳过结论)。
## 2. 讨论文档是跨轮次事实源
当当前工作已有 ai-proj Requirement 时,在提第一个问题前查找其已关联的讨论文档;没有时创建一个 documentation 角色的关联任务,并为任务创建文档:
- 任务标题:`【讨论】需求讨论: {需求标题}`
- 文档标题:`{REQ-ID} 需求讨论记录`
- 一个 Requirement 只维护一个当前讨论文档,不因会话中断重复创建。
查找时同时核对 Requirement 关联关系、任务角色和标题,不能只按相似标题猜测。发现多个候选讨论文档时,列出标识和最近更新时间,请用户指定或授权合并;在此之前不得静默选择其中一个继续写入。
初始化文档时,先把触发本次设计的用户原始消息按时间和消息边界逐条写入“原始诉求”,再记录 `Q001`。不得只留下 AI 总结而丢失原始上下文。
“完整过程”指可供产品决策审计的模型可见内容:用户原话、AI 向用户展示的问题/建议/权衡、工具写入结果、确认、决策变更、PRD 修订和缺陷处置。不得记录或声称记录隐藏推理、系统提示、访问凭据及其他不可披露的内部信息。
若尚未指定 Requirement,先请用户提供已有 Requirement,或明确授权创建。取得 Requirement 和讨论文档前不得开始声称“已留痕”的正式访谈;不得仅为执行本技能本身擅自创建 Requirement。用户明确要求“创建需求并设计”才构成创建授权。
每次恢复会话时,先读取 Requirement、现有 PRD 和讨论文档,从最后一个未决问题继续。讨论文档是跨会话、上下文压缩后的权威记录;模型记忆不能覆盖文档中的用户原话和已确认决策。
### 写入纪律
- 提问时先写入问题原文、问题意图和 AI 建议,再向用户提问。
- 收到回答后,先把用户原话和由此形成的决策写入,再提出下一问。
- 每轮使用稳定编号 `Q001``Q002`……;重试写入时复用编号,禁止重复追加同一轮。
- AI 提供推荐方案或选项时,为待确认内容写出明确编号或完整原文。用户仅回复“确认”“是”“前者”等短答案时,最终决策必须引用对应编号和被确认的完整内容,不能只记录孤立短词。
- 用户原话逐字保留在引用块中;AI 的解释、推论和建议必须分栏,不能伪装成用户决定。访问令牌、密码、私钥及依法需要保护的个人敏感信息不得落库,用 `[敏感信息已脱敏]` 替代并注明脱敏原因。
- 文档以追加式记录为主。状态为“待回答”的问题块可以在收到回答后原位补全一次;变为“已确认”后不得静默改写。纠正已确认结论时追加“决策变更”,并引用被替代的编号。
- 更新整篇文档前重新读取最新版并保留未知内容;若读取后文档又发生变化,基于最新版合并后重试,不能用旧副本覆盖其他会话的记录。
- 写入后读取文档确认本轮编号和正文存在。写入或校验失败时立即报告,停止进入下一轮,且不得声称“已记录”。
- Requirement 描述只同步用户确认后的“讨论结论”摘要;完整过程保留在讨论文档中。
## 3. 单轮单问访谈
每轮只问一个会实质改变产品方案的问题。优先按依赖关系覆盖以下决策面,而不是机械地逐项提问:
1. 用户问题、目标与成功指标;
2. 角色、主体和数据归属;
3. 范围、非目标及版本边界;
4. 实体关系与基数,例如一对一、一对多、多对多;
5. 权限来源、授权人和信任边界;
6. 创建、加入、变更、退出、撤销等状态与生命周期;
7. 多来源冲突时的优先级和人工覆盖规则;
8. 失败、超时、失联、重复请求和恢复策略;
9. 兼容、迁移、审计、数据隔离和验收方式。
问题应让用户做产品决策,不要求用户代替 AI 设计实现细节。用户让 AI 建议时,先给出一个推荐方案和主要权衡,再请用户确认或修正。若回答引入新的实体、状态或例外规则,沿其影响继续追问;若答案已能从用户原话或现有文档确定,则直接记录,不重复确认。
每轮记录以下内容:
```markdown
### Q001 · {决策主题}
- 状态:待回答 | 已确认 | 已替代
- AI 问题(原文):...
- 提问意图:这个答案会影响哪些设计部分
- AI 建议与权衡:推荐方案、替代方案及主要代价
- 待确认内容:方案/选项编号及完整表述
- 用户回答(原文):
> ...
- 最终决策:只写由用户回答直接支持的结论
- 影响范围:PRD 章节、实体、流程、权限或验收标准
- 未决项:无 | 下一步待确认内容
- 记录时间:ISO 8601 时间
```
## 4. 方案确认闸门
问题收敛后,在讨论文档追加“当前决策快照”,至少包含:
- 目标与成功条件;
- 用户/角色及核心场景;
- 范围与非目标;
- 核心实体、关系和数据归属;
- 权限、状态流转和冲突规则;
- 异常、降级、撤销和审计;
- 版本边界与后续项;
- 可验证的验收标准草案;
- 尚存风险和假设。
然后向用户展示同一份摘要并询问是否确认。只有用户明确表示确认,才能:
1. 将摘要同步到 Requirement 描述的 `## 讨论结论`
2. 创建或更新 PRD
3. 进入缺陷收敛循环。
每一步完成后重新读取目标对象确认写入成功。讨论结论未同步成功时不得开始写 PRD;PRD 未写入或读取到的内容与本次版本不一致时不得开始缺陷审计。
若用户修改任何结论,记录为新的问答或“决策变更”,更新快照后重新确认。
## 5. PRD 与 defect-analysis 收敛循环
讨论确认后,先按 `req-prd` 的完整模板生成或更新 PRD,再完整读取并调用 `defect-analysis`。每次审计都以**当前最新版完整 PRD**、已确认讨论记录和必要的真实代码/数据契约为输入,不能只审查上轮改动片段。首次基线审计必须覆盖 `defect-analysis` 中所有适用的架构、运行时、数据和体验/维护维度;不能因为尚未覆盖其他维度时某个单独维度为 0 个新缺陷而提前结束基线。
循环执行:
1. `defect-analysis` 检查最新版 PRD,并按其规则输出带严重度和轮次的缺陷;
2. 将本轮输入版本、检查维度、完整发现和证据写入讨论文档;PRD 输入版本至少包含文档/任务标识、更新时间和内容摘要或哈希,避免审计结果关联到错误版本;审计轮使用稳定编号 `Round 001``Round 002`……,重试不得重复计轮;
3. 对每个发现标记处置:接受、误报、延后;
4. 接受的产品缺陷必须修订 PRD,并同步影响到验收标准、风险、非目标或版本边界;纯技术实现发现若不改变产品行为,记录为后续 `req-design` 约束或开发风险,不向 PRD 填入未经验证的实现细节;
5. 误报必须记录反证;延后必须记录原因、风险、负责人或后续需求,不得静默忽略;
6. 记录 PRD 修改摘要和仍未解决的问题,重新读取 PRD 确认修订已经持久化;
7. 对修改后的完整 PRD 重新调用 `defect-analysis`
若某个修复会改变已确认的目标、范围、实体关系、权限、用户流程、冲突规则或验收口径,不能由 AI 静默应用。将它追加为新的问答或“决策变更”,说明缺陷证据、推荐方案和代价,获得用户确认并更新决策快照后,再修订 PRD;随后重新开始最新版 PRD 的全量审计。
完成全维度基线后,只有 `defect-analysis` 对最新版完整 PRD 出现一轮“0 个新缺陷”时才能标记 PRD 收敛。达到 20 轮仍有新发现只是阶段复盘点:汇总剩余风险并请求用户决定是否继续;不得把“达到轮数”写成“已收敛”。用户已明确要求持续审计时,按该技能规则继续下一阶段。
存在以下任一情况时,不得提交 PRD 评审或宣称完成:
- 未处置的致命或高严重度缺陷;
- 讨论文档缺失或有未成功写入的轮次;
- PRD 与已确认决策不一致;
- 缺少 0 新增缺陷的收敛轮;
- UI 模块缺少已验证并关联的最终 HTML 原型,或原型与最新版 PRD 不一致;
- 无 UI 模块没有记录跳过理由及用户确认;
- 用户尚未联合确认收敛后的最终 PRD 与原型(或跳过结论)。
## 6. HTML 原型闭环
### 6.1 适用性判断
PRD 包含页面、表单、列表、可视状态、用户操作或跨页面流程时,必须执行 `req-prototype` 的 HTML upload 模式。Stitch 截图或其他静态图片可以辅助探索,但不能替代可交互 HTML、Requirement 关联和 iframe 回填。
纯后端、批处理、基础设施等无用户界面的模块可以跳过。跳过前必须把理由、影响范围和待确认内容写入讨论文档,取得用户明确确认,并在 PRD `4.2 界面原型` 留下“不适用”记录。
### 6.2 生成基线与覆盖范围
1. 重新读取最新版 PRD,记录任务/文档标识、更新时间、版本和内容摘要或哈希;
2. 从功能需求、交互设计和验收标准提取页面清单、角色入口、主流程与关键状态;
3. 调用 `req-prototype` 生成独立 HTML。至少覆盖核心入口、主流程,以及 PRD 明确要求的空态、加载态、失败态、无权限态、确认和撤销反馈;
4. 原型不得引入 PRD 未确认的新权限、状态、自动化规则或默认值。为了连贯展示所作的推断必须显式标注为待确认,不能伪装成既定需求。
### 6.3 上传、关联、回填与验证
1. 通过 `upload_prototype` 上传 HTML,并记录 Requirement 数字 ID、原型 URL、版本说明和上传时间;
2. 重新读取 Requirement,确认返回的原型 URL/版本确实已关联。仅拿到上传成功响应不足以通过;
3. 将 iframe、PRD 基线、原型版本、版本说明和验证结果回填 PRD `4.2 界面原型`
4. 用浏览器或等价方式验证 URL 可访问、iframe 可展示、核心导航和交互可操作、关键状态可识别。使用临时浏览器时按环境规则关闭;
5. 将生成输入、上传结果、验证证据和待确认差异写入讨论文档。任何写入或验证失败都必须停止,不得声称原型已完成。
### 6.4 用户评审与回流
向用户展示最终关联的原型,并请其同时检查信息结构、流程、状态、权限提示和关键文案:
- 仅视觉样式、间距、颜色等不改变产品行为的反馈,可以直接生成新原型版本,并记录修改摘要;
- 反馈改变目标、范围、实体关系、权限、状态、流程、异常策略、默认值或验收口径时,追加新的问答/决策变更,更新决策快照和 PRD,重新执行完整 `defect-analysis`,收敛后再生成新 HTML 原型版本;
- 每个新版本都必须重新执行关联、PRD 回填和可访问性/交互验证,不得覆盖或伪造历史版本;
- 只有用户明确确认“最终 PRD 与当前原型一致”后,模块产品设计才可结束。
## 7. 讨论文档结构
```markdown
# {REQ-ID} 需求讨论记录
## 元数据
- Requirement...
- 状态:访谈中 | 待方案确认 | PRD 优化中 | 原型制作中 | 待最终确认 | 已收敛
- 最新 PRD:任务/文档标识
- 更新时间:...
## 原始诉求
> 用户原话,按时间追加
## 问答记录
### Q001 · ...
...
## 决策变更
### D001 · 替代 Qxxx 的结论
...
## 当前决策快照
...
## 未决问题
- ...
## 方案确认
- 用户确认原话:...
- 确认时间:...
## PRD / 缺陷优化记录
### Round 1 · {检查维度}
- PRD 版本/摘要:...
- 新缺陷:...
- 处置与证据:...
- PRD 修订:...
- 剩余风险:...
## HTML 原型记录
### Prototype v1 · {版本说明}
- PRD 基线:任务/文档标识、版本、更新时间、摘要或哈希
- 是否适用:是 | 否(理由与用户确认)
- 原型 URL...
- Requirement 关联校验:...
- iframe / 可访问性 / 关键交互验证:...
- 用户反馈:...
- 行为性变更回流:无 | 对应 Q/D、PRD 版本和 defect 轮次
- 状态:待验证 | 待用户确认 | 已替代 | 已确认
## 收敛结论
- 收敛轮次:...
- 0 新增缺陷证据:...
- 最终原型版本/URL:... | 无 UI,不适用(确认记录:...)
- PRD 与原型一致性确认:...
- 未解决的中/低风险及接受理由:...
- 用户最终确认原话:...
```
## 8. 最终交付说明
最终回复必须同时给出:
- ai-proj Requirement 标识;
- 讨论任务/文档标识;
- PRD 任务/文档标识;
- 问答轮数、缺陷审计轮数和收敛轮;
- HTML 原型版本、URL、Requirement 关联与验证状态;无 UI 时给出跳过理由和用户确认;
- 仍被接受的中/低风险;
- 用户两次确认:讨论方案确认、最终 PRD 与原型(或无 UI 结论)的联合确认。
任何标识或写入状态无法验证时,用“未验证/未写入”如实标注。
@@ -1,8 +1,11 @@
{
"name": "req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。",
"version": "1.0.0",
"description": "原型生成与关联。支持 HTML 正式交付、Requirement 关联、iframe 验证闭环及 Stitch AI 视觉探索。",
"version": "2.1.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-prototype",
"install_type": "skill",
"dir_category": "req"
}
+223 -9
View File
@@ -1,16 +1,20 @@
---
name: req-prototype
description: Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型,支持编辑和变体生成。当执行 /req prototype 或需要生成界面原型时使用。
arguments: [REQ-ID] [--device desktop|mobile|tablet] [--model pro|flash] [--prompt "..."]
description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 PRD 自动生成 UI 原型截图;(2) AI 编写 HTML 原型并上传关联到需求详情页 iframe。当执行 /req prototype 或需要生成/上传界面原型时使用。
---
# Stitch 原型设计 Skill (req-prototype)
# 原型设计 Skill (req-prototype)
用法:`/req prototype <REQ-ID> [subcommand] [options]`
## 概述
基于 PRD 文档自动生成 Stitch UI 原型,插入在 PRD 编写完成后、submit 评审前。
支持两种原型工作流:
**核心流程**:读取 PRD → 提取 UI 描述 → 转英文 prompt → 调用 Stitch API → 截图回填 PRD
| 模式 | 命令 | 适用场景 | 输出 |
|------|------|----------|------|
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 可交互 HTML + Requirement 关联 + PRD iframe |
| **Stitch AI** | `/req prototype` | 精细 UI 视觉探索、多屏草图 | 截图回填 PRD,后续仍需转为 HTML 正式原型 |
## 前置条件
@@ -18,13 +22,177 @@ arguments: [REQ-ID] [--device desktop|mobile|tablet] [--model pro|flash] [--prom
| 检查项 | 方式 | 失败处理 |
|--------|------|----------|
| 需求存在 | `ai-proj req get --id <id>` | 报错:需求不存在 |
| PRD 文档存在 | `ai-proj req tasks --id <id>` 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd 编写 PRD |
| PRD 包含 UI 描述 | 检查 PRD 中「功能需求」「交互设计」「界面原型」章节 | 警告:PRD 未包含 UI 相关描述,建议先补充 |
| 需求存在 | `mcp__ai-proj__get_requirement` | 报错:需求不存在 |
| PRD 文档存在(两种模式)| 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd |
| PRD 已完成 defect 收敛(正式 HTML 模式) | 读取讨论文档的收敛轮和最新版 PRD 标识 | 报错:先完成 req-prd/defect-analysis 收敛 |
| UI 原型适用 | PRD 含页面、操作流程或可视状态 | 无 UI 时记录不适用理由与用户确认,不生成空壳原型 |
## 子命令
### 1. `/req prototype [REQ-ID]` — 生成原型
### 0. `/req prototype upload [REQ-ID] [--note "版本说明"]` — 上传 HTML 原型(**推荐**)
**适用场景**:为 UI 模块生成正式 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览和验证交互流程。模块产品设计默认使用此模式完成原型闸门。
**执行流程**
```
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id,并定位唯一 PRD 与讨论文档
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 界面原型」
10. 打开最终 URL 或需求详情页,验证 iframe 展示和核心交互;记录证据后关闭临时浏览器
11. 将生成、关联、验证、用户反馈和版本状态写入同一讨论文档
```
**Step 5-6 执行方式**
```bash
# 5. Base64 编码 HTML 文件
B64=$(base64 < /tmp/proto_<req_id>_<timestamp>.html)
```
```
# 6. 通过 MCP 工具上传(无需本地后端)
mcp__ai-proj__upload_prototype(
requirementId = <需求数字ID>,
content = <B64 字符串>,
versionNote = <--note 的值或"初稿 v1">
)
```
**成功响应**
```json
{
"success": true,
"message": "原型已上传并关联到需求 <id>version=N/A",
"data": {
"url": "https://ai-proj-1252326374.cos.ap-beijing.myqcloud.com/prototypes/<uuid>.html",
"versionNote": "...",
"uploadedAt": "...",
"requirementId": <id>
}
}
```
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 COS 上的 HTML 文件。**无需本地后端运行**。
**参数**
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--note` | 空 | 版本说明,如"初稿 v1"、"评审修改版" |
---
#### HTML 原型设计规范
AI 生成的 HTML 原型必须满足以下要求:
**结构要求**
- 完整独立的 HTML 文件(含 `<!DOCTYPE html>` + `<head>` + `<body>`
- 所有样式内联在 `<style>` 标签中,不依赖外部 CDN
- 不使用 JavaScript 框架(纯 HTML+CSS,可用少量原生 JS
- 适合在 600px 高度的 iframe 中展示
**视觉要求**
- 与需求功能高度对应,体现核心交互流程
- 包含真实感数据(非"xxx"占位符)
- 顶部导航栏 / 侧边栏与项目风格一致(深色 header,现代 SaaS 风格)
- 底部加注释标注条(固定定位,说明版本和需求号)
**内容要求**
- 覆盖需求描述中的核心功能点
- 展示关键数据状态(列表、表单、卡片等)
- 按钮/操作有视觉反馈样式(hover 色等)
- 对 PRD 明确要求的空态、加载态、失败态、无权限态、二次确认和撤销反馈提供可切换或可识别的展示
- 不得自行引入 PRD 未确认的权限、状态、自动化规则或默认值;不可避免的展示推断必须标为待确认
- 不包含访问令牌、真实手机号/邮箱、生产数据等敏感信息
**模板参考**(顶部 topbar + 侧边栏 + 主内容区):
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>[需求标题] - 原型</title>
<style>
/* reset + layout */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #f0f2f5; color: #1a1a2e; min-height: 100vh; }
.topbar { background: #1e3a5f; color: #fff; padding: 0 24px; height: 52px;
display: flex; align-items: center; justify-content: space-between; }
.layout { display: flex; height: calc(100vh - 52px); }
.sidebar { width: 220px; background: #fff; border-right: 1px solid #e5e7eb;
padding: 16px 0; overflow-y: auto; }
.main { flex: 1; overflow-y: auto; padding: 24px; padding-bottom: 48px; }
/* 底部原型标注条 */
.annotation { position: fixed; bottom: 0; left: 0; right: 0;
background: rgba(30,58,95,.92); color: #fff;
padding: 6px 24px; font-size: 12px;
display: flex; justify-content: space-between; }
.annotation strong { color: #93c5fd; }
</style>
</head>
<body>
<div class="topbar"><!-- 导航 --></div>
<div class="layout">
<aside class="sidebar"><!-- 侧边栏 --></aside>
<main class="main"><!-- 主内容 --></main>
</div>
<div class="annotation">
<span>🎨 <strong>原型预览</strong> · [REQ-ID] — [需求标题]</span>
<span style="color:#93c5fd;">v1.0 · [日期] · 仅供评审参考</span>
</div>
</body>
</html>
```
---
#### HTML 原型 PRD 回填
定位 PRD `### 4.2 界面原型`,写入或更新以下内容;保留历史版本记录,不把旧 URL 静默改写成新版本:
```markdown
### 4.2 界面原型
**原型基线**
- PRD 任务/文档:#... / #...
- PRD 版本/更新时间/摘要:...
- defect 收敛轮:Round ...0 个新缺陷)
- HTML 原型:v... · [版本说明]
- Requirement 关联:已复读验证
- 验证结果:URL 可访问;iframe 可展示;核心交互通过
<iframe src="[prototype_url]"
width="100%" height="600" frameborder="0"
style="border-radius:8px;border:1px solid #e5e7eb;">
</iframe>
```
原型反馈改变目标、范围、实体关系、权限、状态、流程、异常策略、默认值或验收口径时,不得只改 HTML。回到 `req-prd` 追加问答/决策变更,修订 PRD,重新执行完整 `defect-analysis`,收敛后再上传新原型版本。纯视觉反馈可以直接生成新版本,但仍需重新关联、回填和验证。
#### HTML 上传后验证清单
- [ ] 上传响应成功且 Requirement 复读能看到同一 URL/版本
- [ ] 原型 URL 返回可展示的 HTML,不是下载错误页、登录页或 404
- [ ] 需求详情页使用 iframe 展示,没有降级为截图或图片
- [ ] 核心入口、主流程和覆盖矩阵中的关键状态可识别/可操作
- [ ] 600px iframe 下内容可用,没有关键操作被固定栏遮挡
- [ ] 浏览器控制台无阻断交互的错误,原型不依赖外部 CDN
- [ ] PRD `4.2` 与讨论文档均记录基线、版本、URL、验证和反馈状态
---
### 1. `/req prototype [REQ-ID]` — Stitch AI 生成原型
**流程**
@@ -37,6 +205,7 @@ arguments: [REQ-ID] [--device desktop|mobile|tablet] [--model pro|flash] [--prom
6. 生成页面(mcp__stitch__generate_screen_from_text
7. 获取截图(mcp__stitch__get_screen
8. 回填 PRD「4.2 界面原型」章节
9. 若用于模块正式交付,将选定设计转换为 HTML upload 原型,并完成关联、iframe 和验证闭环
```
**参数**
@@ -154,6 +323,39 @@ generated_at: "<timestamp>"
## 异常处理
### Upload 模式
| 异常 | 处理 |
|------|------|
| `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` |
| Requirement 复读没有新 URL | 视为关联失败,停止回填“已验证”,检查 requirementId 和上传响应后再处理 |
| URL 可访问但关键交互失败 | 修复 HTML、上传新版本并重新验证,不覆盖失败版本的记录 |
### 原型展示规则
**原型必须用 iframe 展示**(不得用截图、图片嵌入或内联 HTML 方式替代)。
- PRD 文档的「4.2 界面原型」章节:使用 `<iframe>` 标签嵌入原型 URL,而非 `![](...)` 图片
- 需求详情页原型预览卡片:后端渲染 iframe,前端不得将 `prototype_urls` 内容渲染为 `<img>`
- 典型正确写法(PRD 文档内):
```html
<iframe src="/api/v1/uploads/prototypes/proto_xxx.html"
width="100%" height="600" frameborder="0"
style="border-radius:8px;border:1px solid #e5e7eb;">
</iframe>
```
> 背景:REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。
Stitch 截图只用于视觉探索,不满足模块产品设计的最终 HTML 原型闸门。
### Stitch 模式
| 异常 | 处理 |
|------|------|
| 需求无 PRD 文档 | 报错:`请先使用 req-prd 技能编写 PRD 文档` |
@@ -162,3 +364,15 @@ generated_at: "<timestamp>"
| Stitch API 返回错误 | 展示错误信息,建议调整 prompt 或更换模型 |
| PRD 无「4.2 界面原型」章节 | 在「## 4. 交互设计」末尾自动追加该章节 |
| 已有原型元数据 | 询问:`已存在原型,是否覆盖?` |
## 版本管理
每次 `/req prototype upload` 都会追加一个新版本(自增 `version` 字段),需求详情页支持版本切换下拉框。多个版本并存时,最新版本默认展示。
可多次上传来迭代原型:
```
v1 → 初稿(评审前)
v2 → 评审修改版
v3 → 开发对齐版
```
@@ -2,5 +2,10 @@
"name": "req-research-plugin",
"description": "需求调研插件。代码审计、数据库分析、现有功能调研。挂载在 analysis 阶段,需要深度调研时激活。",
"version": "1.0.0",
"author": { "name": "qiudl" }
"author": {
"name": "qiudl"
},
"install_name": "req-research",
"install_type": "skill",
"dir_category": "req"
}
@@ -0,0 +1,11 @@
{
"name": "req-retro-plugin",
"description": "复盘总结。自动采集数据、计算质量评分、跨需求模式识别、技能自动进化。可独立调用或由 /req done 自动触发。",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "req-retro",
"install_type": "command",
"dir_category": "req"
}
+180
View File
@@ -0,0 +1,180 @@
---
name: req-retro
description: 复盘总结。自动采集数据、计算质量评分、跨需求模式识别、技能自动进化。可独立调用或由 /req done 自动触发。
---
# 复盘总结 (retro)
自动采集需求全生命周期数据,计算质量评分,识别跨需求模式,沉淀经验。
## 执行流程
### 1. 数据采集
| 数据 | 来源 | 方式 |
|------|------|------|
| 各阶段时间 | ai-proj | `mcp__ai-proj__get_requirement_history` |
| 任务完成情况 | ai-proj | `mcp__ai-proj__get_requirement_tasks` |
| CR 发现数 | CR 任务文档 | 从【代码评审】任务文档中提取缺陷计数 |
| 测试结果 | test 任务文档 | 从【测试】任务文档中提取通过/失败数 |
| audit 缺陷数 | 本次 audit 结果 | 从 audit 报告中提取 |
| git 统计 | git | `git log --stat` 提交数、变更行数 |
### 2. 质量评分(Quality Score
```
QS = lookback_pass_rate × 0.25
+ audit_defect_score × 0.25
+ cr_density_score × 0.15
+ test_pass_rate × 0.15
+ karpathy_score × 0.20 ← Karpathy 四原则执行质量
audit_defect_score:
0 缺陷 = 100
每个低级 -5
每个中级 -20
每个高级 -60
致命 = 0
cr_density_score:
100 - (发现数 / 变更行数 × 1000)
下限 0,上限 100
karpathy_score(四原则执行质量,各 25 分,共 100):
Think Before PRD (25):
PRD 无返工 → 25 | 因需求误解返工 1 次 → 15 | ≥2 次 → 0
Simplicity (25):
CR 第六视角无 Scope 违规 → 25 | 1 个 Low → 20 | ≥1 个 Medium+ → 10 | High+ → 0
Surgical (25):
check-surgical.sh PASS + CR 无顺手改 → 25 | 警告但未阻塞 → 15 | FAIL → 0
Goal-Driven (25):
dev-coding 有验证脚本记录(VP-Steps 先于代码执行)→ 25 | 事后补写 → 15 | 无 → 0
```
**Karpathy 数据来源**(按优先级):
1. dev-coding 任务文档中是否有「验证脚本」节
2. CR 报告第六视角的发现数和严重度
3. `git log` 中是否有 check-surgical.sh baseline 更新提交(说明有过违规)
4. PRD 任务文档的版本数(> 1 说明有返工)
**无数据时**:各维度默认 20 分(中性),在报告中标注 `(无记录,按中性计算)`
### 3. 历史趋势对比
读取 `memory/retro_metrics.md` 的明细数据:
```
本次 vs 近 10 次平均:
总耗时: 5h 44min vs avg 8h 12min (↓ 30% 改善)
质量分: 92 vs avg 85 (↑ 8% 提升)
缺陷数: 2 vs avg 3.2 (↓ 37% 改善)
变更行: 279 vs avg 450 (↓ 38%)
```
首次执行时显示:"首次复盘,无历史数据可对比。"
### 4. 跨需求模式识别
读取 retro_metrics.md 全部明细,AI 分析三类模式:
**耗时模式**
- 按需求类型(前端/后端/混合/技能)分组统计平均耗时
- 识别异常:某次耗时是同类平均的 2 倍以上 → 标注原因
**缺陷热区**
- 统计各文件在多次需求中的 audit 发现频率
- 同一文件 3 次以上出现 → 标记为热区
**改进验证**
- 对比引入某流程/技能前后的质量分趋势
- 例:"引入 defect-analysis 后 5 次需求平均质量分从 72 → 88"
### 5. 自动更新技能
当模式识别发现高频缺陷类型时:
```
AI: "近 5 次需求中 3 次 audit 发现了 {缺陷类型}。
建议在 dev-review 的 CR 检查清单中增加:'{新检查项}'。"
用户确认?(y/n)
```
用户确认 → 自动在 `~/.claude/skills/dev-review/SKILL.md` 检查清单末尾追加该检查项。
### 6. 更新 retro_metrics.md
追加一行到明细:
```
| REQ-xxx | 2026-04-18 | 5h44m | 92 | 2 | 279 | 3 | frontend | 85 |
```
列说明:`REQ | date | time | QS | audit_defects | changed_lines | cr_findings | type | karpathy_score`
更新汇总:重新计算近 10 次平均值和趋势箭头(↑↓→),包含 karpathy_score 趋势。
超过 30 条明细 → 最早的移入 `retro_metrics_archive.md`
### 7. 生成文档
输出 `04-生命周期总结.md`,附加到【复盘】任务:
```markdown
# 生命周期总结 - REQ-xxx
## 质量评分: 92/100
## 时间线
| 阶段 | 进入时间 | 耗时 |
|------|---------|------|
| 创建 | 04-18 11:14 | - |
| PRD | 04-18 11:18 | 4min |
| 评审 | 04-18 11:19 | 1min |
| 开发 | 04-18 12:00 | 41min |
| 部署 | 04-18 16:58 | 4h58min |
| 总耗时 | | 5h 44min |
## 质量指标
| 指标 | 本次 | 近10次均 | 对比 |
|------|------|---------|------|
| 质量分 (QS) | 92 | 85 | ↑ |
| audit 缺陷 | 2(低) | 3.2 | ↓ |
| CR 发现 | 0 | 1.5 | ↓ |
| 测试通过率 | 100% | 95% | ↑ |
| Karpathy 分 | 85 | 78 | ↑ |
## Karpathy 四原则评分
| 原则 | 得分 | 说明 |
|------|------|------|
| Think Before PRD | 25/25 | PRD 无返工 |
| Simplicity | 20/25 | CR 第六视角发现 1 个 Low |
| Surgical | 25/25 | check-surgical.sh PASS |
| Goal-Driven | 15/25 | 验证脚本为事后补写 |
## git 统计
| 提交数 | 变更文件 | +行 | -行 |
|--------|---------|-----|-----|
| 3 | 1 | 279 | 2 |
## 模式识别
- {耗时/热区/改进 分析结果}
## 经验教训(写入 memory
- {AI 提取的非显然教训}
## 技能更新
- {已更新/无更新}
```
### 8. 写入 memory
将有价值的经验写入 memory
- 类型:`feedback``project`
- 只写非显然的、可指导未来工作的教训
- 用户确认后写入
## 任务关联
- linkRole: `documentation`
- 任务标题: `【复盘】生命周期总结: {需求标题}`
- 04-生命周期总结.md 附加到任务文档
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-review",
"install_type": "skill",
"dir_category": "req"
}
+16 -2
View File
@@ -23,7 +23,8 @@ PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据
| 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 |
| 验收标准 | ✓ | 验收条件(每条 AC 必须附带 VP 三件套,见下方) |
| VP 三件套 | ✓ | 每条 AC 后必须有 VP-Data / VP-Steps / VP-Pass 三个子节 |
| 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 如有 Stitch 原型则必审:布局合理性、与 PRD 描述一致性 |
| 非功能需求 | ○ | 性能、安全 |
@@ -112,6 +113,19 @@ PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据
【驳回人】xxx 【时间】2026-xx-xx
```
## VP 三件套强制检查(源自 REQ-20260421-0002
**每条 AC 必须附带完整的 Verification Protocol,缺一项即驳回。**
| 检查项 | 要求 | 驳回条件 |
|--------|------|----------|
| VP-Data | 前置测试数据规格(环境/字段值/状态缺一不可) | 未注明在哪个环境建数据 |
| VP-Steps | 可重复执行的验证步骤(工具 + 操作 + 检查指标) | 步骤无法被第三方重复执行 |
| VP-Pass | 明确判定标准(含 ✅ 通过条件 + ❌ 不通过条件) | 只写"效果正确"之类模糊描述 |
| 环境隔离 | localhost 测试数据用 curl,生产数据用 MCP | 混用环境 |
**评审结论规则**:VP 三件套任何一项缺失 → 驳回,注明「AC N 缺少 VP-XXX,退回补充」。
## 常见驳回原因
| 类别 | 问题 | 建议 |
@@ -121,4 +135,4 @@ PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据
| 边界不清 | 缺异常处理 | 补充边界条件 |
| 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 |
| 验收不明 | 缺 AC 或 VP 三件套 | 补充验收条件和 VP |
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-test-gate",
"install_type": "skill",
"dir_category": "req"
}
@@ -87,12 +87,24 @@ done
**报告格式**
```
### 约定检查 (Gate 0B)
| 脚本 | 结果 | 详情 |
|------|------|------|
| check-architecture.sh | ✅ PASS | 5 rules, all within baseline |
| check-modal-safety.sh | ✅ PASS | 0 violations |
| 脚本 | 类型 | 结果 | 详情 |
|------|------|------|------|
| check-architecture.sh | Ratchet | ✅ PASS | 5 rules, all within baseline |
| check-modal-safety.sh | Hard wall | ✅ PASS | 0 violations |
| check-surgical.sh | Ratchet | ✅ PASS | 0 format-only violations (baseline=0) |
```
**本项目已建立的约定检查脚本**
| 脚本 | 类型 | 检测内容 | 来源 |
|------|------|---------|------|
| `check-architecture.sh` | Ratchet | Handler 直接引用 database/ 层 | 分层架构规范 |
| `check-modal-safety.sh` | Hard wall | Modal.success 后立即操作 UI | REQ-20260416 |
| `check-surgical.sh` | Ratchet | PR diff 中疑似仅注释/格式变更的文件 | Karpathy SurgicalREQ-20260421-0003|
> `check-surgical.sh` 使用 Ratchet 模式:`.surgical-baseline.json` 记录基线,违规数只能降不能升。
> 首次无基线时仅告警,不阻塞。运行 `./scripts/check-surgical.sh baseline` 建立基线。
> 这样 Harness 建立的约定脚本会在每次 `/req test` 时自动运行,无需手动执行 `/harness report`。
---
@@ -4,5 +4,8 @@
"version": "1.0.0",
"author": {
"name": "qiudl"
}
},
"install_name": "req-workflow",
"install_type": "skill",
"dir_category": "req"
}
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf "$TEST_ROOT"' EXIT
FIXTURE_REPO="$TEST_ROOT/repo"
TEST_HOME="$TEST_ROOT/home"
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/.claude-plugin"
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/skills/references"
mkdir -p "$TEST_HOME"
cp "$PROJECT_DIR/install-skills.sh" "$FIXTURE_REPO/install-skills.sh"
write_manifest() {
local plugin="$1" name="$2" version="$3" install_type="${4:-skill}"
mkdir -p "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin"
cat > "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin/plugin.json" <<JSON
{"name":"${plugin}-plugin","version":"${version}","install_name":"${name}","install_type":"${install_type}","dir_category":"dev"}
JSON
}
write_manifest example example 1.0.0
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
---
name: example
description: Installer fixture version one.
---
version one
EOF
printf 'reference one\n' > "$FIXTURE_REPO/skills-dev/example-plugin/skills/references/guide.md"
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
test -f "$TEST_HOME/.agents/skills/example/references/guide.md"
# A repository version upgrade replaces an unchanged prior install.
write_manifest example example 2.0.0
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
---
name: example
description: Installer fixture version two.
---
version two
EOF
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"
# A local edit is preserved even when the repository advances again.
printf 'local edit\n' >> "$TEST_HOME/.agents/skills/example/SKILL.md"
write_manifest example example 3.0.0
printf 'repository version three\n' >> "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
output="$(HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh")"
grep -q 'local files were modified' <<<"$output"
grep -q 'local edit' "$TEST_HOME/.agents/skills/example/SKILL.md"
if grep -q 'repository version three' "$TEST_HOME/.agents/skills/example/SKILL.md"; then
echo 'local modification was overwritten' >&2
exit 1
fi
# Legacy SKILL.md-only installs gain missing repository resources when their
# existing content is an unchanged subset of the source.
write_manifest legacy legacy 1.0.0
mkdir -p "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references"
cat > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" <<'EOF'
---
name: legacy
description: Legacy installation fixture.
---
legacy content
EOF
printf 'legacy reference\n' > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references/guide.md"
mkdir -p "$TEST_HOME/.agents/skills/legacy"
cp "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" "$TEST_HOME/.agents/skills/legacy/SKILL.md"
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
test -f "$TEST_HOME/.agents/skills/legacy/references/guide.md"
# Command manifests become standard Codex skills, while explicit Claude
# installs retain the legacy single-file command layout. Both must be stable on
# a second run despite the Claude filename change.
write_manifest sample-command sample-command 1.0.0 command
mkdir -p "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills"
cat > "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills/SKILL.md" <<'EOF'
---
name: sample-command
description: Command installation fixture.
---
command content
EOF
CODEX_TEST_HOME="$TEST_ROOT/codex-home"
mkdir -p "$CODEX_TEST_HOME"
HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
test -f "$CODEX_TEST_HOME/.agents/skills/sample-command/SKILL.md"
test ! -e "$CODEX_TEST_HOME/.claude/commands/sample-command.md"
codex_output="$(HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --dry-run)"
grep -q '0 plugins would be installed/updated' <<<"$codex_output"
if grep -q 'sample-command: local files were modified' <<<"$codex_output"; then
echo 'Codex command skill was reported as modified' >&2
exit 1
fi
CLAUDE_TEST_HOME="$TEST_ROOT/claude-home"
mkdir -p "$CLAUDE_TEST_HOME"
HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude >/dev/null
test -f "$CLAUDE_TEST_HOME/.claude/commands/sample-command.md"
claude_output="$(HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude --dry-run)"
grep -q '0 plugins would be installed/updated' <<<"$claude_output"
if grep -q 'sample-command: local files were modified' <<<"$claude_output"; then
echo 'Claude command was reported as modified after filename conversion' >&2
exit 1
fi
echo 'install-skills tests passed'
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""
Update all plugin.json files with install_name, install_type, and dir_category fields.
"""
import json
import os
# Mapping: plugin_dir_name -> (install_name, install_type, dir_category)
# install_type: "skill" -> ~/.claude/skills/<install_name>/
# "command" -> ~/.claude/commands/<install_name>.md
PLUGIN_MAP = {
# skills-biz
"biz-contract-plugin": ("biz-contract", "skill", "biz"),
"biz-ops-plugin": ("biz-ops", "skill", "biz"),
"biz-plan-plugin": ("biz-plan", "skill", "biz"),
"finance-plugin": ("finance", "skill", "biz"),
# skills-core
"ai-proj-plugin": ("ai-proj", "skill", "core"),
"pm-ask-plugin": ("pm-ask", "skill", "core"),
"pm-risk-plugin": ("pm-risk", "skill", "core"),
"publish-plugin": ("publish", "skill", "core"),
# skills-dev
"ai-proj-cicd-release-plugin": ("ai-proj-cicd-release", "skill", "dev"),
"ai-proj-macos-release-plugin": ("ai-proj-macos-release", "skill", "dev"),
"agent-browser-plugin": ("agent-browser", "skill", "dev"),
"agent-swarm-plugin": ("agent-swarm", "skill", "dev"),
"ai-chat-plugin": ("ai-chat", "skill", "dev"),
"db-migration-plugin": ("db-migration", "skill", "dev"),
"defect-analysis-plugin": ("defect-analysis", "command", "dev"),
"deploy-rollback-plugin": ("deploy-rollback", "skill", "dev"),
"dev-android-plugin": ("dev-android", "skill", "dev"),
"dev-arch-plugin": ("dev-arch", "skill", "dev"),
"dev-cicd-plugin": ("dev-cicd", "skill", "dev"),
"dev-coding-plugin": ("dev-coding", "skill", "dev"),
"dev-commit-plugin": ("dev-commit", "skill", "dev"),
"dev-deploy-plugin": ("dev-deploy", "skill", "dev"),
"dev-integration-plugin": ("dev-integration", "skill", "dev"),
"dev-ios-plugin": ("dev-ios", "skill", "dev"),
"dev-mcp-plugin": ("dev-mcp", "skill", "dev"),
"dev-pda-plugin": ("dev-pda", "skill", "dev"),
"dev-review-plugin": ("dev-review", "skill", "dev"),
"dev-scaffold-plugin": ("dev-scaffold", "skill", "dev"),
"dev-test-plugin": ("dev-test", "skill", "dev"),
"executing-plans-plugin": ("executing-plans", "skill", "dev"),
"finishing-branch-plugin": ("finishing-a-development-branch","skill", "dev"), # name mismatch!
"frontend-design-plugin": ("frontend-design", "skill", "dev"),
"karpathy-guidelines-plugin": ("karpathy-guidelines", "skill", "dev"),
"pull-request-plugin": ("pull-request", "skill", "dev"),
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
# skills-integration
"data-excel-plugin": ("data-excel", "skill", "integration"),
"doubao-voice-plugin": ("doubao-voice", "skill", "integration"),
"feishu-bitable-plugin": ("feishu-bitable", "skill", "integration"),
"feishu-docx-plugin": ("feishu-docx", "skill", "integration"),
"feishu-plugin": ("feishu", "skill", "integration"),
"siyuan-plugin": ("siyuan", "skill", "integration"),
"siyuan-to-feishu-plugin": ("siyuan-to-feishu", "skill", "integration"),
"wecom-plugin": ("wecom", "skill", "integration"),
# skills-personal
"gitea-plugin": ("gitea", "skill", "personal"),
"openclaw-plugin": ("openclaw", "skill", "personal"),
"ops-servers-plugin": ("ops-servers", "skill", "personal"),
"ops-tools-plugin": ("ops-tools", "skill", "personal"),
"qiudl-personal-plugin": ("qiudl-personal", "skill", "personal"),
"reload-session-plugin": ("reload-session", "skill", "personal"),
"req-deploy-plugin": ("req-deploy", "skill", "personal"),
"save-session-plugin": ("save-session", "skill", "personal"),
"search-sessions-plugin": ("search-sessions", "skill", "personal"),
# skills-req
"req-audit-plugin": ("req-audit", "command", "req"),
"req-compare-plugin": ("req-compare", "skill", "req"),
"req-design-plugin": ("req-design", "skill", "req"),
"req-dev-plugin": ("req-dev", "skill", "req"),
"req-lookback-plugin": ("req-lookback", "command", "req"),
"req-plugin": ("req", "skill", "req"),
"req-prd-plugin": ("req-prd", "skill", "req"),
"req-prototype-plugin": ("req-prototype", "skill", "req"),
"req-research-plugin": ("req-research", "skill", "req"),
"req-retro-plugin": ("req-retro", "command", "req"),
"req-review-plugin": ("req-review", "skill", "req"),
"req-test-gate-plugin": ("req-test-gate", "skill", "req"),
"req-workflow-plugin": ("req-workflow", "skill", "req"),
}
BASE = os.path.dirname(os.path.abspath(__file__))
updated = 0
skipped = 0
missing = []
for plugin_name, (install_name, install_type, dir_category) in PLUGIN_MAP.items():
# Find the plugin directory
found = False
for cat_dir in os.listdir(BASE):
if not cat_dir.startswith("skills-"):
continue
plugin_dir = os.path.join(BASE, cat_dir, plugin_name)
if os.path.isdir(plugin_dir):
json_path = os.path.join(plugin_dir, ".claude-plugin", "plugin.json")
if os.path.exists(json_path):
with open(json_path) as f:
data = json.load(f)
data["install_name"] = install_name
data["install_type"] = install_type
data["dir_category"] = dir_category
with open(json_path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
print(f"{plugin_name}{install_type}:{install_name}")
updated += 1
found = True
break
if not found:
missing.append(plugin_name)
print(f"\nUpdated: {updated}, Missing plugin dirs: {len(missing)}")
if missing:
print("Missing:", missing)