7 Commits

Author SHA1 Message Date
bcea648e3c merge: resolve conflict in req-prototype SKILL.md, keep iframe display rule from main 2026-04-21 09:20:55 +09:30
e3513f137b feat(req-prd): PRD 模板新增验收标准章节强制含 VP 三件套(REQ-20260421-0002)
- 模板第7节新增「验收标准」章节,含 VP-Data/VP-Steps/VP-Pass 完整示例
- 检查清单「验收标准可测试」更新说明要求 VP 三件套
- 原第7节「风险评估」顺移为第8节

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:17:11 +09:30
2ab0a61eb9 fix(install): handle nested skills/ subdirectory (e.g. dev-test)
resolve_skills_src() detects when SKILL.md is one level deeper than skills/
and uses that subdirectory as rsync source instead.

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

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

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

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

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

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

marketplace: 48 → 49 plugins (新增 pm-risk-plugin)
2026-04-19 13:33:26 +09:30
72 changed files with 3780 additions and 202 deletions

View File

@@ -35,6 +35,18 @@
], ],
"strict": false "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", "name": "publish-plugin",
"source": "./skills-core/publish-plugin", "source": "./skills-core/publish-plugin",
@@ -59,6 +71,30 @@
], ],
"strict": false "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", "name": "db-migration-plugin",
"source": "./skills-dev/db-migration-plugin", "source": "./skills-dev/db-migration-plugin",
@@ -71,6 +107,18 @@
], ],
"strict": false "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", "name": "deploy-rollback-plugin",
"source": "./skills-dev/deploy-rollback-plugin", "source": "./skills-dev/deploy-rollback-plugin",
@@ -253,6 +301,43 @@
], ],
"strict": false "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", "name": "pull-request-plugin",
"source": "./skills-dev/pull-request-plugin", "source": "./skills-dev/pull-request-plugin",
@@ -278,6 +363,19 @@
], ],
"strict": false "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", "name": "req-compare-plugin",
"source": "./skills-req/req-compare-plugin", "source": "./skills-req/req-compare-plugin",
@@ -317,6 +415,19 @@
], ],
"strict": false "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", "name": "req-plugin",
"source": "./skills-req/req-plugin", "source": "./skills-req/req-plugin",
@@ -346,8 +457,8 @@
{ {
"name": "req-prototype-plugin", "name": "req-prototype-plugin",
"source": "./skills-req/req-prototype-plugin", "source": "./skills-req/req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。", "description": "原型生成与关联。支持 HTML 上传(/req prototype uploadiframe 嵌入详情页)和 Stitch AI 生成两种模式。",
"version": "1.0.0", "version": "2.0.0",
"category": "productivity", "category": "productivity",
"keywords": [ "keywords": [
"project-management", "project-management",
@@ -369,6 +480,19 @@
], ],
"strict": false "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", "name": "req-review-plugin",
"source": "./skills-req/req-review-plugin", "source": "./skills-req/req-review-plugin",
@@ -585,6 +709,19 @@
], ],
"strict": false "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", "name": "ops-tools-plugin",
"source": "./skills-personal/ops-tools-plugin", "source": "./skills-personal/ops-tools-plugin",
@@ -610,6 +747,19 @@
], ],
"strict": false "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", "name": "req-deploy-plugin",
"source": "./skills-personal/req-deploy-plugin", "source": "./skills-personal/req-deploy-plugin",
@@ -622,6 +772,32 @@
"operations" "operations"
], ],
"strict": false "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
} }
] ]
} }

98
hooks/validate-prd.sh Executable file
View File

@@ -0,0 +1,98 @@
#!/bin/bash
# validate-prd.sh
# PostToolUse Hook: PRD 文档写入/编辑后自动校验章节完整性
#
# 检查标准 PRD 模板的必需章节是否存在。
# 借鉴 devflow-claude validate-requirement.sh。
# REQ-20260416-0017 P1-14
#
# 安装方式(可选,加到 ~/.claude/settings.json:
# hooks.PostToolUse:
# - matcher: "Write|Edit"
# hooks:
# - type: command
# command: "<path>/hooks/validate-prd.sh"
# timeout: 5
#
# 也可由 skill 脚本在 PRD 写完后手动调用:
# bash validate-prd.sh /path/to/PRD.md
set -e
# ============ 1. 获取文件路径 ============
FILE_PATH="$1"
# 如果没有参数,从 stdin JSON 提取PostToolUse hook 模式)
if [ -z "$FILE_PATH" ] && command -v jq >/dev/null 2>&1; then
INPUT=$(cat 2>/dev/null || echo "")
if [ -n "$INPUT" ]; then
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.content // empty' 2>/dev/null)
fi
fi
# 没有文件路径,静默退出
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# 不是 .md 文件,跳过
case "$FILE_PATH" in
*.md) ;;
*) exit 0 ;;
esac
# 文件不存在,跳过
if [ ! -f "$FILE_PATH" ]; then
exit 0
fi
# 不含 PRD / 需求 关键词的文件名,跳过
BASENAME=$(basename "$FILE_PATH")
case "$BASENAME" in
*PRD*|*prd*|*需求*|*requirement*|*REQ*) ;;
*) exit 0 ;;
esac
# ============ 2. 检查章节 ============
# 标准 PRD 必需章节(来自 req-prd SKILL.md 的模板)
REQUIRED_SECTIONS=(
"## 1. 概述"
"### 1.1 背景"
"### 1.2 目标"
"### 1.4 客户原始诉求"
"## 2. 用户分析"
"## 3. 功能需求"
"## 4. 交互设计"
"## 5. 技术要求"
"## 6. 上线计划"
"## 7. 风险评估"
)
MISSING=()
CONTENT=$(cat "$FILE_PATH")
for section in "${REQUIRED_SECTIONS[@]}"; do
# 模糊匹配:忽略空格差异和标点
PATTERN=$(echo "$section" | sed 's/[[:space:]]*//g')
CONTENT_CLEAN=$(echo "$CONTENT" | sed 's/[[:space:]]*//g')
if ! echo "$CONTENT_CLEAN" | grep -qi "$(echo "$PATTERN" | sed 's/#//g')"; then
MISSING+=("$section")
fi
done
# ============ 3. 输出 ============
if [ ${#MISSING[@]} -gt 0 ]; then
echo ""
echo "⚠️ PRD 章节检查:${BASENAME}"
echo ""
echo "缺少 ${#MISSING[@]} 个必需章节:"
for m in "${MISSING[@]}"; do
echo "$m"
done
echo ""
echo "💡 请参考 req-prd skill 的 PRD 模板补充缺失章节。"
echo " 章节结构不可变:不得新增、删除、合并或重命名模板中的章节。"
fi
exit 0

338
install-skills.sh Executable file
View File

@@ -0,0 +1,338 @@
#!/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 <cat> Only install plugins in dir_category=<cat>
# 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 <install_name> -> prints version or empty string
local name="$1"
if [[ -f "$STATE_FILE" ]]; then
python3 -c "
import json,sys
try:
d=json.load(open('$STATE_FILE'))
print(d.get('$name',{}).get('version',''))
except: pass
" 2>/dev/null || true
fi
}
state_set() {
# state_set <install_name> <version> <install_type>
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 <json_file> <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
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
# 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/<name>.md
local src_md="$src_dir/SKILL.md"
if [[ ! -f "$src_md" ]]; then
warn "$install_name: SKILL.md not found, skipping"
return
fi
if [[ "$DRY_RUN" == true ]]; then
dry "$install_name$COMMANDS_DIR/${install_name}.md"
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/<name>/
local dst_dir="$SKILLS_DIR/$install_name"
if [[ "$DRY_RUN" == true ]]; then
dry "$install_name$dst_dir/"
else
mkdir -p "$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
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 "$@"

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "biz-contract",
"install_type": "skill",
"dir_category": "biz"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "biz-ops",
"install_type": "skill",
"dir_category": "biz"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "biz-plan",
"install_type": "skill",
"dir_category": "biz"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "finance",
"install_type": "skill",
"dir_category": "biz"
} }

View File

@@ -4,5 +4,8 @@
"version": "2.0.1", "version": "2.0.1",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "ai-proj",
"install_type": "skill",
"dir_category": "core"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "pm-ask",
"install_type": "skill",
"dir_category": "core"
} }

View File

@@ -0,0 +1,11 @@
{
"name": "pm-risk-plugin",
"description": "三维度项目风险扫描:需求层/代码层/流程层。当用户说'/risk'、'风险扫描'、'有什么风险'时自动激活",
"version": "1.0.0",
"author": {
"name": "qiudl"
},
"install_name": "pm-risk",
"install_type": "skill",
"dir_category": "core"
}

View File

