From e5805cbb51bac502b9143f226a9ca85176c8161f Mon Sep 17 00:00:00 2001 From: John Qiu Date: Sun, 19 Apr 2026 13:33:26 +0930 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20P1-10/12/13/14=20=E9=A3=8E=E9=99=A9?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=20+=20=E7=B2=92=E5=BA=A6=E5=88=A4=E6=96=AD?= =?UTF-8?q?=20+=20Issue=20=E9=9B=86=E6=88=90=20+=20PRD=20=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=20(REQ-20260416-0017)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .claude-plugin/marketplace.json | 12 ++ hooks/validate-prd.sh | 98 +++++++++++ .../pm-risk-plugin/.claude-plugin/plugin.json | 8 + skills-core/pm-risk-plugin/skills/SKILL.md | 154 ++++++++++++++++++ skills-dev/dev-commit-plugin/skills/SKILL.md | 42 +++++ skills-req/req-prd-plugin/skills/SKILL.md | 75 +++++++++ 6 files changed, 389 insertions(+) create mode 100755 hooks/validate-prd.sh create mode 100644 skills-core/pm-risk-plugin/.claude-plugin/plugin.json create mode 100644 skills-core/pm-risk-plugin/skills/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c8b26ac..456a72a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -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", diff --git a/hooks/validate-prd.sh b/hooks/validate-prd.sh new file mode 100755 index 0000000..6b37e44 --- /dev/null +++ b/hooks/validate-prd.sh @@ -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: "/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 diff --git a/skills-core/pm-risk-plugin/.claude-plugin/plugin.json b/skills-core/pm-risk-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..03cadb3 --- /dev/null +++ b/skills-core/pm-risk-plugin/.claude-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "pm-risk-plugin", + "description": "三维度项目风险扫描:需求层/代码层/流程层。当用户说'/risk'、'风险扫描'、'有什么风险'时自动激活", + "version": "1.0.0", + "author": { + "name": "qiudl" + } +} diff --git a/skills-core/pm-risk-plugin/skills/SKILL.md b/skills-core/pm-risk-plugin/skills/SKILL.md new file mode 100644 index 0000000..6b3b08c --- /dev/null +++ b/skills-core/pm-risk-plugin/skills/SKILL.md @@ -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 diff --git a/skills-dev/dev-commit-plugin/skills/SKILL.md b/skills-dev/dev-commit-plugin/skills/SKILL.md index 858393f..053e5ba 100644 --- a/skills-dev/dev-commit-plugin/skills/SKILL.md +++ b/skills-dev/dev-commit-plugin/skills/SKILL.md @@ -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 进行中的 diff --git a/skills-req/req-prd-plugin/skills/SKILL.md b/skills-req/req-prd-plugin/skills/SKILL.md index 07f49e6..8e9dc56 100644 --- a/skills-req/req-prd-plugin/skills/SKILL.md +++ b/skills-req/req-prd-plugin/skills/SKILL.md @@ -172,6 +172,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 用户积分规则-修改接口 +``` + +--- + ## 用户故事编写 ### 标准格式 From 84d4e35a42e0096b7980ae1a1087e8b2916b26a2 Mon Sep 17 00:00:00 2001 From: John Qiu Date: Mon, 20 Apr 2026 18:06:32 +0930 Subject: [PATCH 2/6] =?UTF-8?q?feat(req-prototype):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20HTML=20=E4=B8=8A=E4=BC=A0=E6=A8=A1=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8D=87=E8=87=B3=20v2.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 /req prototype upload 子命令(推荐模式) - 含完整 curl 上传流程、HTML 设计规范及模板 - 更新错误处理与版本管理说明 - marketplace 更新(49 个插件) Co-Authored-By: Claude Sonnet 4.6 --- .claude-plugin/marketplace.json | 4 +- .../.claude-plugin/plugin.json | 4 +- .../req-prototype-plugin/skills/SKILL.md | 164 +++++++++++++++++- 3 files changed, 159 insertions(+), 13 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 456a72a..5dc38c8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -358,8 +358,8 @@ { "name": "req-prototype-plugin", "source": "./skills-req/req-prototype-plugin", - "description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。", - "version": "1.0.0", + "description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。", + "version": "2.0.0", "category": "productivity", "keywords": [ "project-management", diff --git a/skills-req/req-prototype-plugin/.claude-plugin/plugin.json b/skills-req/req-prototype-plugin/.claude-plugin/plugin.json index 03a6ced..911d606 100644 --- a/skills-req/req-prototype-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-prototype-plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "req-prototype-plugin", - "description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。", - "version": "1.0.0", + "description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。", + "version": "2.0.0", "author": { "name": "qiudl" } diff --git a/skills-req/req-prototype-plugin/skills/SKILL.md b/skills-req/req-prototype-plugin/skills/SKILL.md index 68295d1..1265144 100644 --- a/skills-req/req-prototype-plugin/skills/SKILL.md +++ b/skills-req/req-prototype-plugin/skills/SKILL.md @@ -1,16 +1,19 @@ --- 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 或需要生成/上传界面原型时使用。 +arguments: [REQ-ID] [upload|edit|variant] [--device desktop|mobile|tablet] [--model pro|flash] [--note "..."] [--prompt "..."] --- -# Stitch 原型设计 Skill (req-prototype) +# 原型设计 Skill (req-prototype) ## 概述 -基于 PRD 文档自动生成 Stitch UI 原型,插入在 PRD 编写完成后、submit 评审前。 +支持两种原型工作流: -**核心流程**:读取 PRD → 提取 UI 描述 → 转英文 prompt → 调用 Stitch API → 截图回填 PRD +| 模式 | 命令 | 适用场景 | 输出 | +|------|------|----------|------| +| **HTML 上传** | `/req prototype upload` | 快速展示、评审用静态原型 | iframe 嵌入需求详情页 | +| **Stitch AI** | `/req prototype` | 精细 UI 设计、多屏交互 | 截图回填 PRD 文档 | ## 前置条件 @@ -18,13 +21,132 @@ arguments: [REQ-ID] [--device desktop|mobile|tablet] [--model pro|flash] [--prom | 检查项 | 方式 | 失败处理 | |--------|------|----------| -| 需求存在 | `ai-proj req get --id ` | 报错:需求不存在 | -| PRD 文档存在 | `ai-proj req tasks --id ` 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd 编写 PRD | -| PRD 包含 UI 描述 | 检查 PRD 中「功能需求」「交互设计」「界面原型」章节 | 警告:PRD 未包含 UI 相关描述,建议先补充 | +| 需求存在 | `mcp__ai-proj__get_requirement` | 报错:需求不存在 | +| 后端运行中(upload 模式)| `curl http://localhost:8080/api/v1/health` | 报错:后端未启动 | +| PRD 文档存在(Stitch 模式)| 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd | ## 子命令 -### 1. `/req prototype [REQ-ID]` — 生成原型 +### 0. `/req prototype upload [REQ-ID] [--note "版本说明"]` — 上传 HTML 原型(**推荐**) + +**适用场景**:快速为需求关联一个带样式的 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览交互流程。 + +**执行流程**: + +``` +1. 获取需求信息(mcp__ai-proj__get_requirement) +2. 读取 PRD 或需求描述,提炼 UI 关键信息 +3. AI 编写带完整样式的 HTML 原型文件(见设计规范) +4. 保存到 /tmp/proto__.html +5. 获取本地 JWT token(登录 API) +6. 上传到后端(multipart POST) +7. 确认上传成功,输出预览 URL +``` + +**Step 5-6 执行方式**: + +```bash +# 5. 获取 token(本地开发环境) +TOKEN=$(curl -s http://localhost:8080/api/v1/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"qiudl","password":"Admin@2026~"}' \ + | python3 -c 'import sys,json; print(json.load(sys.stdin)["data"]["access_token"])') + +# 6. 上传 HTML 原型并关联到需求 +curl -s -X POST "http://localhost:8080/api/v1/requirements//prototype" \ + -H "Authorization: Bearer $TOKEN" \ + -F "file=@/tmp/proto__.html;type=text/html" \ + -F "version_note=<--note 的值或空>" +``` + +**成功响应**: + +```json +{ + "success": true, + "data": { + "url": "/api/v1/uploads/prototypes/proto_xxx.html", + "version_note": "...", + "uploaded_at": "..." + } +} +``` + +**效果**:需求详情页(`/requirements/` 或 `/platform/requirements/`)自动出现「原型预览」卡片,iframe 加载上传的 HTML。 + +**参数**: + +| 参数 | 默认值 | 说明 | +|------|--------|------| +| `--note` | 空 | 版本说明,如"初稿 v1"、"评审修改版" | + +--- + +#### HTML 原型设计规范 + +AI 生成的 HTML 原型必须满足以下要求: + +**结构要求**: +- 完整独立的 HTML 文件(含 `` + `` + ``) +- 所有样式内联在 ` + + +
+
+ +
+
+
+ 🎨 原型预览 · [REQ-ID] — [需求标题] + v1.0 · [日期] · 仅供评审参考 +
+ + +``` + +--- + +### 1. `/req prototype [REQ-ID]` — Stitch AI 生成原型 **流程**: @@ -154,6 +276,18 @@ generated_at: "" ## 异常处理 +### Upload 模式 + +| 异常 | 处理 | +|------|------| +| 后端 500 / `column prototype_urls does not exist` | 需执行数据库迁移:`psql -U -d -c "ALTER TABLE requirements ADD COLUMN IF NOT EXISTS prototype_urls JSONB DEFAULT '[]';"` | +| token 获取失败(401)| 检查用户名密码,或改用生产环境 token | +| 需求 ID 不存在(404)| 确认使用数据库自增 ID,而非 display_id(REQ-xxx) | +| HTML 文件超过 5MB | 精简样式或拆分多版本上传 | +| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 | + +### Stitch 模式 + | 异常 | 处理 | |------|------| | 需求无 PRD 文档 | 报错:`请先使用 req-prd 技能编写 PRD 文档` | @@ -162,3 +296,15 @@ generated_at: "" | Stitch API 返回错误 | 展示错误信息,建议调整 prompt 或更换模型 | | PRD 无「4.2 界面原型」章节 | 在「## 4. 交互设计」末尾自动追加该章节 | | 已有原型元数据 | 询问:`已存在原型,是否覆盖?` | + +## 版本管理 + +每次 `/req prototype upload` 都会追加一个新版本(自增 `version` 字段),需求详情页支持版本切换下拉框。多个版本并存时,最新版本默认展示。 + +可多次上传来迭代原型: + +``` +v1 → 初稿(评审前) +v2 → 评审修改版 +v3 → 开发对齐版 +``` From de25f096e7e2768d3f385d8a984cf2191334d6cf Mon Sep 17 00:00:00 2001 From: John Qiu Date: Mon, 20 Apr 2026 23:55:26 +0930 Subject: [PATCH 3/6] feat(sync): add install-skills.sh + install metadata to all 62 plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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//, command→~/.claude/commands/.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 --- .claude-plugin/marketplace.json | 164 +++++ install-skills.sh | 314 ++++++++ .../.claude-plugin/plugin.json | 5 +- .../biz-ops-plugin/.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../finance-plugin/.claude-plugin/plugin.json | 5 +- .../ai-proj-plugin/.claude-plugin/plugin.json | 5 +- .../pm-ask-plugin/.claude-plugin/plugin.json | 5 +- .../pm-risk-plugin/.claude-plugin/plugin.json | 5 +- .../publish-plugin/.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 11 + skills-dev/agent-swarm-plugin/skills/SKILL.md | 406 ++++++++++ .../ai-chat-plugin/.claude-plugin/plugin.json | 11 + skills-dev/ai-chat-plugin/skills/SKILL.md | 537 ++++++++++++++ .../.claude-plugin/plugin.json | 7 +- .../.claude-plugin/plugin.json | 11 + .../defect-analysis-plugin/skills/SKILL.md | 159 ++++ .../.claude-plugin/plugin.json | 7 +- .../.claude-plugin/plugin.json | 12 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../dev-ios-plugin/.claude-plugin/plugin.json | 12 +- .../dev-mcp-plugin/.claude-plugin/plugin.json | 12 +- .../dev-pda-plugin/.claude-plugin/plugin.json | 12 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 7 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 11 + .../executing-plans-plugin/skills/SKILL.md | 96 +++ .../.claude-plugin/plugin.json | 11 + .../finishing-branch-plugin/skills/SKILL.md | 104 +++ .../.claude-plugin/plugin.json | 11 + .../frontend-design-plugin/skills/SKILL.md | 695 ++++++++++++++++++ .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../feishu-plugin/.claude-plugin/plugin.json | 5 +- .../siyuan-plugin/.claude-plugin/plugin.json | 5 +- .../siyuan-plugin/skills/SKILL.md | 210 ++---- .../.claude-plugin/plugin.json | 5 +- .../wecom-plugin/.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 11 + skills-req/req-audit-plugin/skills/SKILL.md | 105 +++ .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../req-dev-plugin/.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 11 + .../req-lookback-plugin/skills/SKILL.md | 87 +++ .../req-plugin/.claude-plugin/plugin.json | 5 +- .../req-prd-plugin/.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 7 +- .../.claude-plugin/plugin.json | 11 + skills-req/req-retro-plugin/skills/SKILL.md | 150 ++++ .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- .../.claude-plugin/plugin.json | 5 +- update-plugin-meta.py | 119 +++ 66 files changed, 3307 insertions(+), 194 deletions(-) create mode 100755 install-skills.sh create mode 100644 skills-dev/agent-swarm-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/agent-swarm-plugin/skills/SKILL.md create mode 100644 skills-dev/ai-chat-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/ai-chat-plugin/skills/SKILL.md create mode 100644 skills-dev/defect-analysis-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/defect-analysis-plugin/skills/SKILL.md create mode 100644 skills-dev/executing-plans-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/executing-plans-plugin/skills/SKILL.md create mode 100644 skills-dev/finishing-branch-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/finishing-branch-plugin/skills/SKILL.md create mode 100644 skills-dev/frontend-design-plugin/.claude-plugin/plugin.json create mode 100644 skills-dev/frontend-design-plugin/skills/SKILL.md create mode 100644 skills-req/req-audit-plugin/.claude-plugin/plugin.json create mode 100644 skills-req/req-audit-plugin/skills/SKILL.md create mode 100644 skills-req/req-lookback-plugin/.claude-plugin/plugin.json create mode 100644 skills-req/req-lookback-plugin/skills/SKILL.md create mode 100644 skills-req/req-retro-plugin/.claude-plugin/plugin.json create mode 100644 skills-req/req-retro-plugin/skills/SKILL.md create mode 100644 update-plugin-meta.py diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 5dc38c8..1409122 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -71,6 +71,30 @@ ], "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": "db-migration-plugin", "source": "./skills-dev/db-migration-plugin", @@ -83,6 +107,18 @@ ], "strict": false }, + { + "name": "defect-analysis-plugin", + "source": "./skills-dev/defect-analysis-plugin", + "description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。", + "version": "1.0.0", + "category": "utility", + "keywords": [ + "utility", + "tools" + ], + "strict": false + }, { "name": "deploy-rollback-plugin", "source": "./skills-dev/deploy-rollback-plugin", @@ -265,6 +301,43 @@ ], "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.0", + "category": "development", + "keywords": [ + "development", + "coding", + "workflow" + ], + "strict": false + }, { "name": "pull-request-plugin", "source": "./skills-dev/pull-request-plugin", @@ -290,6 +363,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", @@ -329,6 +415,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", @@ -381,6 +480,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", @@ -597,6 +709,19 @@ ], "strict": false }, + { + "name": "ops-servers-plugin", + "source": "./skills-personal/ops-servers-plugin", + "description": "企业服务器管理。用于云服务器分组管理、系统监控、备份管理、故障排查。当用户提到云服务器、生产环境、腾讯云、阿里云相关任务时自动激活。", + "version": "1.0.0", + "category": "devops", + "keywords": [ + "devops", + "deployment", + "operations" + ], + "strict": false + }, { "name": "ops-tools-plugin", "source": "./skills-personal/ops-tools-plugin", @@ -622,6 +747,19 @@ ], "strict": false }, + { + "name": "reload-session-plugin", + "source": "./skills-personal/reload-session-plugin", + "description": "Reload a previously saved Claude session to continue the conversation.", + "version": "1.0.0", + "category": "workflow", + "keywords": [ + "session", + "workflow", + "productivity" + ], + "strict": false + }, { "name": "req-deploy-plugin", "source": "./skills-personal/req-deploy-plugin", @@ -634,6 +772,32 @@ "operations" ], "strict": false + }, + { + "name": "save-session-plugin", + "source": "./skills-personal/save-session-plugin", + "description": "Auto-save Claude session conversation with AI-generated title, summary, and tags in searchable JSON format.", + "version": "1.0.0", + "category": "workflow", + "keywords": [ + "session", + "workflow", + "productivity" + ], + "strict": false + }, + { + "name": "search-sessions-plugin", + "source": "./skills-personal/search-sessions-plugin", + "description": "Search saved Claude sessions by title, tags, date, or content.", + "version": "1.0.0", + "category": "workflow", + "keywords": [ + "session", + "workflow", + "productivity" + ], + "strict": false } ] } \ No newline at end of file diff --git a/install-skills.sh b/install-skills.sh new file mode 100755 index 0000000..9038bfe --- /dev/null +++ b/install-skills.sh @@ -0,0 +1,314 @@ +#!/usr/bin/env bash +# install-skills.sh — Cross-machine Claude skill sync from ai-proj-helper +# +# Usage: +# ./install-skills.sh [options] +# +# Options: +# --dry-run Preview changes without writing anything +# --category Only install plugins in dir_category= +# Valid values: biz, core, dev, integration, personal, req +# --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="${HOME}/.claude/skills" +COMMANDS_DIR="${HOME}/.claude/commands" +STATE_FILE="${HOME}/.claude/.installed-skills.json" + +DRY_RUN=false +CATEGORY_FILTER="" +FORCE=false +CLEANUP=false +LIST_ONLY=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 + --dry-run) DRY_RUN=true ;; + --force) FORCE=true ;; + --cleanup) CLEANUP=true ;; + --list) LIST_ONLY=true ;; + --category) CATEGORY_FILTER="$2"; shift ;; + --help|-h) + grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//' + exit 0 ;; + *) + error "Unknown argument: $1" + exit 1 ;; + esac + shift +done + +# ── State helpers (plain JSON via python3) ───────────────────────────────────── +state_get() { + # state_get -> 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_set() { + # state_set + local name="$1" ver="$2" itype="$3" + 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'} +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 + python3 -c "import json,sys; d=json.load(open('$1')); print(d.get('$2',''))" 2>/dev/null || true +} + +# ── Conflict detection (has local been modified since we installed it?) ──────── +has_local_modification() { + # Returns 0 (true) if local target differs from repo source, 1 if identical or new + local install_name="$1" install_type="$2" plugin_skills_dir="$3" + + if [[ "$install_type" == "command" ]]; then + local src="$plugin_skills_dir/SKILL.md" + local dst="$COMMANDS_DIR/${install_name}.md" + [[ -f "$dst" ]] && ! diff -q "$src" "$dst" &>/dev/null && return 0 + else + local dst_dir="$SKILLS_DIR/$install_name" + if [[ -d "$dst_dir" ]]; then + # Compare each file from source + while IFS= read -r -d '' src_file; do + local rel="${src_file#$plugin_skills_dir/}" + local dst_file="$dst_dir/$rel" + if [[ -f "$dst_file" ]] && ! diff -q "$src_file" "$dst_file" &>/dev/null; then + return 0 + fi + done < <(find "$plugin_skills_dir" -type f -print0) + fi + fi + return 1 +} + +# ── Install a single plugin ──────────────────────────────────────────────────── +install_plugin() { + 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)" + + # 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 + + if [[ "$LIST_ONLY" == true ]]; then + echo " [$dir_category] $install_type:$install_name v$version" + return + fi + + # Check current installed version + local current_version + current_version="$(state_get "$install_name")" + + # Skip if up-to-date (same version) and no force + if [[ "$current_version" == "$version" && "$FORCE" == false ]]; then + return + fi + + # Conflict detection: warn if local files were modified + if [[ -n "$current_version" && "$FORCE" == false ]]; then + if has_local_modification "$install_name" "$install_type" "$skills_dir"; then + warn "$install_name: local files were modified — skipping (use --force to overwrite)" + return + fi + fi + + # Perform install + if [[ "$install_type" == "command" ]]; then + # Single-file command → ~/.claude/commands/.md + local src_md="$skills_dir/SKILL.md" + if [[ ! -f "$src_md" ]]; then + warn "$install_name: skills/SKILL.md not found, skipping" + return + fi + + if [[ "$DRY_RUN" == true ]]; then + dry "$install_name → $COMMANDS_DIR/${install_name}.md" + else + mkdir -p "$COMMANDS_DIR" + cp "$src_md" "$COMMANDS_DIR/${install_name}.md" + state_set "$install_name" "$version" "$install_type" + ok "$install_name → command (v$version)" + fi + + else + # Skill directory → ~/.claude/skills// + local dst_dir="$SKILLS_DIR/$install_name" + + if [[ "$DRY_RUN" == true ]]; then + dry "$install_name → $dst_dir/" + else + mkdir -p "$dst_dir" + # rsync: copy entire skills/ directory content preserving structure + rsync -a --delete "$skills_dir/" "$dst_dir/" + state_set "$install_name" "$version" "$install_type" + ok "$install_name → skill (v$version)" + 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 Claude skills 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 skipped=0 + + while IFS= read -r json_path; do + local before + before="$(state_all_names | wc -l || true)" + install_plugin "$json_path" + local after + after="$(state_all_names | wc -l || true)" + if [[ "$after" -gt "$before" ]] || [[ "$DRY_RUN" == 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 "$@" diff --git a/skills-biz/biz-contract-plugin/.claude-plugin/plugin.json b/skills-biz/biz-contract-plugin/.claude-plugin/plugin.json index a732260..4658d47 100644 --- a/skills-biz/biz-contract-plugin/.claude-plugin/plugin.json +++ b/skills-biz/biz-contract-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "biz-contract", + "install_type": "skill", + "dir_category": "biz" } diff --git a/skills-biz/biz-ops-plugin/.claude-plugin/plugin.json b/skills-biz/biz-ops-plugin/.claude-plugin/plugin.json index bfcd3a6..5b69947 100644 --- a/skills-biz/biz-ops-plugin/.claude-plugin/plugin.json +++ b/skills-biz/biz-ops-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "biz-ops", + "install_type": "skill", + "dir_category": "biz" } diff --git a/skills-biz/biz-plan-plugin/.claude-plugin/plugin.json b/skills-biz/biz-plan-plugin/.claude-plugin/plugin.json index 0b4ec6b..137ad53 100644 --- a/skills-biz/biz-plan-plugin/.claude-plugin/plugin.json +++ b/skills-biz/biz-plan-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "biz-plan", + "install_type": "skill", + "dir_category": "biz" } diff --git a/skills-biz/finance-plugin/.claude-plugin/plugin.json b/skills-biz/finance-plugin/.claude-plugin/plugin.json index 4e75bfd..f5ba670 100644 --- a/skills-biz/finance-plugin/.claude-plugin/plugin.json +++ b/skills-biz/finance-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "finance", + "install_type": "skill", + "dir_category": "biz" } diff --git a/skills-core/ai-proj-plugin/.claude-plugin/plugin.json b/skills-core/ai-proj-plugin/.claude-plugin/plugin.json index a994a19..a666380 100644 --- a/skills-core/ai-proj-plugin/.claude-plugin/plugin.json +++ b/skills-core/ai-proj-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.1", "author": { "name": "qiudl" - } + }, + "install_name": "ai-proj", + "install_type": "skill", + "dir_category": "core" } diff --git a/skills-core/pm-ask-plugin/.claude-plugin/plugin.json b/skills-core/pm-ask-plugin/.claude-plugin/plugin.json index 7f91851..399aaaa 100644 --- a/skills-core/pm-ask-plugin/.claude-plugin/plugin.json +++ b/skills-core/pm-ask-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "pm-ask", + "install_type": "skill", + "dir_category": "core" } diff --git a/skills-core/pm-risk-plugin/.claude-plugin/plugin.json b/skills-core/pm-risk-plugin/.claude-plugin/plugin.json index 03cadb3..ea6be9f 100644 --- a/skills-core/pm-risk-plugin/.claude-plugin/plugin.json +++ b/skills-core/pm-risk-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "pm-risk", + "install_type": "skill", + "dir_category": "core" } diff --git a/skills-core/publish-plugin/.claude-plugin/plugin.json b/skills-core/publish-plugin/.claude-plugin/plugin.json index add959d..054192f 100644 --- a/skills-core/publish-plugin/.claude-plugin/plugin.json +++ b/skills-core/publish-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "publish", + "install_type": "skill", + "dir_category": "core" } diff --git a/skills-dev/agent-browser-plugin/.claude-plugin/plugin.json b/skills-dev/agent-browser-plugin/.claude-plugin/plugin.json index 3e66bf7..0239854 100644 --- a/skills-dev/agent-browser-plugin/.claude-plugin/plugin.json +++ b/skills-dev/agent-browser-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "agent-browser", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/agent-swarm-plugin/.claude-plugin/plugin.json b/skills-dev/agent-swarm-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..9b4d03d --- /dev/null +++ b/skills-dev/agent-swarm-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/agent-swarm-plugin/skills/SKILL.md b/skills-dev/agent-swarm-plugin/skills/SKILL.md new file mode 100644 index 0000000..52c8f61 --- /dev/null +++ b/skills-dev/agent-swarm-plugin/skills/SKILL.md @@ -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 ` | 启动 Swarm 工作流(从 Architect 开始) | +| `/swarm ` | 从指定 Agent 开始 | +| `/swarm parallel ` | 并行执行多个任务 | +| `/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) diff --git a/skills-dev/ai-chat-plugin/.claude-plugin/plugin.json b/skills-dev/ai-chat-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..ca93b16 --- /dev/null +++ b/skills-dev/ai-chat-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/ai-chat-plugin/skills/SKILL.md b/skills-dev/ai-chat-plugin/skills/SKILL.md new file mode 100644 index 0000000..1f9ff8b --- /dev/null +++ b/skills-dev/ai-chat-plugin/skills/SKILL.md @@ -0,0 +1,537 @@ +--- +name: ai-chat +description: AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。 +arguments: [args] +--- + +# AI Chat Skill + +测试和管理 Coolbuy PaaS AI Chat 服务的 Claude Code skill。 + +## Quick Reference + +| 命令 | 用途 | +|------|------| +| `/ai-chat send ` | 发送消息到 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 ` + +实现步骤: + +#### 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": ""} +] +``` + +#### 完整 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 ` — 按分类过滤 + +实现步骤: + +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: ""` | 增量文本内容 | +| `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: ""` | 错误 | + +--- + +## 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 解析失败。 diff --git a/skills-dev/db-migration-plugin/.claude-plugin/plugin.json b/skills-dev/db-migration-plugin/.claude-plugin/plugin.json index 77bb96c..cd00429 100644 --- a/skills-dev/db-migration-plugin/.claude-plugin/plugin.json +++ b/skills-dev/db-migration-plugin/.claude-plugin/plugin.json @@ -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" } diff --git a/skills-dev/defect-analysis-plugin/.claude-plugin/plugin.json b/skills-dev/defect-analysis-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..03134a6 --- /dev/null +++ b/skills-dev/defect-analysis-plugin/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "defect-analysis-plugin", + "description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。", + "version": "1.0.0", + "author": { + "name": "qiudl" + }, + "install_name": "defect-analysis", + "install_type": "command", + "dir_category": "dev" +} diff --git a/skills-dev/defect-analysis-plugin/skills/SKILL.md b/skills-dev/defect-analysis-plugin/skills/SKILL.md new file mode 100644 index 0000000..1821b0c --- /dev/null +++ b/skills-dev/defect-analysis-plugin/skills/SKILL.md @@ -0,0 +1,159 @@ +--- +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 轮后仍有新发现 → 继续,最多 10 轮 +- 每个缺陷标注严重度和轮次 + +## 输出格式 + +对每个缺陷: + +``` +### 缺陷 #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 + 事件委托 | diff --git a/skills-dev/deploy-rollback-plugin/.claude-plugin/plugin.json b/skills-dev/deploy-rollback-plugin/.claude-plugin/plugin.json index d67a17c..d88fcaa 100644 --- a/skills-dev/deploy-rollback-plugin/.claude-plugin/plugin.json +++ b/skills-dev/deploy-rollback-plugin/.claude-plugin/plugin.json @@ -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" } diff --git a/skills-dev/dev-android-plugin/.claude-plugin/plugin.json b/skills-dev/dev-android-plugin/.claude-plugin/plugin.json index 863e3ef..0a33377 100644 --- a/skills-dev/dev-android-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-android-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/dev-arch-plugin/.claude-plugin/plugin.json b/skills-dev/dev-arch-plugin/.claude-plugin/plugin.json index e0e65b4..e4123b5 100644 --- a/skills-dev/dev-arch-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-arch-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-arch", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-cicd-plugin/.claude-plugin/plugin.json b/skills-dev/dev-cicd-plugin/.claude-plugin/plugin.json index c0c6743..623a26f 100644 --- a/skills-dev/dev-cicd-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-cicd-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-cicd", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-coding-plugin/.claude-plugin/plugin.json b/skills-dev/dev-coding-plugin/.claude-plugin/plugin.json index 7be72cb..aeb2016 100644 --- a/skills-dev/dev-coding-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-coding-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-coding", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-commit-plugin/.claude-plugin/plugin.json b/skills-dev/dev-commit-plugin/.claude-plugin/plugin.json index fe2fbea..e8389b8 100644 --- a/skills-dev/dev-commit-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-commit-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-commit", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-deploy-plugin/.claude-plugin/plugin.json b/skills-dev/dev-deploy-plugin/.claude-plugin/plugin.json index cec55fd..29a0717 100644 --- a/skills-dev/dev-deploy-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-deploy-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-deploy", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-integration-plugin/.claude-plugin/plugin.json b/skills-dev/dev-integration-plugin/.claude-plugin/plugin.json index c491d86..3573a44 100644 --- a/skills-dev/dev-integration-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-integration-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-integration", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-ios-plugin/.claude-plugin/plugin.json b/skills-dev/dev-ios-plugin/.claude-plugin/plugin.json index 62337ee..a953299 100644 --- a/skills-dev/dev-ios-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-ios-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/dev-mcp-plugin/.claude-plugin/plugin.json b/skills-dev/dev-mcp-plugin/.claude-plugin/plugin.json index 1a19af3..8cd8722 100644 --- a/skills-dev/dev-mcp-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-mcp-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/dev-pda-plugin/.claude-plugin/plugin.json b/skills-dev/dev-pda-plugin/.claude-plugin/plugin.json index 2f8daad..7cf877b 100644 --- a/skills-dev/dev-pda-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-pda-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/dev-review-plugin/.claude-plugin/plugin.json b/skills-dev/dev-review-plugin/.claude-plugin/plugin.json index 584b9bb..627a950 100644 --- a/skills-dev/dev-review-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-review-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-review", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/dev-scaffold-plugin/.claude-plugin/plugin.json b/skills-dev/dev-scaffold-plugin/.claude-plugin/plugin.json index cf8075c..87adcc6 100644 --- a/skills-dev/dev-scaffold-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-scaffold-plugin/.claude-plugin/plugin.json @@ -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" } diff --git a/skills-dev/dev-test-plugin/.claude-plugin/plugin.json b/skills-dev/dev-test-plugin/.claude-plugin/plugin.json index de2c398..e16178d 100644 --- a/skills-dev/dev-test-plugin/.claude-plugin/plugin.json +++ b/skills-dev/dev-test-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "dev-test", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/executing-plans-plugin/.claude-plugin/plugin.json b/skills-dev/executing-plans-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..4478ed8 --- /dev/null +++ b/skills-dev/executing-plans-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/executing-plans-plugin/skills/SKILL.md b/skills-dev/executing-plans-plugin/skills/SKILL.md new file mode 100644 index 0000000..3dc267e --- /dev/null +++ b/skills-dev/executing-plans-plugin/skills/SKILL.md @@ -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 + # 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 / 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 diff --git a/skills-dev/finishing-branch-plugin/.claude-plugin/plugin.json b/skills-dev/finishing-branch-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..0f34a37 --- /dev/null +++ b/skills-dev/finishing-branch-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-dev/finishing-branch-plugin/skills/SKILL.md b/skills-dev/finishing-branch-plugin/skills/SKILL.md new file mode 100644 index 0000000..b07c4ee --- /dev/null +++ b/skills-dev/finishing-branch-plugin/skills/SKILL.md @@ -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 ( 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 . Remove it now? (y/n) +``` + +If confirmed: +```bash +git worktree remove +``` + +## 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 diff --git a/skills-dev/frontend-design-plugin/.claude-plugin/plugin.json b/skills-dev/frontend-design-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..70a01e4 --- /dev/null +++ b/skills-dev/frontend-design-plugin/.claude-plugin/plugin.json @@ -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.0", + "author": { + "name": "qiudl" + }, + "install_name": "frontend-design", + "install_type": "skill", + "dir_category": "dev" +} diff --git a/skills-dev/frontend-design-plugin/skills/SKILL.md b/skills-dev/frontend-design-plugin/skills/SKILL.md new file mode 100644 index 0000000..f34ae42 --- /dev/null +++ b/skills-dev/frontend-design-plugin/skills/SKILL.md @@ -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] +--- + +# 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 = ({ + variant = 'primary', + size = 'md', + disabled = false, + children, + onClick, +}) => { + return ( +
+ {children} +
+ ); +}; +``` + +#### 2. Storybook Stories (Component.stories.tsx) + +```tsx +import type { Meta, StoryObj } from '@storybook/react'; +import { Component } from './Component'; + +const meta: Meta = { + 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; + +/** 默认状态 */ +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: () => ( +
+ 小号 + 中号 + 大号 +
+ ), +}; + +/** 禁用状态 */ +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 = ({ + image, + title, + location, + rating, + reviewCount, + price, + originalPrice, + tags = [], + onAddToCart, +}) => { + return ( +
+
+ {title} + {tags.length > 0 && ( +
+ {tags.map((tag) => ( + + {tag} + + ))} +
+ )} +
+ +
+

{title}

+

📍 {location}

+ +
+ ⭐ {rating.toFixed(1)} + ({reviewCount}条评价) +
+ +
+
+ ¥ + {price} + +
+ {originalPrice && ( + ¥{originalPrice} + )} +
+ + +
+
+ ); +}; +``` + +```tsx +// ProductCard.stories.tsx +import type { Meta, StoryObj } from '@storybook/react'; +import { ProductCard } from './ProductCard'; + +const meta: Meta = { + title: 'Components/ProductCard', + component: ProductCard, + tags: ['autodocs'], + parameters: { + layout: 'centered', + backgrounds: { + default: 'light', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +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: () => ( +
+ + + +
+ ), +}; +``` + +### 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 = ({ + variant = 'primary', + size = 'md', + fullWidth = false, + loading = false, + disabled = false, + leftIcon, + rightIcon, + children, + onClick, +}) => { + return ( + + ); +}; +``` + +--- + +## 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 配置完整 +- [ ] 包含组件文档描述 +- [ ] 交互状态可测试 +- [ ] 响应式展示 + +### 视觉质量检查 + +- [ ] 字体选择有特色 +- [ ] 配色方案协调 +- [ ] 动画流畅自然 +- [ ] 间距一致 +- [ ] 暗色主题支持 diff --git a/skills-dev/pull-request-plugin/.claude-plugin/plugin.json b/skills-dev/pull-request-plugin/.claude-plugin/plugin.json index bafb656..a99fe87 100644 --- a/skills-dev/pull-request-plugin/.claude-plugin/plugin.json +++ b/skills-dev/pull-request-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "pull-request", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-dev/review-checklist-plugin/.claude-plugin/plugin.json b/skills-dev/review-checklist-plugin/.claude-plugin/plugin.json index 0ad2f48..ca7fe4e 100644 --- a/skills-dev/review-checklist-plugin/.claude-plugin/plugin.json +++ b/skills-dev/review-checklist-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "review-checklist", + "install_type": "skill", + "dir_category": "dev" } diff --git a/skills-integration/data-excel-plugin/.claude-plugin/plugin.json b/skills-integration/data-excel-plugin/.claude-plugin/plugin.json index 5a42b7e..7398824 100644 --- a/skills-integration/data-excel-plugin/.claude-plugin/plugin.json +++ b/skills-integration/data-excel-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "data-excel", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/doubao-voice-plugin/.claude-plugin/plugin.json b/skills-integration/doubao-voice-plugin/.claude-plugin/plugin.json index 6b90226..b90b94f 100644 --- a/skills-integration/doubao-voice-plugin/.claude-plugin/plugin.json +++ b/skills-integration/doubao-voice-plugin/.claude-plugin/plugin.json @@ -10,5 +10,8 @@ "name": "doubao-voice", "path": "./skills/SKILL.md" } - ] + ], + "install_name": "doubao-voice", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/feishu-bitable-plugin/.claude-plugin/plugin.json b/skills-integration/feishu-bitable-plugin/.claude-plugin/plugin.json index ee9dc71..dee9a37 100644 --- a/skills-integration/feishu-bitable-plugin/.claude-plugin/plugin.json +++ b/skills-integration/feishu-bitable-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "feishu-bitable", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/feishu-docx-plugin/.claude-plugin/plugin.json b/skills-integration/feishu-docx-plugin/.claude-plugin/plugin.json index 8abd968..4220e7d 100644 --- a/skills-integration/feishu-docx-plugin/.claude-plugin/plugin.json +++ b/skills-integration/feishu-docx-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "feishu-docx", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/feishu-plugin/.claude-plugin/plugin.json b/skills-integration/feishu-plugin/.claude-plugin/plugin.json index 8df5502..c0afda0 100644 --- a/skills-integration/feishu-plugin/.claude-plugin/plugin.json +++ b/skills-integration/feishu-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.1.0", "author": { "name": "qiudl" - } + }, + "install_name": "feishu", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/siyuan-plugin/.claude-plugin/plugin.json b/skills-integration/siyuan-plugin/.claude-plugin/plugin.json index 3dbaeab..1cf0985 100644 --- a/skills-integration/siyuan-plugin/.claude-plugin/plugin.json +++ b/skills-integration/siyuan-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "siyuan", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/siyuan-plugin/skills/SKILL.md b/skills-integration/siyuan-plugin/skills/SKILL.md index 1d7f2ac..cbfd7b9 100644 --- a/skills-integration/siyuan-plugin/skills/SKILL.md +++ b/skills-integration/siyuan-plugin/skills/SKILL.md @@ -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}", diff --git a/skills-integration/siyuan-to-feishu-plugin/.claude-plugin/plugin.json b/skills-integration/siyuan-to-feishu-plugin/.claude-plugin/plugin.json index 0dc5ff8..da86a12 100644 --- a/skills-integration/siyuan-to-feishu-plugin/.claude-plugin/plugin.json +++ b/skills-integration/siyuan-to-feishu-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "siyuan-to-feishu", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-integration/wecom-plugin/.claude-plugin/plugin.json b/skills-integration/wecom-plugin/.claude-plugin/plugin.json index ac1cfe1..8055b95 100644 --- a/skills-integration/wecom-plugin/.claude-plugin/plugin.json +++ b/skills-integration/wecom-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "wecom", + "install_type": "skill", + "dir_category": "integration" } diff --git a/skills-req/req-audit-plugin/.claude-plugin/plugin.json b/skills-req/req-audit-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..36f7460 --- /dev/null +++ b/skills-req/req-audit-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-req/req-audit-plugin/skills/SKILL.md b/skills-req/req-audit-plugin/skills/SKILL.md new file mode 100644 index 0000000..5b713a7 --- /dev/null +++ b/skills-req/req-audit-plugin/skills/SKILL.md @@ -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'" +``` + +**降级 1:CI 日志**: +```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' +``` + +**降级 2:N/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` +- 任务标题: `【审计】部署后审计: {需求标题}` +- 报告附加到任务文档 diff --git a/skills-req/req-compare-plugin/.claude-plugin/plugin.json b/skills-req/req-compare-plugin/.claude-plugin/plugin.json index 76e7fb5..69bc546 100644 --- a/skills-req/req-compare-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-compare-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-compare", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-design-plugin/.claude-plugin/plugin.json b/skills-req/req-design-plugin/.claude-plugin/plugin.json index c525c3b..cf97828 100644 --- a/skills-req/req-design-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-design-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-design", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-dev-plugin/.claude-plugin/plugin.json b/skills-req/req-dev-plugin/.claude-plugin/plugin.json index dab1d98..e7cae69 100644 --- a/skills-req/req-dev-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-dev-plugin/.claude-plugin/plugin.json @@ -5,5 +5,8 @@ "deprecated": true, "author": { "name": "qiudl" - } + }, + "install_name": "req-dev", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-lookback-plugin/.claude-plugin/plugin.json b/skills-req/req-lookback-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..2b93921 --- /dev/null +++ b/skills-req/req-lookback-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-req/req-lookback-plugin/skills/SKILL.md b/skills-req/req-lookback-plugin/skills/SKILL.md new file mode 100644 index 0000000..d11b5a1 --- /dev/null +++ b/skills-req/req-lookback-plugin/skills/SKILL.md @@ -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` +- 任务标题: `【回归】回归测试: {需求标题}` +- 报告附加到任务文档 diff --git a/skills-req/req-plugin/.claude-plugin/plugin.json b/skills-req/req-plugin/.claude-plugin/plugin.json index 241823f..f5dc4f7 100644 --- a/skills-req/req-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-prd-plugin/.claude-plugin/plugin.json b/skills-req/req-prd-plugin/.claude-plugin/plugin.json index ed2cb41..6d88815 100644 --- a/skills-req/req-prd-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-prd-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-prd", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-prototype-plugin/.claude-plugin/plugin.json b/skills-req/req-prototype-plugin/.claude-plugin/plugin.json index 911d606..8c007b9 100644 --- a/skills-req/req-prototype-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-prototype-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "2.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-prototype", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-research-plugin/.claude-plugin/plugin.json b/skills-req/req-research-plugin/.claude-plugin/plugin.json index c459a16..18776b6 100644 --- a/skills-req/req-research-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-research-plugin/.claude-plugin/plugin.json @@ -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" } diff --git a/skills-req/req-retro-plugin/.claude-plugin/plugin.json b/skills-req/req-retro-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..04d5ff8 --- /dev/null +++ b/skills-req/req-retro-plugin/.claude-plugin/plugin.json @@ -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" +} diff --git a/skills-req/req-retro-plugin/skills/SKILL.md b/skills-req/req-retro-plugin/skills/SKILL.md new file mode 100644 index 0000000..05953c1 --- /dev/null +++ b/skills-req/req-retro-plugin/skills/SKILL.md @@ -0,0 +1,150 @@ +--- +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.3 + + audit_defect_score × 0.3 + + cr_density_score × 0.2 + + test_pass_rate × 0.2 + +audit_defect_score: + 0 缺陷 = 100 + 每个低级 -5 + 每个中级 -20 + 每个高级 -60 + 致命 = 0 + +cr_density_score: + 100 - (发现数 / 变更行数 × 1000) + 下限 0,上限 100 +``` + +### 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 | +``` + +更新汇总:重新计算近 10 次平均值和趋势箭头(↑↓→)。 + +超过 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次均 | 对比 | +|------|------|---------|------| +| 质量分 | 92 | 85 | ↑ | +| audit 缺陷 | 2(低) | 3.2 | ↓ | +| CR 发现 | 0 | 1.5 | ↓ | +| 测试通过率 | 100% | 95% | ↑ | + +## git 统计 +| 提交数 | 变更文件 | +行 | -行 | +|--------|---------|-----|-----| +| 3 | 1 | 279 | 2 | + +## 模式识别 +- {耗时/热区/改进 分析结果} + +## 经验教训(写入 memory) +- {AI 提取的非显然教训} + +## 技能更新 +- {已更新/无更新} +``` + +### 8. 写入 memory + +将有价值的经验写入 memory: +- 类型:`feedback` 或 `project` +- 只写非显然的、可指导未来工作的教训 +- 用户确认后写入 + +## 任务关联 + +- linkRole: `documentation` +- 任务标题: `【复盘】生命周期总结: {需求标题}` +- 04-生命周期总结.md 附加到任务文档 diff --git a/skills-req/req-review-plugin/.claude-plugin/plugin.json b/skills-req/req-review-plugin/.claude-plugin/plugin.json index e9fbd23..7fa0e38 100644 --- a/skills-req/req-review-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-review-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-review", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json b/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json index f567169..6b7d749 100644 --- a/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-test-gate", + "install_type": "skill", + "dir_category": "req" } diff --git a/skills-req/req-workflow-plugin/.claude-plugin/plugin.json b/skills-req/req-workflow-plugin/.claude-plugin/plugin.json index ab721c3..028eb48 100644 --- a/skills-req/req-workflow-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-workflow-plugin/.claude-plugin/plugin.json @@ -4,5 +4,8 @@ "version": "1.0.0", "author": { "name": "qiudl" - } + }, + "install_name": "req-workflow", + "install_type": "skill", + "dir_category": "req" } diff --git a/update-plugin-meta.py b/update-plugin-meta.py new file mode 100644 index 0000000..2df9b01 --- /dev/null +++ b/update-plugin-meta.py @@ -0,0 +1,119 @@ +#!/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// +# "command" -> ~/.claude/commands/.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 + "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"), + "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) From 2ab0a61eb9bc829e22cd95f02c5a6bc06e1f8e09 Mon Sep 17 00:00:00 2001 From: John Qiu Date: Tue, 21 Apr 2026 00:00:01 +0930 Subject: [PATCH 4/6] 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 --- install-skills.sh | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/install-skills.sh b/install-skills.sh index 9038bfe..94245da 100755 --- a/install-skills.sh +++ b/install-skills.sh @@ -116,6 +116,25 @@ read_field() { python3 -c "import json,sys; d=json.load(open('$1')); print(d.get('$2',''))" 2>/dev/null || true } +# 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" +} + # ── Conflict detection (has local been modified since we installed it?) ──────── has_local_modification() { # Returns 0 (true) if local target differs from repo source, 1 if identical or new @@ -193,12 +212,17 @@ install_plugin() { fi 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")" + # Perform install if [[ "$install_type" == "command" ]]; then # Single-file command → ~/.claude/commands/.md - local src_md="$skills_dir/SKILL.md" + local src_md="$src_dir/SKILL.md" if [[ ! -f "$src_md" ]]; then - warn "$install_name: skills/SKILL.md not found, skipping" + warn "$install_name: SKILL.md not found, skipping" return fi @@ -219,8 +243,8 @@ install_plugin() { dry "$install_name → $dst_dir/" else mkdir -p "$dst_dir" - # rsync: copy entire skills/ directory content preserving structure - rsync -a --delete "$skills_dir/" "$dst_dir/" + # rsync resolved source (handles nested skills/ structures) + rsync -a --delete "$src_dir/" "$dst_dir/" state_set "$install_name" "$version" "$install_type" ok "$install_name → skill (v$version)" fi From 011916ceb98ace486879e9c5a333a69074a686ef Mon Sep 17 00:00:00 2001 From: John Qiu Date: Tue, 21 Apr 2026 09:17:11 +0930 Subject: [PATCH 5/6] =?UTF-8?q?feat(req-review):=20=E6=96=B0=E5=A2=9E=20VP?= =?UTF-8?q?=20=E4=B8=89=E4=BB=B6=E5=A5=97=E5=BC=BA=E5=88=B6=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=EF=BC=88REQ-20260421-0002=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 结构检查表新增「VP 三件套」必须项 - 新增「VP 三件套强制检查」章节,含四项检查指标和驳回条件 - 常见驳回原因更新:验收不明包含 VP 缺失场景 Co-Authored-By: Claude Sonnet 4.6 --- skills-req/req-review-plugin/skills/SKILL.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/skills-req/req-review-plugin/skills/SKILL.md b/skills-req/req-review-plugin/skills/SKILL.md index 559f322..1d20edc 100644 --- a/skills-req/req-review-plugin/skills/SKILL.md +++ b/skills-req/req-review-plugin/skills/SKILL.md @@ -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 | From e3513f137b82f12f9a784424b5a0b3a319ced1df Mon Sep 17 00:00:00 2001 From: John Qiu Date: Tue, 21 Apr 2026 09:19:08 +0930 Subject: [PATCH 6/6] =?UTF-8?q?feat(req-prd):=20PRD=20=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=AA=8C=E6=94=B6=E6=A0=87=E5=87=86=E7=AB=A0?= =?UTF-8?q?=E8=8A=82=E5=BC=BA=E5=88=B6=E5=90=AB=20VP=20=E4=B8=89=E4=BB=B6?= =?UTF-8?q?=E5=A5=97=EF=BC=88REQ-20260421-0002=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 模板第7节新增「验收标准」章节,含 VP-Data/VP-Steps/VP-Pass 完整示例 - 检查清单「验收标准可测试」更新说明要求 VP 三件套 - 原第7节「风险评估」顺移为第8节 Co-Authored-By: Claude Sonnet 4.6 --- skills-req/req-prd-plugin/skills/SKILL.md | 43 +++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/skills-req/req-prd-plugin/skills/SKILL.md b/skills-req/req-prd-plugin/skills/SKILL.md index 8e9dc56..ef40f40 100644 --- a/skills-req/req-prd-plugin/skills/SKILL.md +++ b/skills-req/req-prd-plugin/skills/SKILL.md @@ -136,12 +136,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. 附录 - 相关文档链接 - 参考资料 ``` @@ -446,7 +483,7 @@ mcp__ai-proj__export_task_document_to_file - [ ] 背景与目标明确 - [ ] 用户群体定义清晰 - [ ] 功能需求完整 -- [ ] 验收标准可测试 +- [ ] 验收标准可测试(每条 AC 附带 VP-Data / VP-Steps / VP-Pass) - [ ] 异常情况已考虑 - [ ] 性能要求已定义 - [ ] 上线计划合理