@@ -0,0 +1,154 @@
---
name: pm-risk
description: 三维度项目风险扫描(需求层/代码层/流程层)。当用户说"/risk"、"风险扫描"、"有什么风险"、"哪些需求停滞了"、"分支健康"时自动激活。
---
# pm-risk Skill — 三维度风险扫描
借鉴自 devflow-claude `/pm:risk`。源自 REQ-20260416-0017 P1-10。
## 命令
```
/risk [--save]
```
- 不加参数:扫描并展示报告
- `--save`:保存到思源笔记
## 扫描维度
### 维度 1: 需求层
通过 ai-proj MCP 查询需求状态:
| 检测项 | 数据源 | 严重 | 警告 | 提示 |
|--------|--------|------|------|------|
| 需求停滞 | `list_requirements` + `updated_at` | >14 天无更新 | >7 天无更新 | >3 天无更新 |
| 草稿滞留 | `list_requirements --status=draft` | >30 天 | >14 天 | >7 天 |
| 开发中无提交 | 需求关联分支 + `git log` | >7 天无 commit | >3 天 | - |
| 测试中超期 | `list_requirements --delivery_stage=testing` | >14 天 | >7 天 | - |
| 已批准未开发 | `list_requirements --status=approved` | >30 天 | >14 天 | - |
**查询方式**
```
mcp__ai-proj__list_requirements(status=in_progress)
→ 遍历每个需求的 updated_at计算距今天数
```
### 维度 2: 代码层
通过 git 命令分析:
| 检测项 | 命令 | 严重 | 警告 |
|--------|------|------|------|
| 未合并分支过久 | `git branch -r --no-merged origin/develop` + `git log -1` | >14 天无 commit | >7 天 |
| 频繁修复文件 | `git log --diff-filter=M --name-only` 近 30 天 | 同文件 >5 次 fix commit | >3 次 |
| 提交频率下降 | 本周 vs 上周 commit 数 | 下降 >70% | 下降 >50% |
| 大文件提交 | `git log --diff-filter=A --name-only` | >10MB 文件 | >5MB |
**查询方式**
```bash
# 未合并分支
git for-each-ref --sort=-committerdate --format='%(refname:short) %(committerdate:short)' refs/remotes/origin/ | grep -v 'main\|develop\|HEAD'
# 频繁修复
git log --since='30 days ago' --grep='fix' --diff-filter=M --name-only --pretty=format:'' | sort | uniq -c | sort -rn | head -10
# 提交频率
THIS_WEEK=$(git log --since='7 days ago' --oneline | wc -l)
LAST_WEEK=$(git log --since='14 days ago' --until='7 days ago' --oneline | wc -l)
```
### 维度 3: 流程层
通过 MCP + git 交叉分析:
| 检测项 | 检测方法 | 级别 |
|--------|---------|------|
| 跳过评审直接开发 | 需求 status 从 draft 直接跳到 in_progress没有 approved 记录) | 警告 |
| PR 无评审直接合并 | Gitea API 查 PR 无 review approve 就 merge | 警告 |
| 测试门禁跳过 | delivery_stage 从 dev 跳到 released没有 testing | 严重 |
| 直接推 main | `git log --first-parent origin/main` 非 merge commit | 严重 |
## 风险级别定义
| 级别 | 图标 | 含义 | 响应 |
|------|------|------|------|
| 严重 | 🔴 | 立即关注 | 当天处理 |
| 警告 | 🟡 | 近期需处理 | 3 天内处理 |
| 提示 | 🔵 | 值得留意 | 下次迭代关注 |
## 输出模板
```markdown
# 🔍 风险扫描报告
**扫描时间**: YYYY-MM-DD HH:MM CST
**扫描范围**: 项目 ai-proj
## 概览
| 维度 | 🔴 严重 | 🟡 警告 | 🔵 提示 |
|------|---------|---------|---------|
| 需求层 | X | X | X |
| 代码层 | X | X | X |
| 流程层 | X | X | X |
## 🔴 严重风险
### [S1] REQ-20260410-0001 停滞 18 天
- **需求**: REQ-20260410-0001 用户积分管理
- **状态**: in_progress
- **最后更新**: 2026-04-01
- **建议**: 联系负责人确认是否阻塞,必要时降级或暂停
### [S2] ...
## 🟡 警告
### [W1] 分支 feat/xxx 14 天未合并
- **分支**: feat/old-feature
- **最后 commit**: 2026-04-05
- **建议**: 确认是否放弃,清理或合并
## 🔵 提示
...
## ✅ 一切正常的维度
- (无严重/警告时显示此段)
---
**下次扫描建议**: 每周一早会前执行 `/risk`
```
## 无风险时的输出
```
✅ 风险扫描完成 — 一切正常
扫描了 X 个需求、Y 个分支、Z 条提交,未发现风险项。
下次扫描建议:下周一
```
## 定期执行建议
- **手动**:每周一早会前 `/risk`
- **自动**:可配合 `/loop 7d /risk --save` 定期扫描并保存到思源笔记
## 与其他 skill 的关系
| skill | 协作 |
|-------|------|
| `pm-ask` | risk 发现问题后,用 `/ask` 深入分析 |
| `req-workflow` | risk 发现流程违规后,用 `/req` 修正 |
| `ai-proj` | 底层 MCP 数据查询 |
## 参考
- devflow-claude: `plugins/pm/commands/risk.md`
- REQ-20260416-0017 P1-10

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "publish",
"install_type": "skill",
"dir_category": "core"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "agent-browser",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -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"
}

View File

@@ -0,0 +1,406 @@
---
name: agent-swarm
description: Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.
---
# Agent Swarm - Multi-Agent Orchestration
基于 OpenAI Swarm 设计模式的多智能体协作系统,用于复杂开发任务的智能分解与协调。
## 核心概念
### 1. Agent智能体
每个 Agent 是具有特定职责的专家:
- **Instructions**: Agent 的角色定义和行为准则
- **Functions**: Agent 可以调用的工具函数
- **Handoffs**: 何时移交给其他 Agent
### 2. Handoff任务移交
Agent 之间的控制权转移机制:
- 当前 Agent 完成自己的职责
- 识别需要其他专长
- 移交给最合适的 Agent
### 3. Context Variables上下文变量
跨 Agent 共享的状态:
- 项目目录
- 技术栈信息
- 当前进度
- 发现的问题
---
## 预定义 Agent
### 1. Architect Agent架构师
**职责**: 理解需求、技术选型、设计系统架构
**何时使用**:
- 用户描述新功能或系统
- 需要技术方案设计
- 需要架构评审
**工具**:
- Read codebase
- Grep patterns
- 设计文档生成
**Handoff to**:
- Coder Agent开始编码
- Reviewer Agent评审设计
---
### 2. Coder Agent编码者
**职责**: 实现功能、编写代码、修复 bug
**何时使用**:
- 架构师完成设计
- 用户提出 bug 修复
- 需要代码重构
**工具**:
- Edit files
- Write files
- Git operations
**Handoff to**:
- Tester Agent代码完成后
- Architect Agent遇到设计问题
---
### 3. Tester Agent测试员
**职责**: 编写测试、运行测试、验证功能
**何时使用**:
- 代码编写完成
- 需要测试覆盖
- 验证 bug 修复
**工具**:
- Run tests
- Write test cases
- Coverage reports
**Handoff to**:
- Deployer Agent测试通过
- Coder Agent发现问题
---
### 4. Deployer Agent部署员
**职责**: 构建镜像、部署服务、监控上线
**何时使用**:
- 测试全部通过
- 需要发布到环境
- 需要回滚版本
**工具**:
- Docker build
- SSH deployment
- Health checks
**Handoff to**:
- Monitor Agent部署完成
- Coder Agent部署失败
---
### 5. Reviewer Agent评审员
**职责**: 代码审查、文档审查、安全检查
**何时使用**:
- PR 创建后
- 重要功能完成
- 需要质量把关
**工具**:
- Diff analysis
- Security scan
- Best practices check
**Handoff to**:
- Coder Agent需要修改
- Deployer Agent审查通过
---
## 使用方法
### 基本调用
```bash
/swarm start "在 new-ai-proj 中实现任务批量删除功能"
```
**执行流程**:
1. **Architect** 分析需求 → 设计 API 和前端交互
2. **Coder** 实现后端 API → 实现前端 UI
3. **Tester** 编写单元测试 → 运行测试
4. **Reviewer** 代码审查 → 安全检查
5. **Deployer** 部署到 staging → 验证功能
---
### 指定起始 Agent
```bash
/swarm coder "修复 backend/handlers/task_handler.go 的空指针 bug"
```
直接从 Coder Agent 开始,跳过架构设计阶段。
---
### 传递上下文
```bash
/swarm start "优化数据库查询性能" \
--context project=/Users/coolbuy-dev/coding/new-ai-proj \
--context stack=Go,PostgreSQL,Redis \
--context module=backend/services
```
---
### 查看执行轨迹
```bash
/swarm trace
```
显示 Agent 调用链:
```
Architect → analyzed requirements (3 min)
↓ handoff: "Design complete, ready for implementation"
Coder → implemented 5 files (12 min)
↓ handoff: "Code complete, needs testing"
Tester → wrote 8 test cases, all passed (5 min)
↓ handoff: "Tests passed, ready for review"
Reviewer → approved with 2 suggestions (2 min)
↓ handoff: "Approved, ready for deployment"
Deployer → deployed to staging, health check OK (3 min)
```
---
## 配置文件
### swarm.yaml
在项目根目录创建 `swarm.yaml` 自定义 Agent 行为:
```yaml
agents:
architect:
instructions: |
你是系统架构师,专注于 Go + Vue.js 技术栈。
遵循 RESTful API 设计原则。
考虑性能、安全性、可维护性。
max_turns: 5
coder:
instructions: |
你是 Go 后端工程师和 Vue.js 前端工程师。
编写清晰、简洁、高性能的代码。
遵循项目现有代码风格。
tools:
- Edit
- Write
- Bash
max_turns: 10
tester:
instructions: |
你是测试工程师,编写全面的测试用例。
确保边界条件、错误处理、并发安全。
tools:
- Bash
- Write
test_command: "go test ./... -v"
max_turns: 5
context_variables:
project_root: /Users/coolbuy-dev/coding/new-ai-proj
backend_lang: Go 1.21
frontend_framework: Vue 3
database: PostgreSQL 15
deployment_target: staging.ai.pipexerp.com
```
---
## 高级功能
### 1. 自定义 Agent
```yaml
agents:
database-optimizer:
instructions: |
你是数据库性能优化专家。
分析慢查询、优化索引、设计缓存策略。
functions:
- explain_analyze
- create_index
- cache_design
handoff_to:
- coder # 实现优化方案
```
---
### 2. 条件 Handoff
```yaml
handoff_rules:
- from: tester
to: coder
condition: "test_pass_rate < 90%"
message: "测试失败率超过 10%,需要修复"
- from: tester
to: deployer
condition: "test_pass_rate == 100%"
message: "所有测试通过,可以部署"
```
---
### 3. 并行 Agent
对于独立任务,多个 Agent 可以并行工作:
```bash
/swarm parallel \
"coder: 实现后端 API" \
"coder: 实现前端 UI" \
"tester: 编写 API 测试"
```
---
## 与 Remote Coding 集成
在 OpenClaw 中调用本地 Claude Code 执行 Swarm 工作流:
```bash
# OpenClaw 调用 Melbourne Claude Code
ssh melbourne "cd /Users/coolbuy-dev/coding/new-ai-proj && \
/opt/homebrew/bin/claude --dangerously-skip-permissions \
-p '/swarm start 实现任务批量删除功能'"
```
---
## 实际案例
### 案例 1: 新功能开发
**任务**: "为 AI-Proj 实现需求批量导出功能"
**执行过程**:
1. **Architect**:
- 分析需求导出格式Excel/PDF、筛选条件、数据脱敏
- 设计 API: `POST /api/v1/requirements/export`
- 设计前端:导出按钮、进度条、下载链接
2. **Coder**:
- 后端实现 export service
- 前端实现导出 UI 组件
- 集成 file download 功能
3. **Tester**:
- 测试大量数据导出1000+ 需求)
- 测试并发导出
- 测试下载失败重试
4. **Reviewer**:
- 检查文件大小限制
- 检查内存泄漏风险
- 检查数据权限控制
5. **Deployer**:
- 部署到 staging
- 验证导出功能
- 监控资源使用
---
### 案例 2: Bug 修复
**任务**: "修复任务详情页加载缓慢问题"
**执行过程**:
1. **Architect**:
- 分析性能瓶颈N+1 查询问题
- 设计优化方案:使用 JOIN 和预加载
2. **Coder**:
- 优化数据库查询
- 添加 Redis 缓存
- 更新前端数据获取逻辑
3. **Tester**:
- 性能测试:加载时间从 3s → 300ms
- 并发测试100 用户同时访问
- 缓存一致性测试
4. **Deployer**:
- 灰度发布到 10% 用户
- 监控性能指标
- 全量发布
---
## 最佳实践
1. **明确任务范围**: 复杂任务交给 Swarm简单任务直接执行
2. **合理设置 max_turns**: 避免 Agent 陷入死循环
3. **记录 Handoff 原因**: 便于追溯和调试
4. **定期审查轨迹**: 优化 Agent 协作流程
5. **利用 Context Variables**: 避免重复传递信息
---
## 故障排查
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| Agent 一直循环 | max_turns 设置过大 | 降低 max_turns添加明确的 handoff 条件 |
| Handoff 失败 | 目标 Agent 未定义 | 检查 swarm.yaml 配置 |
| 上下文丢失 | Context Variables 未传递 | 在 handoff 时显式传递 context |
| 执行太慢 | 串行执行可并行任务 | 使用 `/swarm parallel` |
---
## 与其他 Skills 集成
- **dev-coding**: Coder Agent 使用 dev-coding 的编码规范
- **dev-test**: Tester Agent 使用 dev-test 的测试策略
- **ops-tools**: Deployer Agent 使用 ops-tools 进行部署
- **ai-proj**: 所有 Agent 使用 ai-proj MCP 进行任务同步
---
## 命令速查
| 命令 | 功能 |
|------|------|
| `/swarm start <task>` | 启动 Swarm 工作流(从 Architect 开始) |
| `/swarm <agent> <task>` | 从指定 Agent 开始 |
| `/swarm parallel <tasks>` | 并行执行多个任务 |
| `/swarm trace` | 查看执行轨迹 |
| `/swarm config` | 显示当前配置 |
| `/swarm agents` | 列出所有可用 Agent |
| `/swarm stop` | 终止当前 Swarm 执行 |
---
## 参考资料
- [OpenAI Swarm 文档](https://github.com/openai/swarm)
- [Multi-Agent Systems 设计模式](https://arxiv.org/abs/2308.00352)
- [Claude Code Skills 文档](https://docs.anthropic.com/claude-code/skills)

View File

@@ -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"
}

View File

@@ -0,0 +1,537 @@
---
name: ai-chat
description: AI Chat 测试与管理。发送消息测试 AI Chat 工具调用链路,管理工具开关和 Provider 配置,支持 local/staging 环境切换。
arguments: <subcommand> [args]
---
# AI Chat Skill
测试和管理 Coolbuy PaaS AI Chat 服务的 Claude Code skill。
## Quick Reference
| 命令 | 用途 |
|------|------|
| `/ai-chat send <message>` | 发送消息到 AI Chat实时显示工具调用 + AI 回复 |
| `/ai-chat env [local\|staging]` | 切换/查看目标环境(默认 local |
| `/ai-chat tools [category]` | 列出当前环境已注册的工具 |
| `/ai-chat config` | 查看 AI 配置Provider、工具开关等 |
| `/ai-chat history` | 显示本次会话的历史消息 |
---
## Environment Config
两套环境,通过 `/ai-chat env` 切换:
| 环境 | Auth URL | AI URL | 登录账号 |
|------|----------|--------|----------|
| **local** (默认) | `http://localhost:7089` | `http://localhost:7092` | lining_admin / admin123 |
| **staging** | `http://39.105.150.219:7089` | `http://39.105.150.219:7092` | lining_admin / admin123 |
### 状态文件
环境状态保存在 `/tmp/ai-chat-state.json`,格式:
```json
{
"env": "local",
"token": "eyJ...",
"token_env": "local",
"history": []
}
```
---
## Commands
### /ai-chat env
**切换或查看当前环境。**
用法:
- `/ai-chat env` — 显示当前环境
- `/ai-chat env local` — 切换到本地环境
- `/ai-chat env staging` — 切换到 staging 环境
实现步骤:
1. 读取 `/tmp/ai-chat-state.json`(不存在则默认 `{"env":"local","history":[]}`
2. 如果提供了参数,更新 `env` 字段并清空 `token`(环境变了 token 失效)
3. 写回状态文件
4. 输出当前环境信息表格
---
### /ai-chat send
**发送消息到 AI Chat 并实时显示流式响应。**
用法:`/ai-chat send <message>`
实现步骤:
#### Step 1: 读取状态
```bash
# 读取状态文件
cat /tmp/ai-chat-state.json 2>/dev/null || echo '{"env":"local","history":[]}'
```
确定环境变量:
- **local**: `AUTH_URL=http://localhost:7089`, `AI_URL=http://localhost:7092`
- **staging**: `AUTH_URL=http://39.105.150.219:7089`, `AI_URL=http://39.105.150.219:7092`
#### Step 2: 获取 Token
如果状态文件中没有 token 或 `token_env` 与当前 `env` 不匹配,执行登录:
```bash
curl -s -X POST "$AUTH_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"lining_admin","password":"admin123"}'
```
从响应中提取 `access_token`
```bash
# 响应格式
# {"access_token":"eyJ...","refresh_token":"...","token_type":"Bearer","expires_in":7200,"user_info":{...}}
```
`python3 -c "import json,sys; print(json.load(sys.stdin)['access_token'])"` 提取 token。
将 token 和 token_env 保存到状态文件。
#### Step 3: 构造请求并发送 SSE 流
```bash
curl -s -N -X POST "$AI_URL/api/v1/ai/chat/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"message\":\"$MSG\",\"history\":$HISTORY}" 2>&1
```
**重要**: `history` 字段传入之前的会话历史(从状态文件读取),实现多轮对话。
#### Step 4: 解析 SSE 事件
用 Python 脚本解析 SSE 流(比 bash while read 更可靠):
```python
#!/usr/bin/env python3
"""解析 AI Chat SSE 流并格式化输出"""
import sys, json
full_content = ""
tool_calls = []
for line in sys.stdin:
line = line.strip()
if not line.startswith("data:"):
continue
data_str = line[5:].strip()
if not data_str:
continue
try:
event = json.loads(data_str)
except json.JSONDecodeError:
continue
evt_type = event.get("type", "")
if evt_type == "content":
chunk = event.get("content", "")
full_content += chunk
# 实时输出内容片段
sys.stdout.write(chunk)
sys.stdout.flush()
elif evt_type == "tool_call":
tc = event.get("tool_call", {})
tool_name = tc.get("name", "unknown")
tool_args = tc.get("arguments", {})
tool_id = tc.get("id", "")
tool_calls.append({"id": tool_id, "name": tool_name})
# 输出工具调用标记
args_str = json.dumps(tool_args, ensure_ascii=False)
if len(args_str) > 200:
args_str = args_str[:200] + "..."
print(f"\n🔧 Tool Call: {tool_name}", file=sys.stderr)
print(f" Args: {args_str}", file=sys.stderr)
elif evt_type == "tool_result":
tr = event.get("tool_result", {})
tool_name = tr.get("name", "unknown")
content = tr.get("content", "")
is_error = tr.get("is_error", False)
# 截断长结果
if len(content) > 500:
content = content[:500] + f"... ({len(content)} chars total)"
status = "❌ Error" if is_error else "✅ Result"
print(f" {status} [{tool_name}]: {content}", file=sys.stderr)
elif evt_type == "done":
usage = event.get("usage") or {}
prompt_t = usage.get("prompt_tokens", 0)
completion_t = usage.get("completion_tokens", 0)
total_t = usage.get("total_tokens", 0)
print(f"\n\n--- Done ---", file=sys.stderr)
if total_t > 0:
print(f"Tokens: {prompt_t} prompt + {completion_t} completion = {total_t} total", file=sys.stderr)
if tool_calls:
print(f"Tool calls: {len(tool_calls)} ({', '.join(tc['name'] for tc in tool_calls)})", file=sys.stderr)
elif evt_type == "error":
err = event.get("error", "unknown error")
print(f"\n❌ Error: {err}", file=sys.stderr)
# 输出换行
print()
# 将 full_content 输出到 fd 3 用于状态更新(如果 fd 3 打开)
try:
with open("/tmp/ai-chat-response.txt", "w") as f:
f.write(full_content)
except:
pass
```
#### Step 5: 更新会话历史
发送完成后,将用户消息和 AI 回复追加到状态文件的 `history` 数组中:
```json
[
{"role": "user", "content": "<用户消息>"},
{"role": "assistant", "content": "<AI 完整回复>"}
]
```
#### 完整 bash 执行流程
```bash
#!/usr/bin/env bash
set -euo pipefail
MSG="$1"
STATE_FILE="/tmp/ai-chat-state.json"
# 1. 读取状态
if [ -f "$STATE_FILE" ]; then
STATE=$(cat "$STATE_FILE")
else
STATE='{"env":"local","history":[]}'
fi
ENV=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('env','local'))")
TOKEN=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('token',''))")
TOKEN_ENV=$(echo "$STATE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('token_env',''))")
HISTORY=$(echo "$STATE" | python3 -c "import json,sys; print(json.dumps(json.load(sys.stdin).get('history',[])))")
# 2. 确定 URL
if [ "$ENV" = "staging" ]; then
AUTH_URL="http://39.105.150.219:7089"
AI_URL="http://39.105.150.219:7092"
else
AUTH_URL="http://localhost:7089"
AI_URL="http://localhost:7092"
fi
# 3. 获取 token如果需要
if [ -z "$TOKEN" ] || [ "$TOKEN_ENV" != "$ENV" ]; then
echo "🔐 Logging in to $ENV environment..."
LOGIN_RESP=$(curl -s -X POST "$AUTH_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"lining_admin","password":"admin123"}')
TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('access_token',d.get('data',{}).get('access_token','')))")
if [ -z "$TOKEN" ]; then
echo "❌ Login failed: $LOGIN_RESP"
exit 1
fi
echo "✅ Login successful"
# 更新状态中的 token
STATE=$(echo "$STATE" | python3 -c "
import json,sys
s=json.load(sys.stdin)
s['token']='$TOKEN'
s['token_env']='$ENV'
print(json.dumps(s,ensure_ascii=False))
")
fi
# 4. 发送 SSE 请求并解析
echo ""
echo "📤 Sending to $ENV: $MSG"
echo "---"
# 转义消息中的特殊字符
MSG_JSON=$(python3 -c "import json; print(json.dumps('$MSG'))")
curl -s -N -X POST "$AI_URL/api/v1/ai/chat/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"message\":$MSG_JSON,\"history\":$HISTORY}" 2>&1 | python3 -c "
import sys, json
full_content = ''
tool_calls = []
for line in sys.stdin:
line = line.strip()
if not line.startswith('data:'):
continue
data_str = line[5:].strip()
if not data_str:
continue
try:
event = json.loads(data_str)
except json.JSONDecodeError:
continue
evt_type = event.get('type', '')
if evt_type == 'content':
chunk = event.get('content', '')
full_content += chunk
sys.stdout.write(chunk)
sys.stdout.flush()
elif evt_type == 'tool_call':
tc = event.get('tool_call', {})
tool_name = tc.get('name', 'unknown')
tool_args = tc.get('arguments', {})
tool_calls.append({'name': tool_name})
args_str = json.dumps(tool_args, ensure_ascii=False)
if len(args_str) > 200:
args_str = args_str[:200] + '...'
print(f'\n🔧 Tool Call: {tool_name}', file=sys.stderr)
print(f' Args: {args_str}', file=sys.stderr)
elif evt_type == 'tool_result':
tr = event.get('tool_result', {})
tool_name = tr.get('name', 'unknown')
content = tr.get('content', '')
is_error = tr.get('is_error', False)
if len(content) > 500:
content = content[:500] + f'... ({len(content)} chars total)'
status = '❌' if is_error else '✅'
print(f' {status} [{tool_name}]: {content}', file=sys.stderr)
elif evt_type == 'done':
usage = event.get('usage') or {}
pt = usage.get('prompt_tokens', 0)
ct = usage.get('completion_tokens', 0)
tt = usage.get('total_tokens', 0)
print(f'\n\n--- Done ---', file=sys.stderr)
if tt > 0:
print(f'Tokens: {pt} prompt + {ct} completion = {tt} total', file=sys.stderr)
if tool_calls:
names = ', '.join(tc['name'] for tc in tool_calls)
print(f'Tool calls: {len(tool_calls)} ({names})', file=sys.stderr)
elif evt_type == 'error':
err = event.get('error', 'unknown error')
print(f'\n❌ Error: {err}', file=sys.stderr)
print()
with open('/tmp/ai-chat-response.txt', 'w') as f:
f.write(full_content)
"
# 5. 更新历史
RESPONSE=$(cat /tmp/ai-chat-response.txt 2>/dev/null || echo "")
python3 -c "
import json
state_file = '$STATE_FILE'
try:
with open(state_file) as f:
state = json.load(f)
except:
state = {'env': 'local', 'history': []}
msg = $MSG_JSON
resp = '''$RESPONSE'''
state['history'].append({'role': 'user', 'content': msg})
if resp:
state['history'].append({'role': 'assistant', 'content': resp})
state['token'] = '$TOKEN'
state['token_env'] = '$ENV'
with open(state_file, 'w') as f:
json.dump(state, f, ensure_ascii=False, indent=2)
"
echo ""
echo "💬 History: $(echo "$STATE" | python3 -c "import json,sys; h=json.load(sys.stdin).get('history',[]); print(len(h)//2 + 1)") messages in session"
```
**重要注意事项**
- 上面的脚本是逻辑参考,**不要**原样执行。Claude Code 应按步骤逐一执行 bash 命令。
- 消息中的引号和特殊字符需要用 python3 json.dumps 转义。
- 如果 token 过期401 响应),自动重新登录。
- SSE 超时设置 `--max-time 120`
---
### /ai-chat tools
**列出当前环境已注册的工具。**
用法:
- `/ai-chat tools` — 列出所有工具
- `/ai-chat tools <category>` — 按分类过滤
实现步骤:
1. 读取状态获取环境和 token必要时先登录
2. 发送请求:
```bash
# 列出所有工具
curl -s "$AI_URL/api/v1/ai/tools" \
-H "Authorization: Bearer $TOKEN"
# 按分类过滤
curl -s "$AI_URL/api/v1/ai/tools?category=order" \
-H "Authorization: Bearer $TOKEN"
```
3. 响应格式:
```json
{
"tools": [
{
"name": "list_orders",
"description": "查询订单列表",
"category": "order",
"enabled": true,
"parameters": {...}
}
]
}
```
4. 按 category 分组,输出表格:
```
📋 AI Tools (142 total)
order (15 tools)
├── list_orders 查询订单列表
├── get_order_detail 获取订单详情
└── ...
product (12 tools)
├── list_products 查询商品列表
└── ...
```
已知工具分类order, product, sku, inventory, task, brand, requirement, customer, dashboard, distribution, finance, discount, channel, approval, organization, feature_gap
---
### /ai-chat config
**查看 AI 服务配置。**
实现步骤:
1. 根据当前环境读取对应配置文件:
- **local**: 读取 `ai-service/api/etc/ai-api-local.yaml`
- **staging**: SSH 到 staging 读取 `/opt/coolbuy/configs/ai-api.yaml`
2. 显示关键配置项:
- AI Provider 和 Model
- 各工具分类的开关状态
- API 端口
3. 输出格式:
```
⚙️ AI Config (local)
Provider: deepseek
Model: deepseek-chat
Port: 7092
Tool Categories:
✅ order ✅ product ✅ sku
✅ inventory ✅ task ✅ brand
✅ requirement ✅ customer ✅ dashboard
✅ distribution ✅ finance ✅ discount
✅ channel ✅ approval ✅ organization
✅ feature_gap
```
---
### /ai-chat history
**显示当前会话的历史消息。**
实现步骤:
1. 读取 `/tmp/ai-chat-state.json``history` 数组
2. 按时间顺序显示:
```
💬 Chat History (3 messages)
[1] 👤 User: 你好
🤖 AI: 你好!我是 AI 助手...
[2] 👤 User: 搜索组织架构找到大客户部
🤖 AI: 我来帮你搜索... (used: search_organizations)
[3] 👤 User: 最近的订单
🤖 AI: 以下是最近的订单列表...
```
3. 如果需要清空历史:`/ai-chat history clear`
- 删除状态文件中的 history 数组,重置为空
---
## SSE Event Format Reference
AI Chat SSE 流使用 `event: message` + `data: {json}` 格式:
| type | 数据字段 | 说明 |
|------|---------|------|
| `content` | `content: "<text>"` | 增量文本内容 |
| `tool_call` | `tool_call: {id, name, arguments}` | AI 请求调用工具 |
| `tool_result` | `tool_result: {tool_call_id, name, content, is_error}` | 工具执行结果 |
| `done` | `usage: {prompt_tokens, completion_tokens, total_tokens}` (可能为 null), `finish_reason` | 流结束 |
| `error` | `error: "<message>"` | 错误 |
---
## Troubleshooting
### Token 过期 (401)
如果请求返回 401删除缓存 token 重新登录:
```bash
# 清除 token 强制重新登录
python3 -c "
import json
with open('/tmp/ai-chat-state.json') as f: s=json.load(f)
s['token']=''
with open('/tmp/ai-chat-state.json','w') as f: json.dump(s,f)
"
```
### 连接失败
- **local**: 确认本地服务已启动 (`./scripts/start_dev.sh`)
- **staging**: 确认 staging 服务运行中 (`ssh coolbuy-staging "docker ps | grep ai-service"`)
### SSE 流中断
- 检查 AI 服务日志
- local: 查看终端输出
- staging: `ssh coolbuy-staging "docker logs coolbuy-ai-service --tail 50"`
### 消息中包含特殊字符
务必用 `python3 -c "import json; print(json.dumps(msg))"` 转义消息内容,避免 JSON 解析失败。

View File

@@ -2,5 +2,10 @@
"name": "db-migration-plugin", "name": "db-migration-plugin",
"description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时激活。", "description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时激活。",
"version": "1.0.0", "version": "1.0.0",
"author": { "name": "qiudl" } "author": {
"name": "qiudl"
},
"install_name": "db-migration",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -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"
}

View File

@@ -0,0 +1,159 @@
---
name: defect-analysis
description: 系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。
---
# 设计缺陷分析 Skill通用版
你是资深架构审计师。对给定的需求方案或代码实现,执行系统性的多维度缺陷检查,**反复迭代直到收敛**(连续一轮无新发现即停止)。
## 检查维度(按严重度排序)
### 1. 致命级:架构不可行
- **异步/同步冲突**:异步操作被当作同步使用?长时间操作阻塞了请求?
- **框架限制**v-html 无法绑定事件、WebSocket/SSE 超时、API 轮数限制
- **数据格式不匹配**:前后端约定的 ID 格式/字段名/序列化方式不一致?
- **循环依赖**:模块 A 内部调 BB 又依赖 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())
"
```
**如果这层失败**:代码逻辑错误或依赖缺失。
### 层 2AI 行为验证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 不遵循指令。加"必须"/"绝不能"等强制词。
### 层 3SSE 流式验证(前后端数据管道)
用 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 + 事件委托 |

View File

@@ -2,5 +2,10 @@
"name": "deploy-rollback-plugin", "name": "deploy-rollback-plugin",
"description": "回滚方案插件。部署后发现问题时的回滚策略、数据修复、灰度回退。挂载在 deploy 阶段。", "description": "回滚方案插件。部署后发现问题时的回滚策略、数据修复、灰度回退。挂载在 deploy 阶段。",
"version": "1.0.0", "version": "1.0.0",
"author": { "name": "qiudl" } "author": {
"name": "qiudl"
},
"install_name": "deploy-rollback",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -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"
}

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-arch",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-cicd",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-coding",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-commit",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -114,6 +114,48 @@ feat/REQ-xxx-i42 + commit → commit message 自动加 "closes #42"
确认提交?(y/n) 确认提交?(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 集成 ## 与 ai-proj 集成
- **查询当前需求**:通过 MCP `mcp__ai-proj__find_requirement``list_requirements` 找 user 进行中的 - **查询当前需求**:通过 MCP `mcp__ai-proj__find_requirement``list_requirements` 找 user 进行中的

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-deploy",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-integration",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-review",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -2,5 +2,10 @@
"name": "dev-scaffold-plugin", "name": "dev-scaffold-plugin",
"description": "模块脚手架插件。新建模块时自动生成分层代码骨架Model/Repository/Service/Handler/Route。挂载在 dev 阶段。", "description": "模块脚手架插件。新建模块时自动生成分层代码骨架Model/Repository/Service/Handler/Route。挂载在 dev 阶段。",
"version": "1.0.0", "version": "1.0.0",
"author": { "name": "qiudl" } "author": {
"name": "qiudl"
},
"install_name": "dev-scaffold",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "dev-test",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -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"
}

View File

@@ -0,0 +1,96 @@
---
name: executing-plans
description: Use when you have a written implementation plan to execute in a separate session with review checkpoints
---
# Executing Plans
## Overview
Load plan, review critically, create branch, execute tasks in batches, report for review between batches.
**Core principle:** Batch execution with checkpoints for architect review.
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
## The Process
### Step 1: Load and Review Plan
1. Read plan file
2. Review critically - identify any questions or concerns about the plan
3. If concerns: Raise them with your human partner before starting
4. If no concerns: Proceed to branch setup
### Step 2: Setup Branch
**Before any implementation, ensure proper branch isolation.**
1. Check if already on a feature branch for this task
2. If not, use `/pr start` to create one:
```bash
/pr start <type> <REQ-id> <name>
# Example: /pr start feature REQ-123 user-login
```
3. If no REQ-id available, ask user or create branch manually:
```bash
git fetch origin
git checkout -b <type>/<descriptive-name> origin/main
```
4. Confirm branch is ready before proceeding
**Branch types:** `feature`, `fix`, `refactor`
### Step 3: Create Tasks and Execute Batch
**Default: First 3 tasks**
1. Create TodoWrite tasks from plan
2. For each task in batch:
- Mark as in_progress
- Follow each step exactly (plan has bite-sized steps)
- Run verifications as specified
- Mark as completed
### Step 4: Report
When batch complete:
- Show what was implemented
- Show verification output
- Say: "Ready for feedback."
### Step 5: Continue
Based on feedback:
- Apply changes if needed
- Execute next batch
- Repeat until complete
### Step 6: Complete Development
After all tasks complete and verified:
- Announce: "I'm using the finishing-a-development-branch skill to complete this work."
- **REQUIRED SUB-SKILL:** Use superpowers:finishing-a-development-branch
- Follow that skill to verify tests, present options, execute choice
## When to Stop and Ask for Help
**STOP executing immediately when:**
- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
- Plan has critical gaps preventing starting
- You don't understand an instruction
- Verification fails repeatedly
**Ask for clarification rather than guessing.**
## When to Revisit Earlier Steps
**Return to Review (Step 1) when:**
- Partner updates the plan based on your feedback
- Fundamental approach needs rethinking
**Don't force through blockers** - stop and ask.
## Remember
- Review plan critically first
- **Create feature branch before implementation**
- Follow plan steps exactly
- Don't skip verifications
- Reference skills when plan says to
- Between batches: just report and wait
- Stop when blocked, don't guess

View File

@@ -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"
}

View File

@@ -0,0 +1,104 @@
---
name: finishing-a-development-branch
description: Use when implementation is complete and all tests pass - verifies and creates PR
---
# Finishing a Development Branch
## Overview
Verify tests pass, then push and create PR.
**Core principle:** Verify tests → Create PR → Done.
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
## The Process
### Step 1: Verify Tests
**Before creating PR, verify tests pass:**
```bash
# Run project's test suite
npm test / cargo test / pytest / go test ./... / mvn test
```
**If tests fail:**
```
Tests failing (<N> failures). Must fix before completing:
[Show failures]
Cannot proceed with PR until tests pass.
```
Stop. Fix tests first.
**If tests pass:** Continue to Step 2.
### Step 2: Push and Create PR
Use the `/pr create` command which will:
1. **Check for existing PR first** - avoids duplicates
2. If PR exists: Report existing PR URL and skip
3. If no PR: Analyze commits, generate title/description, push, create PR
```bash
/pr create
```
**Duplicate prevention:** The `/pr create` command checks for existing open PRs on the current branch before creating a new one.
Report the PR URL when complete (whether existing or newly created).
### Step 3: Cleanup Worktree (if applicable)
Check if working in a worktree:
```bash
git worktree list | grep $(git branch --show-current)
```
If yes, ask user:
```
Worktree at <path>. Remove it now? (y/n)
```
If confirmed:
```bash
git worktree remove <worktree-path>
```
## Quick Reference
```
Tests Pass?
↓ yes
/pr create
PR URL returned
Cleanup worktree (optional)
Done
```
## Red Flags
**Never:**
- Create PR with failing tests
- Skip test verification
- Force-push without explicit request
**Always:**
- Verify tests before creating PR
- Use `/pr create` for consistent PR format
- Report the PR URL
## Integration
**Called by:**
- **executing-plans** (Step 6) - After all batches complete
**Uses:**
- **/pr create** - For pushing and PR creation

View File

@@ -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"
}

View File

@@ -0,0 +1,695 @@
---
name: frontend-design
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
arguments: [component|page|storybook] <description>
---
# Frontend Design 前端设计技能
创建高质量、有设计感的前端界面和组件,支持 Storybook 组件开发。
---
## 命令格式
| 命令 | 功能 | 示例 |
|------|------|------|
| `/frontend-design component <描述>` | 创建 React/Vue 组件 | `/frontend-design component 产品卡片` |
| `/frontend-design page <描述>` | 创建完整页面 | `/frontend-design page 登录页` |
| `/frontend-design storybook <描述>` | 创建带 Storybook 的组件 | `/frontend-design storybook 按钮组件` |
---
## 设计原则
### 1. 设计思维先行
在编码前,明确以下问题:
- **目的**:这个界面解决什么问题?谁在使用?
- **调性**:选择一个明确的美学方向
- **差异化**:什么让这个设计令人难忘?
### 2. 美学方向选择
| 风格 | 特点 | 适用场景 |
|------|------|----------|
| 极简主义 | 大量留白、精炼元素 | 工具类、专业平台 |
| 现代商务 | 清晰层次、专业配色 | 企业官网、B2B |
| 活力年轻 | 鲜艳色彩、动感动画 | 消费品、社交 |
| 奢华精致 | 深色调、金属质感 | 高端品牌、金融 |
| 自然有机 | 柔和曲线、自然色系 | 健康、环保 |
| 复古怀旧 | 经典字体、做旧质感 | 文化、艺术 |
| 未来科技 | 渐变、玻璃拟态 | 科技、创新 |
### 3. 避免的设计陷阱
**禁止使用**
- 过度使用的字体Inter、Roboto、Arial
- 陈词滥调的配色:紫色渐变白底
- 千篇一律的布局
- 缺乏个性的通用组件
**应该追求**
- 独特的字体组合
- 有意图的配色方案
- 打破常规的布局
- 有记忆点的细节
---
## Storybook 组件开发
### 项目结构
```
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.stories.tsx
│ │ ├── Button.module.css
│ │ └── index.ts
│ ├── Card/
│ │ ├── Card.tsx
│ │ ├── Card.stories.tsx
│ │ ├── Card.module.css
│ │ └── index.ts
│ └── index.ts
├── styles/
│ ├── variables.css
│ ├── typography.css
│ └── animations.css
└── .storybook/
├── main.ts
└── preview.ts
```
### 组件模板
#### 1. 组件文件 (Component.tsx)
```tsx
import React from 'react';
import styles from './Component.module.css';
export interface ComponentProps {
/** 组件变体 */
variant?: 'primary' | 'secondary' | 'outline';
/** 尺寸 */
size?: 'sm' | 'md' | 'lg';
/** 是否禁用 */
disabled?: boolean;
/** 子元素 */
children: React.ReactNode;
/** 点击事件 */
onClick?: () => void;
}
export const Component: React.FC<ComponentProps> = ({
variant = 'primary',
size = 'md',
disabled = false,
children,
onClick,
}) => {
return (
<div
className={`${styles.component} ${styles[variant]} ${styles[size]}`}
data-disabled={disabled}
onClick={disabled ? undefined : onClick}
>
{children}
</div>
);
};
```
#### 2. Storybook Stories (Component.stories.tsx)
```tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Component } from './Component';
const meta: Meta<typeof Component> = {
title: 'Components/Component',
component: Component,
tags: ['autodocs'],
parameters: {
layout: 'centered',
docs: {
description: {
component: '组件描述文档',
},
},
},
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline'],
description: '组件变体样式',
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
description: '组件尺寸',
},
disabled: {
control: 'boolean',
description: '是否禁用',
},
},
};
export default meta;
type Story = StoryObj<typeof Component>;
/** 默认状态 */
export const Default: Story = {
args: {
children: '默认组件',
},
};
/** 主要变体 */
export const Primary: Story = {
args: {
variant: 'primary',
children: '主要按钮',
},
};
/** 次要变体 */
export const Secondary: Story = {
args: {
variant: 'secondary',
children: '次要按钮',
},
};
/** 不同尺寸 */
export const Sizes: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Component size="sm"></Component>
<Component size="md"></Component>
<Component size="lg"></Component>
</div>
),
};
/** 禁用状态 */
export const Disabled: Story = {
args: {
disabled: true,
children: '禁用状态',
},
};
```
#### 3. 样式文件 (Component.module.css)
```css
.component {
/* 基础样式 */
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
font-family: var(--font-sans);
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
/* 变体 */
.primary {
background: var(--color-primary);
color: white;
}
.primary:hover {
background: var(--color-primary-dark);
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--color-primary-shadow);
}
.secondary {
background: var(--color-secondary);
color: var(--color-text);
}
.outline {
background: transparent;
border: 2px solid var(--color-border);
color: var(--color-text);
}
/* 尺寸 */
.sm {
padding: 0.5rem 1rem;
font-size: 0.875rem;
}
.md {
padding: 0.75rem 1.5rem;
font-size: 1rem;
}
.lg {
padding: 1rem 2rem;
font-size: 1.125rem;
}
/* 状态 */
[data-disabled="true"] {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
```
---
## 设计系统变量
### CSS 变量模板
```css
:root {
/* 颜色 */
--color-primary: #0066ff;
--color-primary-dark: #0052cc;
--color-primary-light: #4d94ff;
--color-primary-shadow: rgba(0, 102, 255, 0.25);
--color-secondary: #f0f4f8;
--color-accent: #ff6b35;
--color-text: #1a1a2e;
--color-text-muted: #64748b;
--color-text-inverse: #ffffff;
--color-background: #ffffff;
--color-surface: #f8fafc;
--color-border: #e2e8f0;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* 字体 */
--font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-display: 'Clash Display', var(--font-sans);
--font-mono: 'JetBrains Mono', monospace;
/* 字号 */
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--text-4xl: 2.5rem;
/* 间距 */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
--space-16: 4rem;
/* 圆角 */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-xl: 1.5rem;
--radius-full: 9999px;
/* 阴影 */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
/* 动画 */
--duration-fast: 150ms;
--duration-normal: 300ms;
--duration-slow: 500ms;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* 暗色主题 */
[data-theme="dark"] {
--color-text: #f1f5f9;
--color-text-muted: #94a3b8;
--color-background: #0f172a;
--color-surface: #1e293b;
--color-border: #334155;
}
```
---
## 常用组件示例
### 1. 产品卡片 (ProductCard)
```tsx
// ProductCard.tsx
import React from 'react';
import styles from './ProductCard.module.css';
export interface ProductCardProps {
image: string;
title: string;
location: string;
rating: number;
reviewCount: number;
price: number;
originalPrice?: number;
tags?: string[];
onAddToCart?: () => void;
}
export const ProductCard: React.FC<ProductCardProps> = ({
image,
title,
location,
rating,
reviewCount,
price,
originalPrice,
tags = [],
onAddToCart,
}) => {
return (
<article className={styles.card}>
<div className={styles.imageWrapper}>
<img src={image} alt={title} className={styles.image} />
{tags.length > 0 && (
<div className={styles.tags}>
{tags.map((tag) => (
<span key={tag} className={styles.tag} data-tag={tag}>
{tag}
</span>
))}
</div>
)}
</div>
<div className={styles.content}>
<h3 className={styles.title}>{title}</h3>
<p className={styles.location}>📍 {location}</p>
<div className={styles.rating}>
<span className={styles.stars}> {rating.toFixed(1)}</span>
<span className={styles.reviewCount}>({reviewCount})</span>
</div>
<div className={styles.priceRow}>
<div className={styles.price}>
<span className={styles.currency}>¥</span>
<span className={styles.amount}>{price}</span>
<span className={styles.suffix}></span>
</div>
{originalPrice && (
<span className={styles.originalPrice}>¥{originalPrice}</span>
)}
</div>
<button className={styles.addButton} onClick={onAddToCart}>
</button>
</div>
</article>
);
};
```
```tsx
// ProductCard.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { ProductCard } from './ProductCard';
const meta: Meta<typeof ProductCard> = {
title: 'Components/ProductCard',
component: ProductCard,
tags: ['autodocs'],
parameters: {
layout: 'centered',
backgrounds: {
default: 'light',
},
},
};
export default meta;
type Story = StoryObj<typeof ProductCard>;
export const Default: Story = {
args: {
image: 'https://images.unsplash.com/photo-1494947665470-20322015e3a8',
title: '袋鼠岛一日游',
location: '阿德莱德出发',
rating: 4.8,
reviewCount: 126,
price: 389,
tags: ['热卖', '含午餐'],
},
};
export const WithDiscount: Story = {
args: {
...Default.args,
originalPrice: 499,
tags: ['特惠', '限时'],
},
};
export const Grid: Story = {
render: () => (
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 300px)',
gap: '1.5rem'
}}>
<ProductCard
image="https://images.unsplash.com/photo-1494947665470-20322015e3a8"
title="袋鼠岛一日游"
location="阿德莱德出发"
rating={4.8}
reviewCount={126}
price={389}
tags={['热卖']}
/>
<ProductCard
image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
title="巴罗莎谷酒庄之旅"
location="阿德莱德出发"
rating={4.9}
reviewCount={89}
price={299}
originalPrice={399}
tags={['特惠', '含品酒']}
/>
<ProductCard
image="https://images.unsplash.com/photo-1540202403-b7abd6747a18"
title="海豚巡航体验"
location="格雷尔海滩"
rating={4.7}
reviewCount={234}
price={159}
tags={['亲子']}
/>
</div>
),
};
```
### 2. 按钮组件 (Button)
```tsx
// Button.tsx
import React from 'react';
import styles from './Button.module.css';
export interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
fullWidth?: boolean;
loading?: boolean;
disabled?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
children: React.ReactNode;
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
fullWidth = false,
loading = false,
disabled = false,
leftIcon,
rightIcon,
children,
onClick,
}) => {
return (
<button
className={`
${styles.button}
${styles[variant]}
${styles[size]}
${fullWidth ? styles.fullWidth : ''}
`}
disabled={disabled || loading}
onClick={onClick}
>
{loading ? (
<span className={styles.spinner} />
) : (
<>
{leftIcon && <span className={styles.icon}>{leftIcon}</span>}
<span>{children}</span>
{rightIcon && <span className={styles.icon}>{rightIcon}</span>}
</>
)}
</button>
);
};
```
---
## Storybook 配置
### .storybook/main.ts
```ts
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
```
### .storybook/preview.ts
```ts
import type { Preview } from '@storybook/react';
import '../src/styles/variables.css';
import '../src/styles/typography.css';
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#ffffff' },
{ name: 'gray', value: '#f8fafc' },
{ name: 'dark', value: '#0f172a' },
],
},
},
globalTypes: {
theme: {
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
title: 'Theme',
icon: 'circlehollow',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
},
};
export default preview;
```
---
## 快速启动命令
### 创建新组件
```bash
# 创建组件目录
mkdir -p src/components/ComponentName
# 创建文件
touch src/components/ComponentName/{ComponentName.tsx,ComponentName.stories.tsx,ComponentName.module.css,index.ts}
```
### 安装 Storybook
```bash
# 初始化 Storybook
npx storybook@latest init
# 安装额外插件
npm install -D @storybook/addon-a11y @storybook/addon-interactions
# 启动 Storybook
npm run storybook
```
---
## 设计检查清单
### 组件质量检查
- [ ] Props 接口定义完整,带 JSDoc 注释
- [ ] 支持必要的变体variant和尺寸size
- [ ] 处理禁用和加载状态
- [ ] 支持自定义 className
- [ ] 键盘可访问性
- [ ] 屏幕阅读器友好
### Storybook 质量检查
- [ ] 所有变体都有对应 Story
- [ ] argTypes 配置完整
- [ ] 包含组件文档描述
- [ ] 交互状态可测试
- [ ] 响应式展示
### 视觉质量检查
- [ ] 字体选择有特色
- [ ] 配色方案协调
- [ ] 动画流畅自然
- [ ] 间距一致
- [ ] 暗色主题支持

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "pull-request",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "review-checklist",
"install_type": "skill",
"dir_category": "dev"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "data-excel",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -10,5 +10,8 @@
"name": "doubao-voice", "name": "doubao-voice",
"path": "./skills/SKILL.md" "path": "./skills/SKILL.md"
} }
] ],
"install_name": "doubao-voice",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "feishu-bitable",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "feishu-docx",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.1.0", "version": "1.1.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "feishu",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "siyuan",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -5,128 +5,35 @@ description: 思源笔记 API 集成。通过自然语言创建、编辑、搜
# 思源笔记 API 集成 Skill # 思源笔记 API 集成 Skill
## 服务配置 ## 环境变量配置(必须)
### 阿里云生产环境 (推荐) 本 skill 通过环境变量读取思源笔记连接信息,不同用户/组织配置不同的值。
| 配置项 | 值 | **在 `~/.claude/settings.json` 中配置:**
|--------|-----|
| 服务地址 | `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 (自动续期) |
### Tailscale 内网环境 (备用) ```json
{
"env": {
"SIYUAN_URL": "${SIYUAN_URL}",
"SIYUAN_TOKEN": "your-api-token-here"
}
}
```
| 配置项 | 值 | 或在项目级 `.claude/settings.json` 中配置(优先级更高)。
|--------|-----|
| 服务地址 | `http://47.93.23.182` (Tailscale) | **检查配置是否就绪:** 执行任何思源操作前,先确认环境变量已设置:
| 局域网地址 | `http://192.168.1.50:6806` |
| API Token | `nfnycjb1g8vbexb2` | ```bash
| 版本 | 3.1.5 | echo "URL: ${SIYUAN_URL:-未配置}"
| 部署位置 | 飞牛OS (Docker) | echo "TOKEN: ${SIYUAN_TOKEN:+已配置}"
```
如果未配置,提示用户在 `~/.claude/settings.json``env` 中添加 `SIYUAN_URL``SIYUAN_TOKEN`
--- ---
## 服务器管理 (阿里云) ## 🔐 保存<E4BF9D><E5AD98><EFBFBD>敏感<E6958F><E6849F>息脱敏
### 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 所有 API 请求使用 POST 方法,需携带 Token
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/xxx \ curl -X POST ${SIYUAN_URL}/api/xxx \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"param": "value"}' -d '{"param": "value"}'
``` ```
@@ -239,8 +146,8 @@ curl -X POST https://siyuan.pipexerp.com/api/xxx \
#### 列出所有笔记本 #### 列出所有笔记本
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/lsNotebooks \ curl -X POST ${SIYUAN_URL}/api/notebook/lsNotebooks \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{}' -d '{}'
``` ```
@@ -248,8 +155,8 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/lsNotebooks \
#### 创建笔记本 #### 创建笔记本
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/createNotebook \ curl -X POST ${SIYUAN_URL}/api/notebook/createNotebook \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"name": "笔记本名称"}' -d '{"name": "笔记本名称"}'
``` ```
@@ -257,8 +164,8 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/createNotebook \
#### 删除笔记本 #### 删除笔记本
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/notebook/removeNotebook \ curl -X POST ${SIYUAN_URL}/api/notebook/removeNotebook \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID"}' -d '{"notebook": "笔记本ID"}'
``` ```
@@ -276,22 +183,22 @@ curl -X POST https://siyuan.pipexerp.com/api/notebook/removeNotebook \
```bash ```bash
# 1. 先查询是否存在(按路径精确匹配) # 1. 先查询是否存在(按路径精确匹配)
DOC_PATH="/网络管理/家庭Tailscale网络" DOC_PATH="/网络管理/家庭Tailscale网络"
EXISTING=$(curl -s -X POST https://siyuan.pipexerp.com/api/query/sql \ EXISTING=$(curl -s -X POST ${SIYUAN_URL}/api/query/sql \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "{\"stmt\": \"SELECT id FROM blocks WHERE type='d' AND hpath='${DOC_PATH}' LIMIT 1\"}" \ -d "{\"stmt\": \"SELECT id FROM blocks WHERE type='d' AND hpath='${DOC_PATH}' LIMIT 1\"}" \
| jq -r '.data[0].id // empty') | jq -r '.data[0].id // empty')
if [ -n "$EXISTING" ]; then if [ -n "$EXISTING" ]; then
# 2a. 存在则更新 # 2a. 存在则更新
curl -s -X POST https://siyuan.pipexerp.com/api/block/updateBlock \ curl -s -X POST ${SIYUAN_URL}/api/block/updateBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "{\"id\": \"${EXISTING}\", \"dataType\": \"markdown\", \"data\": \"# 更新的内容\"}" -d "{\"id\": \"${EXISTING}\", \"dataType\": \"markdown\", \"data\": \"# 更新的内容\"}"
else else
# 2b. 不存在则创建 # 2b. 不存在则创建
curl -s -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \ curl -s -X POST ${SIYUAN_URL}/api/filetree/createDocWithMd \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/网络管理/家庭Tailscale网络", "markdown": "# 新内容"}' -d '{"notebook": "笔记本ID", "path": "/网络管理/家庭Tailscale网络", "markdown": "# 新内容"}'
fi fi
@@ -300,8 +207,8 @@ fi
#### 创建文档 (仅新建时使用) #### 创建文档 (仅新建时使用)
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \ curl -X POST ${SIYUAN_URL}/api/filetree/createDocWithMd \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"notebook": "笔记本ID", "notebook": "笔记本ID",
@@ -313,8 +220,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/createDocWithMd \
#### 获取文档内容 #### 获取文档内容
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/getDoc \ curl -X POST ${SIYUAN_URL}/api/filetree/getDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "文档ID"}' -d '{"id": "文档ID"}'
``` ```
@@ -322,8 +229,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/getDoc \
#### 删除文档 #### 删除文档
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/removeDoc \ curl -X POST ${SIYUAN_URL}/api/filetree/removeDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/文档路径"}' -d '{"notebook": "笔记本ID", "path": "/文档路径"}'
``` ```
@@ -331,8 +238,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/removeDoc \
#### 重命名文档 #### 重命名文档
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/filetree/renameDoc \ curl -X POST ${SIYUAN_URL}/api/filetree/renameDoc \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"notebook": "笔记本ID", "path": "/旧路径", "title": "新标题"}' -d '{"notebook": "笔记本ID", "path": "/旧路径", "title": "新标题"}'
``` ```
@@ -344,8 +251,8 @@ curl -X POST https://siyuan.pipexerp.com/api/filetree/renameDoc \
#### 插入块 #### 插入块
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/block/insertBlock \ curl -X POST ${SIYUAN_URL}/api/block/insertBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"dataType": "markdown", "dataType": "markdown",
@@ -357,8 +264,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/insertBlock \
#### 更新块 #### 更新块
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/block/updateBlock \ curl -X POST ${SIYUAN_URL}/api/block/updateBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"dataType": "markdown", "dataType": "markdown",
@@ -370,8 +277,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/updateBlock \
#### 删除块 #### 删除块
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/block/deleteBlock \ curl -X POST ${SIYUAN_URL}/api/block/deleteBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "块ID"}' -d '{"id": "块ID"}'
``` ```
@@ -383,8 +290,8 @@ curl -X POST https://siyuan.pipexerp.com/api/block/deleteBlock \
#### 全文搜索 #### 全文搜索
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/search/fullTextSearchBlock \ curl -X POST ${SIYUAN_URL}/api/search/fullTextSearchBlock \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"query": "搜索关键词", "query": "搜索关键词",
@@ -395,8 +302,8 @@ curl -X POST https://siyuan.pipexerp.com/api/search/fullTextSearchBlock \
#### SQL 查询 #### SQL 查询
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/query/sql \ curl -X POST ${SIYUAN_URL}/api/query/sql \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"stmt": "SELECT * FROM blocks WHERE content LIKE '\''%关键词%'\'' LIMIT 10" "stmt": "SELECT * FROM blocks WHERE content LIKE '\''%关键词%'\'' LIMIT 10"
@@ -410,8 +317,8 @@ curl -X POST https://siyuan.pipexerp.com/api/query/sql \
#### 导出 Markdown #### 导出 Markdown
```bash ```bash
curl -X POST https://siyuan.pipexerp.com/api/export/exportMdContent \ curl -X POST ${SIYUAN_URL}/api/export/exportMdContent \
-H "Authorization: Token nfnycjb1g8vbexb2" \ -H "Authorization: Token ${SIYUAN_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "文档ID"}' -d '{"id": "文档ID"}'
``` ```
@@ -421,13 +328,16 @@ curl -X POST https://siyuan.pipexerp.com/api/export/exportMdContent \
## Python 封装 ## Python 封装
```python ```python
import os
import requests import requests
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
class SiYuanAPI: class SiYuanAPI:
"""思源笔记 API 封装""" """思源笔记 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.base_url = base_url
self.headers = { self.headers = {
"Authorization": f"Token {token}", "Authorization": f"Token {token}",

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "siyuan-to-feishu",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "wecom",
"install_type": "skill",
"dir_category": "integration"
} }

View File

@@ -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"
}

View File

@@ -0,0 +1,105 @@
---
name: req-audit
description: 部署后审计。运行时日志检查 + 静态缺陷分析 + 设计偏移检测。可独立调用或由 /req done 自动触发。
---
# 部署后审计 (audit)
对本次部署执行三维度审计:运行时行为、代码缺陷、设计偏移。
## 执行流程
### 2a. 运行时检查
检查部署后是否有新增错误。
**优先 SSH**
```bash
ssh -o ConnectTimeout=3 ${EC2_USER}@${EC2_HOST} \
"docker logs ${APP_CONTAINER} --since 10m 2>&1 | grep -i 'error\|panic\|fatal\|traceback'"
```
**降级 1CI 日志**
```bash
RUN_ID=$(gh run list --repo ${OWNER}/${REPO} --limit 1 --json databaseId -q '.[0].databaseId')
gh run view ${RUN_ID} --repo ${OWNER}/${REPO} --log 2>&1 | grep -i 'error\|panic\|fatal'
```
**降级 2N/A + 警告**
```
⚠️ 无法获取运行时日志SSH 不可达 + CI 日志无异常信息2a 标记为 N/A。
运行时问题可能未被发现,建议手动检查服务器日志。
```
### 2b. 静态分析
调用现有 `/defect-analysis` command传入变更文件
```
对以下变更文件执行缺陷分析:
{变更文件列表}
重点关注:运行时行为(不是合并前 CR 的重复,而是部署后复查)
```
输出:缺陷清单(按致命/高/中/低分级)
### 2c. 设计偏移检测
1. 读取需求的 PRD 文档linkRole=prd 的任务文档)
2. 读取本次变更的源码
3. AI 对比分析:
```
请对比以下 PRD 功能点和实际代码实现:
PRD 功能点:
{从 PRD 提取的功能清单}
实际代码变更:
{变更文件的关键逻辑}
检查:
- 遗漏的功能PRD 有但代码没实现)
- 多做的功能(代码有但 PRD 没提)
- 实现方式与 PRD 描述不一致
```
输出:偏移项列表
### 合并报告
```markdown
## 部署后审计报告
### 2a 运行时检查
| 检查项 | 结果 | 详情 |
| 新增错误 | ✅ 无 / ❌ 有 N 条 | ... |
### 2b 静态分析
| 缺陷 | 严重度 | 描述 |
(来自 defect-analysis 输出)
### 2c 设计偏移
| 偏移项 | 类型 | 说明 |
### 结论
- 致命/高级缺陷: N 个 → {阻断/通过}
- 中/低级缺陷: N 个 → 已创建 backlog
- 设计偏移: N 项 → {建议处理方式}
```
### 缺陷分级处理
| 级别 | 处理 |
|------|------|
| 致命 | 阻断归档 + 回滚建议 + `ai-proj task create` 创建修复任务并关联需求 |
| 高级 | 阻断归档 + 回滚建议 + 创建修复任务 |
| 中级 | 警告不阻断 + 创建 backlog 任务 |
| 低级 | 记录到报告,不创建任务 |
## 任务关联
- linkRole: `code_review`
- 任务标题: `【审计】部署后审计: {需求标题}`
- 报告附加到任务文档

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-compare",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -4,5 +4,8 @@
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-design",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -5,5 +5,8 @@
"deprecated": true, "deprecated": true,
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-dev",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -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"
}

View File

@@ -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`
- 任务标题: `【回归】回归测试: {需求标题}`
- 报告附加到任务文档

View File

@@ -4,5 +4,8 @@
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -4,5 +4,8 @@
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-prd",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -136,12 +136,49 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
### 6.2 灰度策略 ### 6.2 灰度策略
[灰度发布计划] [灰度发布计划]
## 7. 风险评估 ## 7. 验收标准 ⭐ 强制包含 VP 三件套
> **规则(源自 REQ-20260421-0002**:每条 AC 必须附带 VP-Data / VP-Steps / VP-Pass缺一项评审不通过。
### AC1: [验收条件标题]
**目标**[一句话描述期望结果]
**VP-Data前置测试数据**
- 环境localhost / production二选一明确注明
- 数据:[字段、值、状态,例如:需求状态=approved关联任务 3 个task_project_id 非空]
- 建数据方式:[curl localhost:8080/... 或 MCP 工具,禁止混用]
**VP-Steps验证步骤**
1. [工具 + 操作例如agent-browser open http://localhost:3000/xxx]
2. [检查指标例如eval `document.querySelector('.xxx').textContent`]
3. [确认值,例如:返回值包含"期望字符串"]
**VP-Pass通过判定**
- ✅ [具体期望值例如eval 返回数组长度 = 3]
- ✅ [第二个判定条件]
- ❌ [明确的不通过条件,例如:仅靠代码分析得出结论 = 不通过]
---
### AC2: [第二条验收条件]
**目标**...
**VP-Data**...
**VP-Steps**...
**VP-Pass**
- ✅ ...
- ❌ ...
## 8. 风险评估
| 风险 | 影响 | 概率 | 应对措施 | | 风险 | 影响 | 概率 | 应对措施 |
|------|------|------|----------| |------|------|------|----------|
| ... | 高/中/低 | 高/中/低 | ... | | ... | 高/中/低 | 高/中/低 | ... |
## 8. 附录 ## 9. 附录
- 相关文档链接 - 相关文档链接
- 参考资料 - 参考资料
``` ```
@@ -172,6 +209,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 用户积分规则-修改接口
```
---
## 用户故事编写 ## 用户故事编写
### 标准格式 ### 标准格式
@@ -371,7 +483,7 @@ mcp__ai-proj__export_task_document_to_file
- [ ] 背景与目标明确 - [ ] 背景与目标明确
- [ ] 用户群体定义清晰 - [ ] 用户群体定义清晰
- [ ] 功能需求完整 - [ ] 功能需求完整
- [ ] 验收标准可测试 - [ ] 验收标准可测试(每条 AC 附带 VP-Data / VP-Steps / VP-Pass
- [ ] 异常情况已考虑 - [ ] 异常情况已考虑
- [ ] 性能要求已定义 - [ ] 性能要求已定义
- [ ] 上线计划合理 - [ ] 上线计划合理

View File

@@ -1,8 +1,11 @@
{ {
"name": "req-prototype-plugin", "name": "req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。", "description": "原型生成与关联。支持 HTML 上传(/req prototype uploadiframe 嵌入详情页)和 Stitch AI 生成两种模式。",
"version": "1.0.0", "version": "2.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-prototype",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -303,6 +303,7 @@ generated_at: "<timestamp>"
> 背景REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。 > 背景REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。
### Stitch 模式 ### Stitch 模式
| 异常 | 处理 | | 异常 | 处理 |

View File

@@ -2,5 +2,10 @@
"name": "req-research-plugin", "name": "req-research-plugin",
"description": "需求调研插件。代码审计、数据库分析、现有功能调研。挂载在 analysis 阶段,需要深度调研时激活。", "description": "需求调研插件。代码审计、数据库分析、现有功能调研。挂载在 analysis 阶段,需要深度调研时激活。",
"version": "1.0.0", "version": "1.0.0",
"author": { "name": "qiudl" } "author": {
"name": "qiudl"
},
"install_name": "req-research",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -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"
}

View File

@@ -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 附加到任务文档

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-review",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -23,7 +23,8 @@ PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据
| 功能描述 | ✓ | 详细功能需求 | | 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 | | 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 | | API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 | | 验收标准 | ✓ | 验收条件(每条 AC 必须附带 VP 三件套,见下方) |
| VP 三件套 | ✓ | 每条 AC 后必须有 VP-Data / VP-Steps / VP-Pass 三个子节 |
| 用户故事 | ○ | As a... I want... | | 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 如有 Stitch 原型则必审:布局合理性、与 PRD 描述一致性 | | 页面原型 | ○ | 如有 Stitch 原型则必审:布局合理性、与 PRD 描述一致性 |
| 非功能需求 | ○ | 性能、安全 | | 非功能需求 | ○ | 性能、安全 |
@@ -112,6 +113,19 @@ PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据
【驳回人】xxx 【时间】2026-xx-xx 【驳回人】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 不合理 | 重新设计 | | 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 | | 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 | | 验收不明 | 缺 AC 或 VP 三件套 | 补充验收条件和 VP |

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-test-gate",
"install_type": "skill",
"dir_category": "req"
} }

View File

@@ -4,5 +4,8 @@
"version": "1.0.0", "version": "1.0.0",
"author": { "author": {
"name": "qiudl" "name": "qiudl"
} },
"install_name": "req-workflow",
"install_type": "skill",
"dir_category": "req"
} }

119
update-plugin-meta.py Normal file
View File

@@ -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/<install_name>/
# "command" -> ~/.claude/commands/<install_name>.md
PLUGIN_MAP = {
# skills-biz
"biz-contract-plugin": ("biz-contract", "skill", "biz"),
"biz-ops-plugin": ("biz-ops", "skill", "biz"),
"biz-plan-plugin": ("biz-plan", "skill", "biz"),
"finance-plugin": ("finance", "skill", "biz"),
# skills-core
"ai-proj-plugin": ("ai-proj", "skill", "core"),
"pm-ask-plugin": ("pm-ask", "skill", "core"),
"pm-risk-plugin": ("pm-risk", "skill", "core"),
"publish-plugin": ("publish", "skill", "core"),
# skills-dev
"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)