Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ffee89840 | ||
|
|
998b22e905 | ||
|
|
826bba8485 | ||
|
|
f5c5bd3f40 | ||
|
|
4e6ae9036a | ||
|
|
3b38deb078 | ||
|
|
16e58047a0 | ||
|
|
dec25562a4 | ||
|
|
d630b374a3 | ||
|
|
8fc1cd05b7 | ||
|
|
b859a84455 | ||
|
|
9a1400758e | ||
|
|
a58dd1aff3 | ||
|
|
bb5e6be73e | ||
|
|
ef0e9ca1f0 | ||
|
|
ad4e2b16a8 | ||
|
|
ba107a54a8 | ||
|
|
4ea6920a13 | ||
|
|
039a749e3e | ||
|
|
daca19a262 | ||
|
|
ddb5d5cb06 | ||
|
|
da57cccf96 | ||
|
|
7eed2b8f10 | ||
|
|
5a45916b2c |
+59
-122
@@ -95,6 +95,32 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ai-proj-cicd-release-plugin",
|
||||
"source": "./skills-dev/ai-proj-cicd-release-plugin",
|
||||
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ai-proj-macos-release-plugin",
|
||||
"source": "./skills-dev/ai-proj-macos-release-plugin",
|
||||
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "db-migration-plugin",
|
||||
"source": "./skills-dev/db-migration-plugin",
|
||||
@@ -111,7 +137,7 @@
|
||||
"name": "defect-analysis-plugin",
|
||||
"source": "./skills-dev/defect-analysis-plugin",
|
||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -329,7 +355,7 @@
|
||||
"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",
|
||||
"version": "1.0.1",
|
||||
"category": "development",
|
||||
"keywords": [
|
||||
"development",
|
||||
@@ -338,6 +364,18 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "karpathy-guidelines-plugin",
|
||||
"source": "./skills-dev/karpathy-guidelines-plugin",
|
||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||
"version": "1.0.1",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "pull-request-plugin",
|
||||
"source": "./skills-dev/pull-request-plugin",
|
||||
@@ -355,7 +393,7 @@
|
||||
"name": "review-checklist-plugin",
|
||||
"source": "./skills-dev/review-checklist-plugin",
|
||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -363,6 +401,19 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "slark-cicd-plugin",
|
||||
"source": "./skills-dev/slark-cicd-plugin",
|
||||
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
|
||||
"version": "1.1.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-audit-plugin",
|
||||
"source": "./skills-req/req-audit-plugin",
|
||||
@@ -444,8 +495,8 @@
|
||||
{
|
||||
"name": "req-prd-plugin",
|
||||
"source": "./skills-req/req-prd-plugin",
|
||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
||||
"version": "2.0.0",
|
||||
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||
"version": "2.2.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
@@ -457,8 +508,8 @@
|
||||
{
|
||||
"name": "req-prototype-plugin",
|
||||
"source": "./skills-req/req-prototype-plugin",
|
||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
||||
"version": "2.0.0",
|
||||
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||
"version": "2.2.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
@@ -548,7 +599,7 @@
|
||||
"name": "doubao-voice-plugin",
|
||||
"source": "./skills-integration/doubao-voice-plugin",
|
||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -684,120 +735,6 @@
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "gitea-plugin",
|
||||
"source": "./skills-personal/gitea-plugin",
|
||||
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "openclaw-plugin",
|
||||
"source": "./skills-personal/openclaw-plugin",
|
||||
"description": "OpenClaw (龙虾) 远程 AI 计算调度系统 - 概念设计与运维管理",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-servers-plugin",
|
||||
"source": "./skills-personal/ops-servers-plugin",
|
||||
"description": "企业服务器管理。用于云服务器分组管理、系统监控、备份管理、故障排查。当用户提到云服务器、生产环境、腾讯云、阿里云相关任务时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-tools-plugin",
|
||||
"source": "./skills-personal/ops-tools-plugin",
|
||||
"description": "Plugin for ops-tools",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "qiudl-personal-plugin",
|
||||
"source": "./skills-personal/qiudl-personal-plugin",
|
||||
"description": "Plugin for qiudl-personal",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "reload-session-plugin",
|
||||
"source": "./skills-personal/reload-session-plugin",
|
||||
"description": "Reload a previously saved Claude session to continue the conversation.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-deploy-plugin",
|
||||
"source": "./skills-personal/req-deploy-plugin",
|
||||
"description": "Plugin for req-deploy",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "save-session-plugin",
|
||||
"source": "./skills-personal/save-session-plugin",
|
||||
"description": "Auto-save Claude session conversation with AI-generated title, summary, and tags in searchable JSON format.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "search-sessions-plugin",
|
||||
"source": "./skills-personal/search-sessions-plugin",
|
||||
"description": "Search saved Claude sessions by title, tags, date, or content.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
# ai-proj-helper
|
||||
|
||||
Claude Code 技能市场 + MCP 配置管理工具。
|
||||
Codex 优先、兼容 Claude Code 的 Agent Skills 市场与 MCP 配置管理工具。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
./init.sh
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
交互式配置 MCP 连接(默认 SSE 模式)+ 自动注册技能市场到 `~/.claude/plugins/known_marketplaces.json`。支持命令行参数:
|
||||
默认安装到 Codex 标准目录 `~/.agents/skills`。Claude Code 的 MCP 与 marketplace 初始化使用:
|
||||
|
||||
```bash
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
@@ -18,11 +18,11 @@ Claude Code 技能市场 + MCP 配置管理工具。
|
||||
|
||||
```
|
||||
ai-proj-helper/
|
||||
├── skills-core/ # 基础设施 (1): ai-proj
|
||||
├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
|
||||
├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
|
||||
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
|
||||
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
|
||||
├── skills-core/ # 基础设施技能
|
||||
├── skills-dev/ # 开发与发布技能
|
||||
├── skills-req/ # 需求管理技能
|
||||
├── skills-integration/ # 第三方集成技能
|
||||
├── skills-biz/ # 商务技能
|
||||
├── skills-personal/ # 个人(.gitignore 排除)
|
||||
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
||||
├── init.sh # MCP 初始化
|
||||
@@ -51,4 +51,4 @@ skills:
|
||||
|
||||
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
|
||||
- 其余 `skills-*` 目录均由 Git 版本控制
|
||||
- 所有目录都会被 `generate-marketplace.py` 自动扫描并加入 marketplace.json
|
||||
- 只有受 Git 跟踪的分类目录会被 `generate-marketplace.py` 扫描并加入公开 marketplace;`skills-personal/` 始终排除
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ai-proj-helper — 让 Claude Code 变成你的项目经理
|
||||
# ai-proj-helper — 让 Codex / Claude Code 变成你的项目经理
|
||||
|
||||
> 一套开箱即用的 Claude Code 技能包 + MCP 服务,帮你用自然语言管理需求、写代码、做评审、同步飞书,把 AI 助手变成真正的项目经理。
|
||||
> 一套遵循 Agent Skills 标准的技能包 + MCP 服务,支持 Codex,并兼容 Claude Code。
|
||||
|
||||
## 它能帮你做什么
|
||||
|
||||
@@ -66,7 +66,7 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
|
||||
|
||||
### 前置条件
|
||||
|
||||
- **Claude Code** 已安装([安装指南](https://docs.anthropic.com/en/docs/claude-code/overview))
|
||||
- **Codex**([Skills 文档](https://developers.openai.com/codex/skills))或 **Claude Code** 已安装
|
||||
- **ai-proj 账号 + MCP API Key**:联系管理员获取(Key 格式: `aiproj_pk_xxx`)
|
||||
|
||||
### 一键部署(2 步搞定)
|
||||
@@ -76,17 +76,16 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
|
||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
cd ai-proj-helper
|
||||
|
||||
# 2. 运行初始化(按提示输入 API Key 即可)
|
||||
./init.sh
|
||||
# 2. 默认安装到 Codex 的用户级标准目录 ~/.agents/skills
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
脚本会自动完成:
|
||||
- 配置 MCP 服务器连接(`~/.claude/.mcp.json`)
|
||||
- 注册技能市场到 Claude Code(`~/.claude/plugins/known_marketplaces.json`)
|
||||
安装器会复制完整技能目录,包括 `SKILL.md`、references、scripts 和 assets。Codex 会自动发现 `~/.agents/skills` 中的技能;若没有出现,重启 Codex。
|
||||
|
||||
也支持命令行参数跳过交互:
|
||||
Claude Code 用户显式选择 Claude 目标;需要同时配置 MCP 和 marketplace 时运行 `init.sh`:
|
||||
|
||||
```bash
|
||||
./install-skills.sh --agent claude
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
```
|
||||
|
||||
@@ -163,7 +162,7 @@ skills:
|
||||
|
||||
- **mode**: MCP 连接模式。`sse` 直连远程服务器(推荐),`stdio` 在本地启动 Node.js 进程
|
||||
- **disabled**: 不需要的技能可以加到这里,重新运行 `./init.sh` 生效
|
||||
- **personal_dir**: 个人技能目录,默认不被 Git 跟踪
|
||||
- **personal_dir**: 本机个人技能目录,默认不被 Git 跟踪,也不会写入公开 marketplace
|
||||
|
||||
## 常见问题
|
||||
|
||||
@@ -171,13 +170,17 @@ skills:
|
||||
|
||||
A: 需要先联系管理员获取 MCP API Key(格式 `aiproj_pk_xxx`),然后在提示处输入。
|
||||
|
||||
**Q: 安装后 Codex 没有识别到技能?**
|
||||
|
||||
A: 确认技能位于 `~/.agents/skills/<name>/SKILL.md`,然后重启 Codex。Codex CLI 也可用 `/skills` 查看。
|
||||
|
||||
**Q: 安装后 Claude Code 没有识别到技能?**
|
||||
|
||||
A: 重启 Claude Code 后生效。如果仍不生效,检查 `~/.claude/plugins/known_marketplaces.json` 中是否包含 `ai-proj-helper` 条目。
|
||||
|
||||
**Q: 如何更新到最新版本?**
|
||||
|
||||
A: 进入项目目录执行 `git pull`,然后重新运行 `./init.sh`。
|
||||
A: 进入项目目录执行 `git pull`,然后运行 `./install-skills.sh`;Claude Code 用户增加 `--agent claude`。
|
||||
|
||||
**Q: 如何禁用不需要的技能?**
|
||||
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
# Setup Guide
|
||||
# Claude Code Marketplace Setup
|
||||
|
||||
## 1. Create Repository on Gitea
|
||||
本页只描述 Claude Code marketplace。Codex 用户直接运行 `./install-skills.sh`,技能默认安装到 `~/.agents/skills`。
|
||||
|
||||
Go to https://gitea.pipexerp.com and create a new repository:
|
||||
- Name: `claude-marketplace`
|
||||
- Visibility: Private or Public (your choice)
|
||||
- **Do NOT** initialize with README (we already have one)
|
||||
|
||||
## 2. Push to Gitea
|
||||
## 1. Clone the Gitea Repository
|
||||
|
||||
```bash
|
||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
||||
git push -u origin main
|
||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
cd ai-proj-helper
|
||||
```
|
||||
|
||||
## 3. Test Installation
|
||||
## 2. Test Installation
|
||||
|
||||
### Add the marketplace
|
||||
```bash
|
||||
# SSH (recommended)
|
||||
/plugin marketplace add git@gitea.pipexerp.com:huangjun/claude-marketplace.git
|
||||
# SSH
|
||||
/plugin marketplace add ssh://git@gitea.pipexerp.com:10022/pipexerp/ai-proj-helper.git
|
||||
|
||||
# OR HTTPS (requires credential configuration)
|
||||
/plugin marketplace add https://gitea.pipexerp.com/huangjun/claude-marketplace.git
|
||||
/plugin marketplace add https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
```
|
||||
|
||||
### List available plugins
|
||||
@@ -42,12 +37,12 @@ git push -u origin main
|
||||
# Check for your installed plugins
|
||||
```
|
||||
|
||||
## 4. Update Plugins Later
|
||||
## 3. Update Plugins Later
|
||||
|
||||
When you make changes and push updates:
|
||||
|
||||
```bash
|
||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
||||
cd /path/to/ai-proj-helper
|
||||
|
||||
# Make changes to plugins
|
||||
# ...
|
||||
@@ -67,7 +62,7 @@ Users update with:
|
||||
/plugin update ai-proj-plugin@coolbuy-claude-plugins
|
||||
```
|
||||
|
||||
## 5. Private Repository Setup
|
||||
## 4. Repository Authentication
|
||||
|
||||
If your Gitea repo is private, users need authentication:
|
||||
|
||||
@@ -87,30 +82,28 @@ To create a Gitea token:
|
||||
3. Give it "Read repository" permissions
|
||||
4. Copy the token and add to your environment
|
||||
|
||||
## 6. Structure Overview
|
||||
## 5. Structure Overview
|
||||
|
||||
```
|
||||
claude-marketplace/
|
||||
ai-proj-helper/
|
||||
├── .claude-plugin/
|
||||
│ └── marketplace.json # Catalog of all plugins
|
||||
├── plugins/
|
||||
│ ├── ai-proj-plugin/
|
||||
│ │ ├── .claude-plugin/
|
||||
│ │ │ └── plugin.json # Plugin metadata
|
||||
│ │ └── skills/
|
||||
│ │ └── SKILL.md # Skill definition
|
||||
│ └── [33 more plugins...]
|
||||
├── skills-core/ # Core plugins
|
||||
├── skills-dev/ # Development and release plugins
|
||||
├── skills-req/ # Requirement plugins
|
||||
├── skills-integration/ # Integration plugins
|
||||
├── skills-biz/ # Business plugins
|
||||
├── README.md # User documentation
|
||||
├── SETUP.md # This file
|
||||
└── convert-skills.sh # Conversion script (reference)
|
||||
├── generate-marketplace.py # Marketplace generator
|
||||
└── install-skills.sh # Versioned local installer
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Push to Gitea: `git push -u origin main`
|
||||
2. ✅ Test locally: `/plugin marketplace add <url>`
|
||||
3. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
||||
4. ✅ Share with team: Send them the repository URL
|
||||
1. ✅ Test locally: `/plugin marketplace add <url>`
|
||||
2. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
||||
3. ✅ Share with team: Send them the repository URL
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -123,7 +116,7 @@ claude-marketplace/
|
||||
- Check plugin name is correct
|
||||
- Ensure marketplace.json is valid: `cat .claude-plugin/marketplace.json | jq`
|
||||
|
||||
**"Skills not working"**
|
||||
**"Skills not working in Claude Code"**
|
||||
- Skills are Agent Skills (auto-invoked by Claude when relevant)
|
||||
- They don't create slash commands
|
||||
- Check plugin installation: `/plugin list`
|
||||
|
||||
+41
-190
@@ -1,218 +1,69 @@
|
||||
# Skill Sync Guide
|
||||
|
||||
## Overview
|
||||
仓库中的插件是团队技能的发布源。默认安装目标是 Codex 的用户级标准目录 `~/.agents/skills/`。个人技能保留在
|
||||
`skills-personal/` 或其他本机目录,不会进入公开 marketplace。
|
||||
|
||||
This guide explains how to keep your local skills (`~/.claude/skills/`) synchronized with the marketplace plugins.
|
||||
|
||||
## Quick Sync
|
||||
## 从仓库更新本机
|
||||
|
||||
```bash
|
||||
cd /path/to/claude-marketplace
|
||||
./sync-skills.sh
|
||||
git pull
|
||||
./install-skills.sh --dry-run
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
1. ✅ Compare local skills with marketplace plugins
|
||||
2. ➕ Add new skills as plugins
|
||||
3. 📝 Update changed skills
|
||||
4. ✓ Skip unchanged plugins
|
||||
|
||||
## Sync Workflow
|
||||
|
||||
### 1. Edit Skills Locally
|
||||
|
||||
Work on your skills in `~/.claude/skills/`:
|
||||
```bash
|
||||
code ~/.claude/skills/my-skill/SKILL.md
|
||||
```
|
||||
|
||||
### 2. Run Sync Script
|
||||
Claude Code 需要显式选择目标:
|
||||
|
||||
```bash
|
||||
cd ~/path/to/claude-marketplace
|
||||
./sync-skills.sh
|
||||
./install-skills.sh --agent claude
|
||||
```
|
||||
|
||||
### 3. Review Changes
|
||||
安装器会复制完整技能目录,包括 `SKILL.md`、`references/`、`scripts/` 和 `assets/`。它用内容摘要区分仓库升级和本地修改:
|
||||
|
||||
- 目标未修改时,版本升级会自动安装。
|
||||
- 旧版只安装了 `SKILL.md` 时,会安全补齐仓库中的其他同源文件。
|
||||
- 目标存在本地修改时会跳过;确认覆盖后才使用 `--force`。
|
||||
- `--cleanup` 会删除状态文件记录中已从仓库移除的技能,使用前先运行 `--dry-run --cleanup`。
|
||||
|
||||
按分类安装或查看清单:
|
||||
|
||||
```bash
|
||||
git status
|
||||
git diff
|
||||
./install-skills.sh --list
|
||||
./install-skills.sh --category dev
|
||||
./install-skills.sh --exclude ai-proj-cicd-release
|
||||
```
|
||||
|
||||
### 4. Commit & Push
|
||||
## 将本机技能发布到仓库
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Update skill: description of changes"
|
||||
git push
|
||||
```
|
||||
不要批量复制整个 `~/.agents/skills/` 或其他 Agent 的安装目录。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
|
||||
|
||||
### 5. Team Updates
|
||||
1. 选择确实属于本仓库、可供团队复用的技能。
|
||||
2. 在对应 `skills-*/<name>-plugin/` 下放置 `.claude-plugin/plugin.json` 和完整 `skills/` 目录。
|
||||
3. 清除用户名、绝对路径、内网地址、密钥标识和历史凭据;把环境差异改为从仓库配置解析。
|
||||
4. 更新插件版本并运行:
|
||||
|
||||
Team members update with:
|
||||
```bash
|
||||
/plugin marketplace update coolbuy-claude-plugins
|
||||
/plugin update <plugin-name>@coolbuy-claude-plugins
|
||||
```
|
||||
```bash
|
||||
python3 generate-marketplace.py
|
||||
claude plugin validate .
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Automated Sync (Optional)
|
||||
5. 审核变更后通过分支和 PR 发布。
|
||||
|
||||
### Git Hook (Pre-commit)
|
||||
## 本地个人技能
|
||||
|
||||
Auto-sync when committing changes to skills:
|
||||
`skills-personal/` 受 `.gitignore` 保护,仅供当前机器使用。生成器明确排除此目录,避免
|
||||
`marketplace.json` 引用公开克隆中不存在的文件。若个人技能要转为团队技能,应先按上面的发布流程完成脱敏和审核。
|
||||
|
||||
```bash
|
||||
# In your dotfiles/skills repo
|
||||
cat > .git/hooks/pre-commit << 'EOF'
|
||||
#!/bin/bash
|
||||
# Auto-sync skills to marketplace
|
||||
~/path/to/claude-marketplace/sync-skills.sh
|
||||
EOF
|
||||
## 常见问题
|
||||
|
||||
chmod +x .git/hooks/pre-commit
|
||||
```
|
||||
**本地修改被跳过怎么办?**
|
||||
|
||||
### Cron Job (Scheduled)
|
||||
先比较仓库源和 `~/.agents/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。Claude 目标改查 `~/.claude/skills/`。
|
||||
|
||||
Sync daily at 9 AM:
|
||||
**marketplace 没更新?**
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
运行 `python3 generate-marketplace.py`,然后检查 `.claude-plugin/marketplace.json` 是否只包含受 Git 跟踪且真实存在的 source。
|
||||
|
||||
# Add this line:
|
||||
0 9 * * * cd ~/path/to/claude-marketplace && ./sync-skills.sh && git add . && git commit -m "Daily sync" && git push
|
||||
```
|
||||
**如何移除技能?**
|
||||
|
||||
## Skill Splitting Guidelines
|
||||
|
||||
From `~/.claude/CLAUDE.md`:
|
||||
|
||||
- **Token Limit**: Single skill ≤ 10,000 tokens
|
||||
- **Check Size**: `wc -w ~/.claude/skills/<skill>/SKILL.md`
|
||||
- **When to Split**: If > 7,500 words (≈10,000 tokens)
|
||||
|
||||
### Split Strategy
|
||||
|
||||
When a skill grows too large:
|
||||
|
||||
1. **Entry Skill** - Overview + command routing (<100 lines)
|
||||
- Example: `req/SKILL.md`
|
||||
|
||||
2. **Command Reference** - Detailed commands (<200 lines)
|
||||
- Example: `req-commands/SKILL.md`
|
||||
|
||||
3. **Workflow Guide** - Complete processes (<200 lines)
|
||||
- Example: `req-workflow/SKILL.md`
|
||||
|
||||
4. **Methodology** - Complex concepts (<150 lines)
|
||||
- Example: `req-review/SKILL.md`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Sync Script Fails
|
||||
|
||||
```bash
|
||||
# Check permissions
|
||||
ls -la sync-skills.sh
|
||||
|
||||
# Make executable
|
||||
chmod +x sync-skills.sh
|
||||
|
||||
# Check paths
|
||||
echo $HOME/.claude/skills
|
||||
```
|
||||
|
||||
### marketplace.json Not Updated
|
||||
|
||||
```bash
|
||||
# Manually regenerate
|
||||
python3 generate-marketplace.py
|
||||
|
||||
# Or edit directly
|
||||
code .claude-plugin/marketplace.json
|
||||
```
|
||||
|
||||
### Git Conflicts
|
||||
|
||||
```bash
|
||||
# Discard local changes
|
||||
git checkout .claude-plugin/marketplace.json
|
||||
|
||||
# Or merge manually
|
||||
git mergetool
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Descriptive Frontmatter
|
||||
|
||||
Always include in `SKILL.md`:
|
||||
```yaml
|
||||
---
|
||||
name: skill-name
|
||||
description: Clear, concise description of what this skill does
|
||||
---
|
||||
```
|
||||
|
||||
### 2. Version Bumping
|
||||
|
||||
When making significant changes:
|
||||
```bash
|
||||
# Update version in plugin.json
|
||||
{
|
||||
"version": "1.1.0" # was 1.0.0
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Testing Before Sync
|
||||
|
||||
```bash
|
||||
# Test skill locally first
|
||||
/skill-name
|
||||
|
||||
# Then sync to marketplace
|
||||
./sync-skills.sh
|
||||
```
|
||||
|
||||
### 4. Commit Messages
|
||||
|
||||
Use clear, descriptive messages:
|
||||
```bash
|
||||
git commit -m "Add feishu-bitable plugin for table operations"
|
||||
git commit -m "Update req-workflow with new approval process"
|
||||
git commit -m "Fix: Correct PRD template in req-prd"
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Sync Status
|
||||
|
||||
```bash
|
||||
# Compare local vs marketplace
|
||||
diff -qr ~/.claude/skills /tmp/claude-marketplace/plugins
|
||||
```
|
||||
|
||||
### List Differences
|
||||
|
||||
```bash
|
||||
# Find skills not in marketplace
|
||||
comm -23 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
|
||||
|
||||
# Find plugins not in local
|
||||
comm -13 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I sync in reverse (marketplace → local)?**
|
||||
A: Not recommended. Treat local skills as the source of truth.
|
||||
|
||||
**Q: What about binary files (images, scripts)?**
|
||||
A: Copy them manually to the plugin directory, then commit.
|
||||
|
||||
**Q: How do I remove a plugin?**
|
||||
A: Delete the plugin directory, regenerate marketplace.json, commit, and push.
|
||||
|
||||
**Q: Can I sync specific skills only?**
|
||||
A: Modify `sync-skills.sh` to accept a skill name parameter.
|
||||
删除插件目录、重新生成 marketplace、提交变更。使用者随后执行 `./install-skills.sh --dry-run --cleanup`,确认后再去掉 `--dry-run`。
|
||||
|
||||
+7
-14
@@ -14,28 +14,27 @@ script_dir = Path(__file__).parent.resolve()
|
||||
config_file = script_dir / "claude-config.yaml"
|
||||
marketplace_file = script_dir / ".claude-plugin" / "marketplace.json"
|
||||
|
||||
# Skill directories (label, directory name)
|
||||
# Public marketplace skill directories. skills-personal is deliberately
|
||||
# excluded: it is gitignored and must never produce sources that disappear from
|
||||
# a public clone of this repository.
|
||||
SKILL_DIRS = [
|
||||
("core", "skills-core"),
|
||||
("dev", "skills-dev"),
|
||||
("req", "skills-req"),
|
||||
("integration", "skills-integration"),
|
||||
("biz", "skills-biz"),
|
||||
("personal", "skills-personal"),
|
||||
]
|
||||
|
||||
|
||||
def load_config():
|
||||
"""Load claude-config.yaml and return disabled list + personal_dir."""
|
||||
"""Load claude-config.yaml and return the disabled plugin list."""
|
||||
disabled = []
|
||||
personal = "skills-personal"
|
||||
|
||||
if config_file.exists() and HAS_YAML:
|
||||
with open(config_file) as f:
|
||||
cfg = yaml.safe_load(f) or {}
|
||||
skills_cfg = cfg.get("skills", {})
|
||||
disabled = skills_cfg.get("disabled", []) or []
|
||||
personal = skills_cfg.get("personal_dir", personal)
|
||||
elif config_file.exists():
|
||||
# Fallback: parse disabled list without PyYAML
|
||||
in_disabled = False
|
||||
@@ -54,17 +53,14 @@ def load_config():
|
||||
disabled.append(val)
|
||||
elif stripped and not stripped.startswith("#"):
|
||||
break
|
||||
if stripped.startswith("personal_dir:"):
|
||||
personal = stripped.split(":", 1)[1].strip().strip('"').strip("'")
|
||||
|
||||
return disabled, personal
|
||||
return disabled
|
||||
|
||||
|
||||
# Category mapping
|
||||
def get_category_and_keywords(plugin_name):
|
||||
if any(x in plugin_name for x in ['dev-', 'coding', 'frontend']):
|
||||
return "development", ["development", "coding", "workflow"]
|
||||
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server']):
|
||||
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server', 'slark-cicd']):
|
||||
return "devops", ["devops", "deployment", "operations"]
|
||||
elif any(x in plugin_name for x in ['ai-proj', 'req']):
|
||||
return "productivity", ["project-management", "tasks", "requirements"]
|
||||
@@ -116,15 +112,12 @@ def scan_plugins(directory, source_prefix, disabled):
|
||||
|
||||
|
||||
# Load config
|
||||
disabled_skills, personal_dir_name = load_config()
|
||||
disabled_skills = load_config()
|
||||
|
||||
# Collect plugins from all skill directories
|
||||
plugins = []
|
||||
counts = {}
|
||||
for label, dir_name in SKILL_DIRS:
|
||||
# personal_dir may be overridden by config
|
||||
if label == "personal":
|
||||
dir_name = personal_dir_name
|
||||
skill_path = script_dir / dir_name
|
||||
if not skill_path.is_dir():
|
||||
continue
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# ai-proj-helper 初始化脚本
|
||||
# 配置 MCP 连接 + 安装技能到 ~/.claude/skills/
|
||||
# 配置 Claude MCP 连接 + 安装 Claude 技能
|
||||
|
||||
set -e
|
||||
|
||||
@@ -183,32 +183,13 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Install skills to ~/.claude/skills/ ──────────────────────────────
|
||||
# ── Install complete skill packages ──────────────────────────────────
|
||||
# Use the versioned installer as the single installation path so references,
|
||||
# scripts and assets stay beside SKILL.md and local edits are not overwritten.
|
||||
echo "📦 安装技能到 ~/.claude/skills/ ..."
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
mkdir -p "$SKILLS_DIR"
|
||||
|
||||
SKILL_COUNT=0
|
||||
for plugin_dir in "$SCRIPT_DIR"/skills-*/; do
|
||||
for skill_path in "$plugin_dir"*-plugin/; do
|
||||
[ -d "$skill_path" ] || continue
|
||||
skill_md="$skill_path/skills/SKILL.md"
|
||||
[ -f "$skill_md" ] || continue
|
||||
|
||||
# Extract skill name: ai-proj-plugin -> ai-proj
|
||||
dir_name=$(basename "$skill_path")
|
||||
skill_name="${dir_name%-plugin}"
|
||||
|
||||
target_dir="$SKILLS_DIR/$skill_name"
|
||||
mkdir -p "$target_dir"
|
||||
|
||||
# Copy SKILL.md (overwrite if exists)
|
||||
cp "$skill_md" "$target_dir/SKILL.md"
|
||||
SKILL_COUNT=$((SKILL_COUNT + 1))
|
||||
done
|
||||
done
|
||||
echo " 已安装 $SKILL_COUNT 个技能"
|
||||
echo "✅ 技能安装完成 → $SKILLS_DIR"
|
||||
"$SCRIPT_DIR/install-skills.sh" --agent claude
|
||||
SKILL_COUNT=$(python3 -c 'import json, os; p=os.path.expanduser("~/.claude/.installed-skills.json"); print(len(json.load(open(p))) if os.path.exists(p) else 0)' 2>/dev/null || echo 0)
|
||||
echo "✅ 技能安装完成"
|
||||
|
||||
# ── Verify MCP connection ────────────────────────────────────────────
|
||||
echo ""
|
||||
@@ -270,7 +251,7 @@ if $HAS_CLAUDE; then
|
||||
else
|
||||
echo " ✅ MCP 服务器 → $MCP_CONFIG"
|
||||
fi
|
||||
echo " ✅ 技能 ($SKILL_COUNT 个) → $SKILLS_DIR"
|
||||
echo " ✅ 技能 ($SKILL_COUNT 个) → ~/.claude/skills"
|
||||
echo ""
|
||||
echo "重启 Claude Code 即可使用。"
|
||||
echo "如需更改配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
||||
|
||||
+177
-59
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# install-skills.sh — Cross-machine Claude skill sync from ai-proj-helper
|
||||
# install-skills.sh — Cross-agent skill sync from ai-proj-helper
|
||||
#
|
||||
# Usage:
|
||||
# ./install-skills.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --agent <agent> Install target: codex (default) or claude
|
||||
# --dry-run Preview changes without writing anything
|
||||
# --category <cat> Only install plugins in dir_category=<cat>
|
||||
# Valid values: biz, core, dev, integration, personal, req
|
||||
# --exclude <name> Skip one install_name (repeatable)
|
||||
# --force Overwrite even if local files were modified
|
||||
# --cleanup Remove locally installed skills that are no longer in repo
|
||||
# --list List all available plugins without installing
|
||||
@@ -16,15 +18,18 @@
|
||||
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"
|
||||
SKILLS_DIR=""
|
||||
COMMANDS_DIR=""
|
||||
STATE_FILE=""
|
||||
|
||||
AGENT_TARGET="codex"
|
||||
DRY_RUN=false
|
||||
CATEGORY_FILTER=""
|
||||
EXCLUDED_NAMES=()
|
||||
FORCE=false
|
||||
CLEANUP=false
|
||||
LIST_ONLY=false
|
||||
INSTALL_ACTION=false
|
||||
|
||||
# ── Colour helpers ─────────────────────────────────────────────────────────────
|
||||
GREEN='\033[0;32m'
|
||||
@@ -42,11 +47,19 @@ dry() { echo -e "${YELLOW}[dry]${RESET} $*"; }
|
||||
# ── Argument parsing ───────────────────────────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--agent)
|
||||
[[ $# -ge 2 ]] || { error "--agent requires codex or claude"; exit 1; }
|
||||
AGENT_TARGET="$2"; shift ;;
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--force) FORCE=true ;;
|
||||
--cleanup) CLEANUP=true ;;
|
||||
--list) LIST_ONLY=true ;;
|
||||
--category) CATEGORY_FILTER="$2"; shift ;;
|
||||
--category)
|
||||
[[ $# -ge 2 ]] || { error "--category requires a value"; exit 1; }
|
||||
CATEGORY_FILTER="$2"; shift ;;
|
||||
--exclude)
|
||||
[[ $# -ge 2 ]] || { error "--exclude requires an install_name"; exit 1; }
|
||||
EXCLUDED_NAMES+=("$2"); shift ;;
|
||||
--help|-h)
|
||||
grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//'
|
||||
exit 0 ;;
|
||||
@@ -57,6 +70,24 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
done
|
||||
|
||||
case "$AGENT_TARGET" in
|
||||
codex)
|
||||
# ~/.agents/skills is the current user-level Codex discovery location and
|
||||
# is intentionally agent-neutral. Commands are installed as normal skills.
|
||||
SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.agents/skills}"
|
||||
STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.agents/.ai-proj-helper-installed-skills.json}"
|
||||
;;
|
||||
claude)
|
||||
SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.claude/skills}"
|
||||
COMMANDS_DIR="${AI_PROJ_HELPER_COMMANDS_DIR:-${HOME}/.claude/commands}"
|
||||
STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.claude/.installed-skills.json}"
|
||||
;;
|
||||
*)
|
||||
error "Unsupported agent: $AGENT_TARGET (expected codex or claude)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# ── State helpers (plain JSON via python3) ─────────────────────────────────────
|
||||
state_get() {
|
||||
# state_get <install_name> -> prints version or empty string
|
||||
@@ -72,14 +103,28 @@ except: pass
|
||||
fi
|
||||
}
|
||||
|
||||
state_digest() {
|
||||
# state_digest <install_name> -> prints installed content digest or empty string
|
||||
local name="$1"
|
||||
if [[ -f "$STATE_FILE" ]]; then
|
||||
python3 -c "
|
||||
import json
|
||||
try:
|
||||
d=json.load(open('$STATE_FILE'))
|
||||
print(d.get('$name',{}).get('content_digest',''))
|
||||
except: pass
|
||||
" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
state_set() {
|
||||
# state_set <install_name> <version> <install_type>
|
||||
local name="$1" ver="$2" itype="$3"
|
||||
# state_set <install_name> <version> <install_type> <content_digest>
|
||||
local name="$1" ver="$2" itype="$3" digest="$4"
|
||||
python3 -c "
|
||||
import json,os
|
||||
f='$STATE_FILE'
|
||||
d=json.load(open(f)) if os.path.exists(f) else {}
|
||||
d['$name']={'version':'$ver','install_type':'$itype'}
|
||||
d['$name']={'version':'$ver','install_type':'$itype','content_digest':'$digest','agent':'$AGENT_TARGET'}
|
||||
json.dump(d,open(f,'w'),indent=2)
|
||||
" 2>/dev/null
|
||||
}
|
||||
@@ -116,6 +161,66 @@ read_field() {
|
||||
python3 -c "import json,sys; d=json.load(open('$1')); print(d.get('$2',''))" 2>/dev/null || true
|
||||
}
|
||||
|
||||
content_digest() {
|
||||
# Stable digest for one command file or a complete skill directory.
|
||||
python3 - "$1" <<'PY'
|
||||
import hashlib
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
target = pathlib.Path(sys.argv[1])
|
||||
if not target.exists():
|
||||
print("")
|
||||
raise SystemExit
|
||||
|
||||
digest = hashlib.sha256()
|
||||
files = [target] if target.is_file() else sorted(
|
||||
path for path in target.rglob("*") if path.is_file() or path.is_symlink()
|
||||
)
|
||||
for path in files:
|
||||
# A single-file command is renamed when installed for Claude. Hash its
|
||||
# content under a stable logical name so source and target compare equally.
|
||||
relative = "." if target.is_file() else path.relative_to(target).as_posix()
|
||||
digest.update(relative.encode("utf-8"))
|
||||
digest.update(b"\0")
|
||||
if path.is_symlink():
|
||||
digest.update(b"link\0")
|
||||
digest.update(os.readlink(path).encode("utf-8"))
|
||||
else:
|
||||
digest.update(path.read_bytes())
|
||||
digest.update(b"\0")
|
||||
print(digest.hexdigest())
|
||||
PY
|
||||
}
|
||||
|
||||
is_compatible_subset() {
|
||||
# True when every file in an existing legacy target also exists unchanged in
|
||||
# the repository source. This safely upgrades old SKILL.md-only installs.
|
||||
python3 - "$1" "$2" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
source = pathlib.Path(sys.argv[1])
|
||||
target = pathlib.Path(sys.argv[2])
|
||||
if not source.is_dir() or not target.is_dir():
|
||||
raise SystemExit(1)
|
||||
|
||||
for target_path in target.rglob("*"):
|
||||
if target_path.is_dir():
|
||||
continue
|
||||
source_path = source / target_path.relative_to(target)
|
||||
if not source_path.is_file() or target_path.is_symlink() != source_path.is_symlink():
|
||||
raise SystemExit(1)
|
||||
if target_path.is_symlink():
|
||||
if target_path.readlink() != source_path.readlink():
|
||||
raise SystemExit(1)
|
||||
elif target_path.read_bytes() != source_path.read_bytes():
|
||||
raise SystemExit(1)
|
||||
raise SystemExit(0)
|
||||
PY
|
||||
}
|
||||
|
||||
# Resolve the actual source directory to rsync from.
|
||||
# If skills/ has SKILL.md at the top level, use it directly.
|
||||
# If skills/ has a single subdirectory (e.g. skills/dev-test/SKILL.md), use that subdirectory.
|
||||
@@ -135,33 +240,9 @@ resolve_skills_src() {
|
||||
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() {
|
||||
INSTALL_ACTION=false
|
||||
local json_path="$1"
|
||||
local plugin_dir
|
||||
plugin_dir="$(dirname "$(dirname "$json_path")")" # strip /.claude-plugin/plugin.json
|
||||
@@ -173,6 +254,11 @@ install_plugin() {
|
||||
dir_category="$(read_field "$json_path" dir_category)"
|
||||
version="$(read_field "$json_path" version)"
|
||||
|
||||
local excluded
|
||||
for excluded in ${EXCLUDED_NAMES[@]+"${EXCLUDED_NAMES[@]}"}; do
|
||||
[[ "$install_name" == "$excluded" ]] && return
|
||||
done
|
||||
|
||||
# Skip if no install metadata (legacy plugin without our new fields)
|
||||
if [[ -z "$install_name" || -z "$install_type" ]]; then
|
||||
warn "$(basename "$plugin_dir"): missing install_name/install_type, skipping"
|
||||
@@ -190,35 +276,67 @@ install_plugin() {
|
||||
return
|
||||
fi
|
||||
|
||||
local effective_install_type="$install_type"
|
||||
if [[ "$AGENT_TARGET" == "codex" ]]; then
|
||||
effective_install_type="skill"
|
||||
fi
|
||||
|
||||
if [[ "$LIST_ONLY" == true ]]; then
|
||||
echo " [$dir_category] $install_type:$install_name v$version"
|
||||
echo " [$dir_category] $effective_install_type:$install_name v$version"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check current installed version
|
||||
local current_version
|
||||
# Resolve actual source (handles plugins where content sits one level deeper,
|
||||
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md).
|
||||
local src_dir
|
||||
src_dir="$(resolve_skills_src "$skills_dir")"
|
||||
|
||||
local source_path target_path
|
||||
if [[ "$effective_install_type" == "command" ]]; then
|
||||
source_path="$src_dir/SKILL.md"
|
||||
target_path="$COMMANDS_DIR/${install_name}.md"
|
||||
else
|
||||
source_path="$src_dir"
|
||||
target_path="$SKILLS_DIR/$install_name"
|
||||
fi
|
||||
|
||||
if [[ ! -e "$source_path" ]]; then
|
||||
warn "$install_name: install source not found, skipping"
|
||||
return
|
||||
fi
|
||||
|
||||
# A recorded content digest distinguishes repository updates from user edits.
|
||||
# Legacy state is adopted automatically only when the target is missing or
|
||||
# already identical to the repository source.
|
||||
local current_version recorded_digest source_digest target_digest
|
||||
current_version="$(state_get "$install_name")"
|
||||
recorded_digest="$(state_digest "$install_name")"
|
||||
source_digest="$(content_digest "$source_path")"
|
||||
target_digest="$(content_digest "$target_path")"
|
||||
|
||||
# Skip if up-to-date (same version) and no force
|
||||
if [[ "$current_version" == "$version" && "$FORCE" == false ]]; then
|
||||
if [[ "$FORCE" == false && -n "$target_digest" && "$target_digest" == "$source_digest" ]]; then
|
||||
if [[ "$DRY_RUN" == false && ( "$current_version" != "$version" || "$recorded_digest" != "$source_digest" ) ]]; then
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# 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)"
|
||||
local legacy_subset=false
|
||||
if [[ "$effective_install_type" == "skill" && -z "$recorded_digest" && -n "$target_digest" ]]; then
|
||||
if is_compatible_subset "$source_path" "$target_path"; then
|
||||
legacy_subset=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$FORCE" == false && -n "$target_digest" && "$legacy_subset" == false ]]; then
|
||||
if [[ -z "$recorded_digest" || "$target_digest" != "$recorded_digest" ]]; then
|
||||
warn "$install_name: local files were modified or have legacy unverified state — skipping (use --force once to adopt repository content)"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# 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
|
||||
if [[ "$effective_install_type" == "command" ]]; then
|
||||
# Single-file command → ~/.claude/commands/<name>.md
|
||||
local src_md="$src_dir/SKILL.md"
|
||||
if [[ ! -f "$src_md" ]]; then
|
||||
@@ -228,25 +346,29 @@ install_plugin() {
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
dry "$install_name → $COMMANDS_DIR/${install_name}.md"
|
||||
INSTALL_ACTION=true
|
||||
else
|
||||
mkdir -p "$COMMANDS_DIR"
|
||||
cp "$src_md" "$COMMANDS_DIR/${install_name}.md"
|
||||
state_set "$install_name" "$version" "$install_type"
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
ok "$install_name → command (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
|
||||
else
|
||||
# Skill directory → ~/.claude/skills/<name>/
|
||||
# Standard skill directory → the selected agent's discovery root.
|
||||
local dst_dir="$SKILLS_DIR/$install_name"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
dry "$install_name → $dst_dir/"
|
||||
INSTALL_ACTION=true
|
||||
else
|
||||
mkdir -p "$dst_dir"
|
||||
# rsync resolved source (handles nested skills/ structures)
|
||||
rsync -a --delete "$src_dir/" "$dst_dir/"
|
||||
state_set "$install_name" "$version" "$install_type"
|
||||
rsync -a --checksum --delete "$src_dir/" "$dst_dir/"
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
ok "$install_name → skill (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -307,19 +429,15 @@ main() {
|
||||
return
|
||||
fi
|
||||
|
||||
info "Installing Claude skills from: $REPO_DIR"
|
||||
info "Installing skills for $AGENT_TARGET from: $REPO_DIR"
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
|
||||
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
|
||||
|
||||
local installed=0 skipped=0
|
||||
local installed=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
|
||||
if [[ "$INSTALL_ACTION" == true ]]; then
|
||||
((installed++)) || true
|
||||
fi
|
||||
done < <(find_plugins)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "ai-proj-cicd-release-plugin",
|
||||
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "ai-proj-cicd-release",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: ai-proj-cicd-release
|
||||
description: Execute and audit the AI-Proj service CI/CD flow across Gitea gates, immutable image builds, staging verification, approved production release, rollback, and evidence capture. Use for AI-Proj CI status, release PRs, staging or production deployments, failed-release diagnosis, deployed commit/schema verification, and delivery-chain repair. Do not use for unrelated repositories or macOS application packaging.
|
||||
---
|
||||
|
||||
# AI-Proj CI/CD release
|
||||
|
||||
Use the repository's live workflows and release scripts as the executable source of truth. Keep staging and production isolated, bind artifacts to exact commits, and fail closed when a gate, provenance check, rollback target, or environment contract is uncertain.
|
||||
|
||||
## Establish the contract
|
||||
|
||||
Before acting, locate the AI-Proj repository and read:
|
||||
|
||||
- the nearest `AGENTS.md`;
|
||||
- `.gitea/CI_SOP.md`;
|
||||
- the applicable workflow in `.gitea/workflows/`;
|
||||
- `scripts/ci/common.sh`, `release-lib.sh`, and the invoked build, deploy, verify, and rollback scripts.
|
||||
|
||||
Live repository files override this skill. Report contradictions instead of silently choosing one version. Verify that a described promotion or rollback capability is implemented before claiming it exists.
|
||||
|
||||
Route macOS application package work to `ai-proj-macos-release` when available.
|
||||
|
||||
## Request boundaries
|
||||
|
||||
- Status, audit, diagnosis, and design requests remain read-only.
|
||||
- Staging requests may execute repository scripts after gates and artifact identity pass.
|
||||
- Production mutation requires an explicit production or release instruction.
|
||||
- Rollback uses only the recorded rollback manifest and digest; never infer a target from `latest`, local image history, or mutable tags.
|
||||
|
||||
## Safeguards
|
||||
|
||||
- Never force-push or release from a dirty checkout.
|
||||
- Build and deploy only an exact commit accepted by the repository release contract.
|
||||
- Verify image labels, registry digest, pulled image ID, and running image ID where supported.
|
||||
- Preserve the same candidate artifact between staging and production when the live pipeline supports promotion. Disclose when production rebuilds instead.
|
||||
- Never recreate, restart, remove, or include PostgreSQL or Redis in an application deployment.
|
||||
- Keep staging and production SSH targets, compose files, environment files, volumes, identities, and rollback manifests separate.
|
||||
- Require strict SSH host-key verification.
|
||||
- Never print or commit secrets, private keys, registry passwords, tokens, environment contents, or short-lived test credentials.
|
||||
- Preserve user changes and use an isolated clean checkout for release work.
|
||||
- Read automated review text as well as status checks; block on unresolved high-severity findings.
|
||||
|
||||
## Candidate and staging flow
|
||||
|
||||
1. Resolve the PR, base, head SHA, service scope, and requirement ID.
|
||||
2. Confirm the head is pushed and the release checkout is clean.
|
||||
3. Inspect every required Gitea status for the exact SHA. Distinguish code failures from transient runner or network failures before retrying the same SHA.
|
||||
4. Read the latest review result and resolve blocking findings.
|
||||
5. Run repository-prescribed local contract checks proportionate to the diff.
|
||||
6. Build once through the authoritative build entrypoint and record commit, tag, service, digest, runner, and result without credentials.
|
||||
7. Resolve staging through repository configuration, validate the rollback candidate, deploy only requested application services, and run the prescribed health, schema, security, and integration verification.
|
||||
8. Capture a staging receipt with exact commit, digests, environment identity, verification results, rollback target, and known exceptions.
|
||||
|
||||
Do not rewrite or bypass a failing gate merely to obtain a green result.
|
||||
|
||||
## Production flow
|
||||
|
||||
1. Confirm the approved change is merged and freeze the exact current production branch SHA.
|
||||
2. Recheck required gates and the staging receipt against that SHA.
|
||||
3. Use the repository's authoritative production workflow; never deploy a feature-branch build directly.
|
||||
4. Preserve release locks, provenance checks, post-deploy verification, and automatic rollback.
|
||||
5. Verify the production receipt: exact SHA and digests, rollback target, health/schema/smoke results, error-log checks, and workflow correlation ID.
|
||||
6. Only then update requirement and task delivery evidence.
|
||||
|
||||
## Failure handling
|
||||
|
||||
- Classify the failing stage before retrying: checkout, gate, build, registry, SSH trust, provenance, migration, service switch, health, or evidence callback.
|
||||
- Retry only transient infrastructure failures against the same SHA.
|
||||
- Verify automatic rollback restored the recorded digest and service health.
|
||||
- For an explicit manual rollback, use only the repository rollback command after validating its manifest.
|
||||
- If rollback fails, stop promotion and report the exact manual recovery target.
|
||||
|
||||
During long operations, provide concise progress updates. Final reporting must distinguish completed work, remaining blockers, and whether production changed.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "ai-proj-macos-release-plugin",
|
||||
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "ai-proj-macos-release",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: ai-proj-macos-release
|
||||
description: Build, sign, notarize, publish, and verify the AI-Proj macOS Apple Silicon package through the repository's release chain. Use when asked to release, republish, update, or repair the downloadable macOS application, including Gatekeeper failures and download-manifest updates. Do not use for service deployments or unrelated applications.
|
||||
---
|
||||
|
||||
# AI-Proj macOS release
|
||||
|
||||
Use this workflow only for an explicitly requested AI-Proj macOS package release. Repository scripts and current project instructions are authoritative; stop and report any contradiction.
|
||||
|
||||
## Resolve the release contract
|
||||
|
||||
Before building, read the nearest `AGENTS.md`, the desktop package configuration, and the repository's macOS build, publish, and verification scripts. Resolve from those files:
|
||||
|
||||
- application version and architecture;
|
||||
- production API configuration;
|
||||
- signing identity and notarization mechanism;
|
||||
- object-storage bucket, endpoint, release prefix, and public manifest;
|
||||
- required website or download-manifest fallback version.
|
||||
|
||||
Do not copy machine-specific credential paths or identifiers into source control. Use the operator's configured secure credential provider without printing secret values.
|
||||
|
||||
## Release flow
|
||||
|
||||
1. Confirm the requested release version is unused. Keep package metadata, native application metadata, artifact filename, public manifest, and website fallback aligned.
|
||||
2. Use a clean checkout of the exact approved commit. Run the repository's production desktop build script with the production API mode.
|
||||
3. Require a valid Developer ID signature. If the repository's default notarization profile is unavailable, use another already-authorized App Store Connect credential source only after confirming its key, key ID, and issuer belong together.
|
||||
4. Submit the final package to Apple notarization, wait for acceptance, staple the ticket, and validate it.
|
||||
5. Mount the package read-only and verify the nested application with `codesign`, `spctl`, and the repository's smoke checks. Require Gatekeeper to report a notarized Developer ID.
|
||||
6. Publish through the repository script. Use its configured object-storage credentials and upload mode; never handcraft a mutable public path when the script provides immutable versioned objects.
|
||||
7. Require remote read-back verification of size and SHA-256. Upload artifacts first and update the public manifest last.
|
||||
8. Download the public artifact independently and repeat signature, notarization, Gatekeeper, size, and checksum verification.
|
||||
9. Confirm the manifest's latest version and asset URL, then update the website entry if the request includes it.
|
||||
|
||||
## Failure boundaries
|
||||
|
||||
- Missing signing or storage credentials: stop and report the missing configured provider; do not search broadly through personal files.
|
||||
- Notarization authentication failure: stop and correct the credential tuple; never publish an unnotarized package.
|
||||
- Gatekeeper reports an unnotarized or invalid application: do not publish.
|
||||
- Upload stalls or fails: use only an alternative mode supported by the repository script, then repeat remote checksum verification.
|
||||
- A public version already exists: do not overwrite it unless the user explicitly authorizes replacement and the repository permits it.
|
||||
- Never expose signing keys, API keys, keychain passwords, storage credentials, or token values in logs, commits, manifests, or bundles.
|
||||
|
||||
Record the exact commit, version, artifact checksum and size, Apple result, public URL, manifest result, and verification outcome. Do not mark the release complete until the independently downloaded artifact passes all checks.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "defect-analysis-plugin",
|
||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -59,7 +59,9 @@ description: 系统性设计缺陷分析。对需求方案/代码架构进行多
|
||||
|
||||
- 每轮检查一个维度,输出发现的缺陷列表
|
||||
- 如果某轮发现 0 个新缺陷 → **收敛,停止**
|
||||
- 如果 5 轮后仍有新发现 → 继续,最多 10 轮
|
||||
- 如果 5 轮后仍有新发现 → 继续;20 轮作为阶段复盘点,不得误报为已收敛
|
||||
- 达到 20 轮仍有新发现时,汇总剩余风险面并请求用户确认是否继续;用户已明确要求持续审计时可继续下一阶段
|
||||
- 只有出现一轮 0 个新缺陷时才标记收敛;达到授权范围、时间或预算边界时应报告“尚未收敛”,不得伪装完成
|
||||
- 每个缺陷标注严重度和轮次
|
||||
|
||||
## 输出格式
|
||||
|
||||
@@ -73,6 +73,72 @@ ai-proj task append-doc --id <taskId> --content "实现说明"
|
||||
|
||||
---
|
||||
|
||||
## Step 0:验证优先(Karpathy: Goal-Driven Execution)
|
||||
|
||||
**编写任何代码前,必须先写验证脚本。** 规则来源:Karpathy "Goal-Driven Execution" 原则。
|
||||
|
||||
> "Define success criteria. Loop until verified."
|
||||
> "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
||||
|
||||
### 执行流程
|
||||
|
||||
```
|
||||
① 写验证脚本(按类型选择)
|
||||
② 运行一遍,确认全部 FAIL(证明功能确实不存在 / bug 确实存在)
|
||||
③ 编码实现
|
||||
④ 再次运行验证脚本,全部 PASS → 完成
|
||||
```
|
||||
|
||||
### 后端验证脚本模板
|
||||
|
||||
实现 API 前,先写好所有 curl 命令并标注期望结果:
|
||||
|
||||
```bash
|
||||
# 验证脚本:REQ-XXXX [功能名]
|
||||
BASE="http://localhost:8080"
|
||||
TOKEN="<JWT>"
|
||||
|
||||
echo "=== T1: 正常创建 ==="
|
||||
curl -s -X POST "$BASE/api/v1/xxx" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"name":"test"}' | jq '.code'
|
||||
# 期望: 0
|
||||
|
||||
echo "=== T2: 缺少必填字段 ==="
|
||||
curl -s -X POST "$BASE/api/v1/xxx" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{}' | jq '.code'
|
||||
# 期望: 非 0(参数错误)
|
||||
|
||||
echo "=== T3: 跨租户访问 ==="
|
||||
curl -s -X GET "$BASE/api/v1/xxx/999" \
|
||||
-H "Authorization: Bearer $TOKEN_OTHER_TENANT" | jq '.code'
|
||||
# 期望: 403
|
||||
```
|
||||
|
||||
**先运行 → 全部 FAIL → 编码 → 再次运行 → 全部 PASS**
|
||||
|
||||
### 前端验证脚本模板
|
||||
|
||||
实现页面前,先列出所有 `data-testid` 和期望的 DOM 状态:
|
||||
|
||||
```
|
||||
验证清单(编码前先确认这些状态不存在 / 行为不正确):
|
||||
- data-testid="xxx-btn-submit" 点击 → 列表刷新,行数增加 1
|
||||
- data-testid="xxx-table" 行数 === API 返回 total
|
||||
- data-testid="xxx-input-name" 空值提交 → 显示「请输入名称」提示
|
||||
```
|
||||
|
||||
### 与 VP 三件套的关系
|
||||
|
||||
| VP 协议 | 验证优先对应 |
|
||||
|---------|------------|
|
||||
| VP-Data | 先在环境建好测试数据(curl 确认成功) |
|
||||
| VP-Steps | **即为本节验证脚本** — 编码前写好,编码后执行 |
|
||||
| VP-Pass | 验证脚本每条命令的期望输出值 |
|
||||
|
||||
---
|
||||
|
||||
## Go 后端开发
|
||||
|
||||
### 分层架构
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: dev-review
|
||||
description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。
|
||||
description: 代码评审技能。六视角对抗性扫描法(含 Karpathy Scope 审计),用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。
|
||||
---
|
||||
|
||||
# 代码评审 Skill (dev-review)
|
||||
|
||||
## 概述
|
||||
|
||||
独立的代码评审技能,核心方法论是**五视角对抗性扫描法**。
|
||||
独立的代码评审技能,核心方法论是**六视角对抗性扫描法**(五个传统安全/健壮性视角 + Karpathy Scope 审计视角)。
|
||||
|
||||
**适用场景**:
|
||||
- `/req cr [REQ-ID]` — 需求流程中的代码评审阶段
|
||||
@@ -22,7 +22,7 @@ description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码
|
||||
|
||||
| 上游 | 本技能输入 | 本技能输出 | 下游 |
|
||||
|------|-----------|-----------|------|
|
||||
| dev-coding | PR diff + 开发设计文档 | CR 报告(五视角扫描 + 发现汇总 + 结论) | dev-test |
|
||||
| dev-coding | PR diff + 开发设计文档 | CR 报告(六视角扫描 + 发现汇总 + 结论) | dev-test |
|
||||
|
||||
---
|
||||
|
||||
@@ -67,7 +67,7 @@ description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码
|
||||
|
||||
---
|
||||
|
||||
## 五视角对抗性扫描法
|
||||
## 六视角对抗性扫描法
|
||||
|
||||
### 总览
|
||||
|
||||
@@ -146,6 +146,28 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
|
||||
- [ ] Redis 不可用时是否有降级方案?(缓存穿透到数据库)
|
||||
- [ ] token 过期/刷新逻辑是否正确?(access vs refresh 不同策略)
|
||||
|
||||
### 视角6:Scope 审计者(Karpathy: Simplicity + Surgical)
|
||||
|
||||
**思维模式**:每一行变更,需求有没有要求它?
|
||||
|
||||
> "Touch only what you must. Clean up only your own mess."
|
||||
> "Every changed line should trace directly to the user's request."
|
||||
|
||||
扫描清单:
|
||||
- [ ] diff 中变更的**每个文件**,是否都在 req-design 变更文件清单中?(超出清单 = 疑似顺手重构)
|
||||
- [ ] 新增的函数/方法/结构体,每个都有对应 AC 需要它?
|
||||
- [ ] 是否引入了"未来可能用到"的参数、配置项、可选字段、接口抽象?
|
||||
- [ ] 是否修改了本次 AC 无关的注释、格式、变量名、import 顺序?
|
||||
- [ ] 代码量是否合理?实现简单 AC 超过 200 行须说明必要性
|
||||
("If you write 200 lines and it could be 50, rewrite it")
|
||||
- [ ] 错误处理是否只覆盖真实会发生的场景?不为不可能的情况写防御代码
|
||||
|
||||
**典型发现示例**:
|
||||
```
|
||||
backend/services/user_service.go:45 — 新增了 WithRetry 参数,但 AC 中无重试需求。
|
||||
建议:移除该参数,AC 有需要时再添加。严重度:Low
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CR 报告模板
|
||||
@@ -160,7 +182,7 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
|
||||
### 变更概要
|
||||
{1-3 句描述本次变更的目的和范围}
|
||||
|
||||
### 五视角扫描结果
|
||||
### 六视角扫描结果
|
||||
|
||||
#### 1. 攻击者视角
|
||||
{扫描发现,或 "未发现问题"}
|
||||
@@ -177,6 +199,9 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
|
||||
#### 5. 依赖者视角
|
||||
{扫描发现,或 "未发现问题"}
|
||||
|
||||
#### 6. Scope 审计者视角(Karpathy)
|
||||
{扫描发现,或 "所有变更文件均在设计清单范围内,无过度实现"}
|
||||
|
||||
### 审查发现汇总
|
||||
|
||||
| # | 严重度 | 文件:行号 | ���角 | 描述 | 建议 |
|
||||
@@ -221,7 +246,7 @@ file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
|
||||
| 文档存在 | CR 任务有附加文档 |
|
||||
| 字数 | ≥ 500 字 |
|
||||
| 代码引用 | 含 `file:line` 格式的引用 |
|
||||
| 五视角扫描 | 含全部 5 个视角章节 |
|
||||
| 六视角扫描 | 含全部 6 个视角章节(含 Scope 审计者) |
|
||||
| 结论章节 | 含明确的通过/不通过结论 |
|
||||
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"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",
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
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>
|
||||
arguments: "[component|page|storybook] <description>"
|
||||
---
|
||||
|
||||
# Frontend Design 前端设计技能
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "karpathy-guidelines",
|
||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "karpathy-guidelines",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: karpathy-guidelines
|
||||
description: Karpathy 四原则编码行为守则。减少 LLM 常见编码错误:过度实现、静默假设、顺手重构、无验证标准。在任意编码场景激活。
|
||||
---
|
||||
|
||||
# Karpathy Guidelines Skill
|
||||
|
||||
> 来源:[andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills)
|
||||
> 在本项目中已深度融合到 req 技能工作流各阶段。
|
||||
|
||||
## 四原则
|
||||
|
||||
### 1. Think Before Coding(编前推理)
|
||||
> "Don't assume. Don't hide confusion. Surface tradeoffs."
|
||||
|
||||
**在写第一行代码前:**
|
||||
- 显式列出本次实现的假设(数据格式、边界条件、依赖接口)
|
||||
- 如存在多种解读,列出所有方案(附估算),不要静默选择
|
||||
- 如有更简单的实现方式,说出来
|
||||
- 遇到不清晰的地方,停下来,指出混乱点,提问
|
||||
|
||||
**在 req 工作流中:** → 已嵌入 `req-prd` 的「Phase 0 假设倾倒协议」
|
||||
|
||||
---
|
||||
|
||||
### 2. Simplicity First(简单优先)
|
||||
> "Minimum code that solves the problem. Nothing speculative."
|
||||
|
||||
**禁止:**
|
||||
- 添加未被需求要求的功能
|
||||
- 为单次使用的代码添加抽象
|
||||
- 添加未被请求的"灵活性"或"可配置性"
|
||||
- 为不可能发生的场景写错误处理
|
||||
- 写了 200 行但 50 行就够的代码 → 重写
|
||||
|
||||
**自检:** "一个高级工程师看这段代码会觉得过度设计吗?" 如果是 → 简化
|
||||
|
||||
**在 req 工作流中:** → 已嵌入 `req-design` 过度设计检查 + `dev-review` 第六视角
|
||||
|
||||
---
|
||||
|
||||
### 3. Surgical Changes(手术式修改)
|
||||
> "Touch only what you must. Clean up only your own mess."
|
||||
|
||||
**修改现有代码时:**
|
||||
- 不要"顺手改进"相邻代码、注释或格式
|
||||
- 不要重构没有损坏的代码
|
||||
- 匹配现有代码风格,即使你会做不同的选择
|
||||
- 发现不相关的死代码 → 提及但不删除
|
||||
|
||||
**你的变更造成的孤儿:**
|
||||
- 删除你的变更导致的无用 import/变量/函数
|
||||
- 不要删除已存在的死代码(除非被要求)
|
||||
|
||||
**铁律:** diff 中每一行修改都应该可以追溯到用户的需求
|
||||
|
||||
**在 req 工作流中:** → 已嵌入 `dev-review` 第六视角 + `check-surgical.sh` Harness 脚本
|
||||
|
||||
---
|
||||
|
||||
### 4. Goal-Driven Execution(目标驱动执行)
|
||||
> "Define success criteria. Loop until verified."
|
||||
|
||||
**将请求转化为可验证目标:**
|
||||
- "加验证" → "为无效输入写测试,然后让它通过"
|
||||
- "修 bug" → "写一个复现 bug 的测试,然后让它通过"
|
||||
- "重构 X" → "确保测试在重构前后都通过"
|
||||
|
||||
**多步任务需要说明计划:**
|
||||
```
|
||||
1. [步骤] → 验证: [检查项]
|
||||
2. [步骤] → 验证: [检查项]
|
||||
3. [步骤] → 验证: [检查项]
|
||||
```
|
||||
|
||||
**在 req 工作流中:** → 已嵌入 `dev-coding` 的「Step 0 验证优先」+ VP 三件套协议
|
||||
|
||||
---
|
||||
|
||||
## 与 req 工作流的映射
|
||||
|
||||
| 原则 | 生效阶段 | 落地机制 |
|
||||
|------|---------|---------|
|
||||
| Think Before Coding | req-prd 启动前 | Phase 0 假设倾倒协议 |
|
||||
| Simplicity First | req-design + dev-review | 过度设计检查 + 第六视角 |
|
||||
| Surgical Changes | dev-review + CI | 第六视角 + check-surgical.sh |
|
||||
| Goal-Driven Execution | dev-coding | Step 0 验证优先 + VP 三件套 |
|
||||
|
||||
## 反模式速查
|
||||
|
||||
| 场景 | ❌ LLM 常犯 | ✅ 正确做法 |
|
||||
|------|-----------|-----------|
|
||||
| "做个导出功能" | 静默假设格式/字段,直接实现 | 列出3种解读,等用户确认 |
|
||||
| "让搜索更快" | 同时加缓存+索引+async | 列出3种"更快"含义,确认再做 |
|
||||
| "加折扣计算" | Strategy+Abstract+Enum,50行 | 一个函数,3行 |
|
||||
| "修空邮件bug" | 顺手加用户名校验+类型注解 | 只改空邮件的那2行 |
|
||||
| "修认证bug" | 直接修改,无验证标准 | 先写复现测试,修复后验证通过 |
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "review-checklist-plugin",
|
||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# 通用代码评审检查清单
|
||||
|
||||
适用于所有项目,补充五视角扫描法。
|
||||
|
||||
## API 设计
|
||||
- [ ] RESTful 命名是否规范?(复数名词、无动词)
|
||||
- [ ] 分页参数是否有默认值和上限?
|
||||
- [ ] 响应格式是否统一?(code/message/data)
|
||||
|
||||
## 错误处理
|
||||
- [ ] 错误是否被正确传播?(不要吞掉错误)
|
||||
- [ ] 用户可见的错误消息是否友好?(不暴露技术细节)
|
||||
- [ ] 是否有 panic recover 兜底?
|
||||
|
||||
## 性能
|
||||
- [ ] 列表查询是否有分页?(不允许无限制查询)
|
||||
- [ ] N+1 查询问题?(循环内查数据库)
|
||||
- [ ] 是否有不必要的全表扫描?(缺少索引)
|
||||
|
||||
## 可维护性
|
||||
- [ ] 魔法数字是否提取为常量?
|
||||
- [ ] 复杂业务逻辑是否有注释说明?
|
||||
- [ ] 函数是否过长?(超过 100 行考虑拆分)
|
||||
@@ -13,16 +13,17 @@ description: 项目级代码评审检查清单。按项目积累特定检查项
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. `dev-review` 执行五视角扫描时,自动加载当前项目的检查清单
|
||||
2. 扫描完成后,逐条检查清单项
|
||||
3. 检查结果附加到 CR 报告的「项目检查清单」章节
|
||||
1. `dev-review` 执行五视角扫描时,先读取 `references/general.md`
|
||||
2. 如果仓库是 AI-Proj,读取 `references/ai-proj.md`;如果是 Coolbuy PaaS,读取 `references/coolbuy-paas.md`
|
||||
3. 扫描完成后,逐条检查适用的清单项
|
||||
4. 检查结果附加到 CR 报告的「项目检查清单」章节
|
||||
|
||||
## 检查清单文件
|
||||
|
||||
```
|
||||
review-checklist-plugin/
|
||||
├── skills/SKILL.md # 本文件
|
||||
└── checklists/
|
||||
review-checklist/
|
||||
├── SKILL.md # 本文件
|
||||
└── references/
|
||||
├── ai-proj.md # AI-Proj 项目清单
|
||||
├── coolbuy-paas.md # 酷采3.0 项目清单
|
||||
└── general.md # 通用清单(所有项目适用)
|
||||
@@ -32,7 +33,7 @@ review-checklist-plugin/
|
||||
|
||||
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
|
||||
|
||||
1. 打开对应项目的检查清单文件
|
||||
1. 打开 `references/` 中对应项目的检查清单文件
|
||||
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
|
||||
3. 标注严重度和适用范围
|
||||
|
||||
|
||||
+9
-1
@@ -18,6 +18,14 @@
|
||||
- [ ] JWT token 类型是否区分 access/refresh?— 教训:token 混用导致安全漏洞
|
||||
- [ ] bcrypt cost 是否使用 12?— 教训:默认 cost 10 导致登录失败
|
||||
|
||||
### 租户隔离(多企业安全,源自 REQ-20260711-0004)
|
||||
- [ ] 隔离/权限类修复是否枚举了威胁模型的**所有读取面**?— list 枚举 + 单条直读 + 按 ID/pattern 查 + count + 关联子查询。教训:P1 只修 list 面漏了 find_task/get-by-id 直读面,直读即绕过枚举防护,audit 才逮到高危残留
|
||||
- [ ] 同一威胁在**镜像面**是否一并处理?— 一个对象类型(task)漏,同类(project/document/manual/history)大概率同漏
|
||||
- [ ] MCP 裸 SQL(不走仓储层)是否应用 `ResolveTenantScope` / scope 片段?— SSE 面 list_tasks/list_projects 曾裸 SQL 无企业过滤
|
||||
- [ ] context 注入的是**类型化 key**(`EnterpriseIDContextKey{}`)而非字符串 key?— 字符串 key 与 `ResolveTenantScope` 读的类型化 key 不通,静默失效
|
||||
- [ ] scope 解析不出 / 依赖为 nil 时是否 **fail-closed**(空哨兵拒绝)而非跳过(退化全量)?
|
||||
- [ ] MCP endpoint 参数是否 snake_case + camelCase 双绑?— CLI 发 snake、bridge 发 camel,gin 静默忽略不匹配参数(REQ-20260711-0003)
|
||||
|
||||
### Redis
|
||||
- [ ] Redis key 是否有 TTL?— 缺少 TTL 导致内存泄露
|
||||
- [ ] Redis 不可用时是否降级到数据库?
|
||||
@@ -37,6 +45,6 @@
|
||||
|
||||
## 通用
|
||||
|
||||
- [ ] `.env` ��凭据文件是否被意外加入 git?
|
||||
- [ ] `.env` 等凭据文件是否被意外加入 git?
|
||||
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
|
||||
- [ ] 错误日志是否包含足够的上下文信息?(user_id, tenant_id, request_id)
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
### 数据迁移
|
||||
- [ ] 从酷采2.0迁移的字段映射是否正确?(varchar ID → bigint ID)
|
||||
- [ ] 迁移脚本是否处理了酷采2.0���软删除标记(is_delete → deleted_at)?
|
||||
- [ ] 迁移脚本是否处理了酷采2.0 的软删除标记(is_delete → deleted_at)?
|
||||
|
||||
## 前端(Vue 3 + Ant Design Vue)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# 通用代码评审检查清单
|
||||
|
||||
每次代码审查都应加载本清单。
|
||||
|
||||
适用于所有项目,补充六视角扫描法(五传统视角 + Karpathy Scope 视角)。
|
||||
|
||||
## Karpathy 反模式速查(Scope 审计者视角辅助)
|
||||
|
||||
基于 [andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) EXAMPLES.md 提炼。
|
||||
|
||||
### ❌ 反模式 → ✅ 正确做法
|
||||
|
||||
| 场景 | 反模式(LLM 常犯) | 正确做法 |
|
||||
|------|-----------------|---------|
|
||||
| "做个导出功能" | 静默假设文件格式/字段/分页,直接实现 | 列出3种解读(API/文件/任务队列),问用户选哪种 |
|
||||
| "让搜索更快" | 同时加缓存+索引+async,200行 | 列出3种"更快"含义+估算,等确认再做 |
|
||||
| "加个折扣计算" | Strategy+Abstract+Enum+DataClass,50行 | `def calc_discount(amount, pct): return amount * pct / 100` |
|
||||
| "修保存偏好的bug" | 顺手加 merge/validate/notify/cache | 只改最小范围,加注释"其他特性按需再加" |
|
||||
| "修空邮件校验bug" | 顺手加用户名校验+类型注解+docstring | 只改空邮件的那2行 |
|
||||
| "加日志到上传函数" | 改引号风格+加类型注解+重构return逻辑 | 只加日志,保持原有代码风格 |
|
||||
| "修认证bug" | "我会检查代码并做改进"(无标准) | 先写测试复现bug,再实现修复,再跑测试 |
|
||||
| "加限流" | 一次提交Redis+多策略+配置系统+监控 | 分4步,每步独立可验证可部署 |
|
||||
|
||||
### 触发关键词(出现时加强 Scope 审计)
|
||||
|
||||
`export/导出` `faster/更快` `manage/管理` `notify/通知` `fix/修复` `improve/改进` `refactor/重构` `add/添加`
|
||||
|
||||
## API 设计
|
||||
- [ ] RESTful 命名是否规范?(复数名词、无动词)
|
||||
- [ ] 分页参数是否有默认值和上限?
|
||||
- [ ] 响应格式是否统一?(code/message/data)
|
||||
|
||||
## 错误处理
|
||||
- [ ] 错误是否被正确传播?(不要吞掉错误)
|
||||
- [ ] 用户可见的错误消息是否友好?(不暴露技术细节)
|
||||
- [ ] 是否有 panic recover 兜底?
|
||||
|
||||
## 性能
|
||||
- [ ] 列表查询是否有分页?(不允许无限制查询)
|
||||
- [ ] N+1 查询问题?(循环内查数据库)
|
||||
- [ ] 是否有不必要的全表扫描?(缺少索引)
|
||||
|
||||
## 可维护性
|
||||
- [ ] 魔法数字是否提取为常量?
|
||||
- [ ] 复杂业务逻辑是否有注释说明?
|
||||
- [ ] 函数是否过长?(超过 100 行考虑拆分)
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "slark-cicd-plugin",
|
||||
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "slark-cicd",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
name: slark-cicd
|
||||
description: Slark 仓库 staging、生产和 Desktop 安装包的端到端 CI/CD 可执行 runbook。覆盖本地预推快检、PR 与内网 ci/internal-gate 门禁、合并 origin/main、生产前强制 staging 验收、审批式生产发布,以及在 m5max 构建签名、公证并上传 macOS/Windows Desktop 包到 OSS。当用户要在 slark(qiudl/qiu-slark)里发布/上线、部署到生产或 staging、发布 Desktop 安装包、盯 CI/合并 PR、复现或验证运行时行为、或排查发布链/推送路由问题时使用。
|
||||
---
|
||||
|
||||
# Slark CI/CD runbook
|
||||
|
||||
驱动 Slark 从改代码到上线的端到端流程。权威流程与完整细节见仓库文档
|
||||
`docs/cicd-staging-production.md`(本技能命令与之一致);本文件是可直接照做的分阶段清单。
|
||||
|
||||
仓库:`qiudl/qiu-slark`(本机克隆通常在 `/Users/donglinlai/coding/slark`)。所有命令在**仓库根**执行。
|
||||
`ai-proj` 相关命令加 `GODEBUG=netdns=go` 前缀。
|
||||
|
||||
## 铁律(先记死)
|
||||
|
||||
- GitHub `origin/main` 是唯一代码权威、合并入口与生产发布来源;`internal` 只用于 CI/镜像,永不发布。
|
||||
- 生产发布只接受**最新 `origin/main` 的精确 40 位 SHA**;`HEAD != origin/main` 会被 `deploy.sh` 拒绝。
|
||||
- 生产发布必须在**普通 clone** 中执行,且 `.git` 必须是目录;`release-prod.sh` / `deploy.sh` 会拒绝
|
||||
`.git` 为指针文件的 git worktree。不要污染现有 checkout:主目录脏或被占用时,新建干净的临时 clone。
|
||||
- **生产发布前必须先发布并验收 staging,不得跳过**:同一最新 `origin/main` 精确 SHA 必须先完成迁移演练、
|
||||
staging 正式部署、隔离检查和需求功能验收。把证据报告给用户后,必须再次取得明确的生产确认;开始 staging
|
||||
前获得的生产授权不能替代这次确认。未通过、未完成或用户未确认时停止,不得执行生产发布命令。
|
||||
- 审批式部署,永不自动:亲手敲的 `sudo`/`rm -rf`/`dd`/`curl|sh`/包安装是 `destructive`(NEVER_AUTO),
|
||||
**每次都要人审**;命中审批闸就**等人批**,绝不绕过、绝不把这些 key 加进 auto-approve 白名单。
|
||||
- staging 与生产硬隔离:staging 脚本带生产 IP 拒运行护栏、不 push origin、不反向 rsync。
|
||||
- 当前 Slark staging 权威目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`
|
||||
(Name=`slark-staging`,2026-08-18 核验公网 IP `15.135.112.181`)。公网 IP 自动分配,发布前必须按
|
||||
实例 ID 重查并确认 Name/状态;不得凭历史 IP 判断目标。
|
||||
- `82.157.141.202` 是 ai-proj 预生产宿主机。其 `/opt/slark-staging` cohost 是隔离的 Slark 兼容验收栈,
|
||||
但不是 Slark 独立预生产;只有任务明确指定 cohost 时才能使用,不得作为普通 Slark staging 的默认目标。
|
||||
- staging 发布若影响 `packages/daemon`、`packages/runtime`、Server/daemon 公共协议或 Desktop 公共运行链,
|
||||
必须把 `server-staging` 与 `daemon-staging` 更新到同一精确 SHA;两者版本不一致不得宣告 staging 成功。
|
||||
- 只修 PR 范围内的 CI 失败;不为过检去改 CI/workflow 或做无关改动。
|
||||
|
||||
## 选择链路
|
||||
|
||||
- 「发布/上线/部署生产」→ 生产发布链:阶段 1→2→3(同 SHA staging 验收)→ 人工确认 →4→5。
|
||||
- 「Desktop/桌面版打包、发布、上传 OSS」→ 阶段 1→2 后走 `docs/desktop-oss-release.md` 的 m5max 双平台链路。
|
||||
- 「盯 CI/合并 PR」→ 阶段 1→2(用 babysit 心态循环到 green + mergeable + 评论收口)。
|
||||
- 「复现/验证运行时行为、别碰生产」→ staging 预验链(阶段 3,可独立随时跑)。
|
||||
|
||||
## 阶段 1:PR 与内网 gate(`ci/internal-gate`)
|
||||
|
||||
真实门禁是内网 CI(GitHub Actions 已停用)。检查与自查:
|
||||
|
||||
```bash
|
||||
gh pr checks <PR> # 应见 ci/internal-gate
|
||||
gh pr view <PR> --json state,mergeable,mergeStateStatus,isDraft,reviewDecision
|
||||
```
|
||||
|
||||
- 基础门(全 PR):release-contract / member-gate / authz-matrix / controlled-content-exits /
|
||||
onconflict-predicate / migration-idempotency / wsl-path-translation / typecheck / test(全量)。
|
||||
- 条件外部门(按改动路径):改 server DB/迁移/schema → `postgresql-security`;改 web → `web-e2e`;
|
||||
android / daemon+desktop 各有门。
|
||||
- 本地复跑基础门可跑部分:`pnpm -r typecheck && pnpm test`。
|
||||
|
||||
红了:只修本 PR 范围内的失败。疑似无关的合并阻塞→先 merge 最新 `main`(可能别的 PR 已修)。
|
||||
`BLOCKED: <label> requires <VAR>` = runner 环境未配外部门命令,属运维问题,不是 PR 代码问题。
|
||||
|
||||
## 阶段 2:合并到 `origin/main`
|
||||
|
||||
合并前确认:`mergeable=MERGEABLE`、`mergeStateStatus=CLEAN`、非 draft、`ci/internal-gate` 绿、评论收口。
|
||||
|
||||
```bash
|
||||
gh pr merge <PR> --merge # 仓库风格:merge commit
|
||||
```
|
||||
|
||||
若本机 `main` 被其他 worktree 占用导致 `--delete-branch` 本地 checkout 失败(属本地副作用):
|
||||
|
||||
```bash
|
||||
gh pr view <PR> --json state,mergedAt,mergeCommit # 确认 GitHub 侧 MERGED
|
||||
git push origin --delete <feature-branch> # 删远端
|
||||
git branch -D <feature-branch> # 删本地(先切走)
|
||||
```
|
||||
|
||||
## 阶段 3:staging 真机预验(生产前强制,也可独立运行)
|
||||
|
||||
生产候选必须使用最新 `origin/main` 的同一精确 SHA。先执行迁移演练,再正式部署;随后完成隔离检查和本次需求的
|
||||
功能验收。验收不能只看通用 health:凡需求涉及真实集成(如飞书 OAuth),staging 缺少对应 provider/凭据时必须
|
||||
明确标为未完成并停止生产链,除非用户在看到该限制后明确接受。完成后报告目标实例、SHA、Server/Daemon revision、
|
||||
迁移演练、健康、隔离和功能结果,并等待用户再次确认是否进入生产。
|
||||
|
||||
### 3.1 当前权威路径:Slark 独立 staging
|
||||
|
||||
稳定目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`(Name=`slark-staging`)。它使用自动分配
|
||||
公网 IP,因此每次部署前先查询当前 IP;2026-08-18 核验值为 `15.135.112.181`:
|
||||
|
||||
```bash
|
||||
aws ec2 describe-instances --region ap-southeast-2 \
|
||||
--instance-ids i-013e5ca3fdfddc13e \
|
||||
--query 'Reservations[0].Instances[0].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name,PublicIp:PublicIpAddress}' \
|
||||
--output table
|
||||
|
||||
export STAGING_SSH_KEY=~/.ssh/cloud-server-syd.pem
|
||||
export STAGING_REMOTE=ubuntu@15.135.112.181
|
||||
export STAGING_REMOTE_IP=15.135.112.181
|
||||
export STAGING_BASE=http://15.135.112.181
|
||||
|
||||
scripts/deploy-staging.sh --migrate-dry-run
|
||||
scripts/deploy-staging.sh
|
||||
STAGING_TOKEN=$(cat /tmp/.staging_token) scripts/staging-seed.sh
|
||||
scripts/staging-verify-isolation.sh
|
||||
```
|
||||
|
||||
不得把查询到的 Name 非 `slark-staging` 的机器当作目标。四件套细节与环境隔离约束见
|
||||
`docs/req-20260811-0059-staging-environment-design.md`。
|
||||
|
||||
### 3.2 非权威路径:ai-proj cohost(仅明确指定时)
|
||||
|
||||
ai-proj cohost 位于 `ubuntu@82.157.141.202:/opt/slark-staging`。全程使用隔离数据、数据库、密钥和状态目录,
|
||||
但宿主机身份仍是 ai-proj staging;普通“Slark 预生产”不得走这里。仅在任务明确要求 cohost 兼容验收时,
|
||||
先在**干净的独立 worktree**检出待验精确 SHA,再执行:
|
||||
|
||||
```bash
|
||||
STAGING_SSH_KEY=~/.ssh/ai_proj_stg.pem \
|
||||
STAGING_KNOWN_HOSTS_FILE=~/.ssh/known_hosts \
|
||||
STAGING_REMOTE=ubuntu@82.157.141.202 \
|
||||
STAGING_REMOTE_IP=82.157.141.202 \
|
||||
scripts/deploy-staging-cohost.sh
|
||||
```
|
||||
|
||||
如果改动影响 daemon/runtime/公共协议,还需用 Compose `daemon` profile 更新 `daemon-staging`,并核对
|
||||
Server/daemon revision 同为待验 SHA。
|
||||
|
||||
### 3.3 环境选择检查
|
||||
|
||||
普通 Slark staging 默认走 3.1;只有用户或需求明确说“ai-proj cohost”才走 3.2。任何验收都必须记录:
|
||||
环境稳定身份、当次 IP、待验 40 位 SHA、Server/daemon revision/status、Server health 和目标功能结果。
|
||||
|
||||
routed-remote 要 `network=enabled` 必须同时满足:① agent `workspace_access=write` +
|
||||
`repository_access=write`;② per-agent 工作区是可写 git worktree。细节见
|
||||
`docs/req-20260811-0059-staging-environment-design.md`。staging 刻意不碰 `deploy.sh` 的生产闸门。
|
||||
|
||||
## 阶段 4:生产发布(审批式)
|
||||
|
||||
**前置门禁**:阶段 3 已对同一 SHA 完成 staging 部署和验收,证据已报告,且用户在报告之后明确确认生产发布。
|
||||
缺任一项即停止;不得把 PR 合并授权、较早的生产授权或单纯的“继续”视为验收后确认。
|
||||
|
||||
**唯一姿势**:从干净的普通 clone 发布最新 `origin/main`(`HEAD == origin/main` 精确 SHA)。staging 可用
|
||||
独立 worktree,但生产脚本为保证同步与发布边界,会拒绝 worktree;不要在用户已有脏 checkout 中清理或发布。
|
||||
|
||||
```bash
|
||||
# 若当前仓库不是普通 clone,先在安全父目录创建一次性干净 clone:
|
||||
git clone https://github.com/qiudl/qiu-slark.git <clean-production-clone>
|
||||
cd <clean-production-clone>
|
||||
|
||||
git fetch origin main
|
||||
test -d .git # 必须通过;worktree 的 .git 是文件
|
||||
git status --porcelain # 必须干净
|
||||
git checkout --detach "$(git rev-parse origin/main)" # 在产品分支上时先 detach 到该 SHA
|
||||
|
||||
pnpm release:prod # = release-prod.sh → deploy.sh --backend --no-install --no-mirror
|
||||
# 备选:scripts/deploy.sh --pull --backend
|
||||
```
|
||||
|
||||
- `deploy.sh` 用 `check-production-release-sha.sh` 锁 `HEAD == origin/main` SHA,不符即拒。
|
||||
- `--backend` 才跑迁移:owner 连接(DDL 权)与运行时 `slark_app`(DML-only)分离;幂等、失败即非零。
|
||||
- 命中审批闸(发布/sudo)→ **等人批**;不要绕。脚本内部 SSH 载荷子进程的 sudo 不触发闸。
|
||||
- 普通工作 clone 发布完切回原分支:`git checkout <branch>`;一次性发布 clone 可保留作审计,清理时用可恢复方式。
|
||||
|
||||
### HANDOFF_BLOCKED 恢复入口
|
||||
|
||||
发布准备遇到 `HANDOFF_BLOCKED`、handoff manifest=`failed_closed` 或命令状态不确定时,停止发布切换;禁止靠重跑
|
||||
发布脚本、直接改表或默认 replay 来“解卡”。先把 manifest、命令、execution、lease/outbox 和审计证据做只读盘点,
|
||||
再让用户明确授权每条记录的 reconciliation action/outcome 及是否允许继续发布。恢复细节见
|
||||
[references/production-handoff-recovery.md](references/production-handoff-recovery.md);仅遇到该类事故时读取。
|
||||
|
||||
`COMMAND_AUTHORITY_CHANGED` 是有效并发护栏,不是可忽略错误:重新读取当前 authority/transport/execution generation,
|
||||
确认期间没有新活动,再在原授权范围内幂等续办。若发现新工作、活跃 lease/outbox 或无法解释的副作用,立即停止并
|
||||
重新请求决策。
|
||||
|
||||
## 阶段 5:发布后核查
|
||||
|
||||
```bash
|
||||
scripts/verify-deploy.sh # 健康(前端/api/health=200)、bundle、server/daemon SHA、迁移集、federation、凭据
|
||||
```
|
||||
|
||||
预期 `✓ deploy verification passed: server=<sha> daemon=<sha>` 且 `<sha> == origin/main`,舰队 `online ≥ 发布前`。
|
||||
完成前还要独立复核 governed release 账本为 `succeeded/complete`、四组件实际 SHA 均为目标 SHA、租约已释放、
|
||||
新 handoff manifest=`verified`;若本次处理过旧 manifest,还要核对其全部 case 已达授权终态且 replay 数为 0。
|
||||
|
||||
默认生产包装器使用 `--no-mirror`:构建 daemon candidate binary 用于运行态验证不等于上传镜像资产。镜像落后告警
|
||||
在该模式下是预期的非阻断结果;不得未经单独授权补传镜像。交付说明要明确国内安装器可能回退 upstream,避免把
|
||||
本地构建、生产 daemon 更新和镜像上传混为一谈。
|
||||
|
||||
## Desktop m5max 双平台发布
|
||||
|
||||
Desktop 安装包不走 Server 生产部署脚本。权威流程见仓库 `docs/desktop-oss-release.md`,已验证基线为
|
||||
REQ-20260819-0005 / Desktop 0.3.1:
|
||||
|
||||
- 版本 PR 通过 `ci/internal-gate` 并合并后,m5max 从最新 `origin/main` 精确 SHA 的干净普通 clone 构建。
|
||||
- m5max 原生构建、Developer ID 签名并公证/staple macOS DMG/ZIP;交叉构建 Windows x64 NSIS EXE。
|
||||
- Darwin 不能执行 Windows 原生 `smoke:windows`。只有发布负责人明确接手 Windows 原生验收时才能继续交叉打包,交付证据必须标注该边界。
|
||||
- 资产不回传开发机;由 m5max 直接上传 `xiaoqu-public-file/slark/desktop/releases/v<version>/`,manifest 最后更新。
|
||||
- `xiaoqu-public-file` 的 canonical 凭证源是发布控制机上的 `/Users/donglinlai/coding/param.rxt`(必须为 `0600`);AK/SK 分别位于 XML 标签 `ossAccessKeyId` / `ossAccessKeySecret`。不得改猜 Bitwarden、Keychain、通用 `credentials.env` 或 m5max 本地配置;只有该文件缺失、权限不符或标签解析为空时才停止并报告。
|
||||
- m5max 不持久化 OSS 凭证。发布控制机从 `param.rxt` 提取 AK/SK 后,只用 `printf '%s\n%s\n' ... | ssh m5max ...` 经 SSH stdin 传两行;远端用 `read -r` 接收并仅为当次 shell 导出 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`,随后运行上传脚本。禁止 `scp` 凭证文件、写远端临时文件或把值打印到日志。
|
||||
- m5max 非交互 SSH 必须显式补 `PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH`;已验证 `ossutil` 位于 `/Users/johnq/.local/bin/ossutil`。执行前检查 Node、三个安装包、精确 main SHA 和干净工作树,避免因交互 shell 环境差异重新猜路径。
|
||||
- m5max 默认出口若走 `utun`,只为当次 `ossutil` 使用 `--bind-address "$(ipconfig getifaddr en0)"`,不得修改整机 Tailscale/默认路由。
|
||||
- 完成前核对三份资产 SHA256/大小、macOS 签名与公证、公开 URL/manifest,并回写 ai-proj 证据。
|
||||
|
||||
## 推送路由自查(换机器/新克隆必做)
|
||||
|
||||
```bash
|
||||
git remote -v # origin 收发都应是 https://github.com/qiudl/qiu-slark.git
|
||||
git config --get-regexp '^url\.' # 有输出 = pushInsteadOf 改写,push 可能被静默重定向到内网
|
||||
scripts/git-release-governance.sh check-local
|
||||
scripts/git-release-governance.sh status
|
||||
```
|
||||
|
||||
## 故障分流
|
||||
|
||||
| 现象 | 处置 |
|
||||
| --- | --- |
|
||||
| `release-prod` 拒绝 HEAD≠origin/main | `git fetch origin main` 后 detach 到 origin/main SHA,工作树须干净 |
|
||||
| `release-prod` 拒绝 git worktree / `.git` 不是目录 | 改用干净的普通 clone,锁定最新 `origin/main`;不要在现有脏 checkout 中强行切换 |
|
||||
| `ci/internal-gate` red | 看 gate 分组日志找 FAIL 项;`pnpm -r typecheck && pnpm test` 本地复现修复 |
|
||||
| `BLOCKED: <label> requires <VAR>` | runner 未配外部门命令,报运维配 `SLARK_CI_*_CMD`,非 PR 问题 |
|
||||
| 合并阻塞但与 PR 无关 | merge 最新 `main` 再看 |
|
||||
| push 成功但 GitHub 没有 | 查 `git config --get-regexp '^url\.'`,移除 pushInsteadOf 或显式指定 GitHub URL |
|
||||
| staging routed-remote 恒断网 | 查两道放网杠杆(workspace_access=write + 可写 git worktree) |
|
||||
| cohost Server 已更新但 daemon 仍是旧 SHA | 用 `--profile daemon up -d daemon-staging` 更新 daemon;核对两容器 revision 后才算完成 |
|
||||
| cohost daemon 启动即退出/fatal | 看 `docker logs slark_daemon_staging`;修复凭据/环境或版本契约,禁止用旧 daemon 冒充验收通过 |
|
||||
| verify 失败 SHA 不符 | 部署到了旧码,重发 |
|
||||
| `HANDOFF_BLOCKED` / manifest=`failed_closed` | 停止切换并读取 handoff recovery 参考;只读盘点后取得逐项 action/outcome 授权,禁止默认 replay |
|
||||
| reconciliation 返回 `COMMAND_AUTHORITY_CHANGED` | 查当前 generation 与新活动;无新活动才在原授权内幂等续办,有变化则停止重新决策 |
|
||||
| `--no-mirror` 后提示镜像落后 | 预期非阻断;报告 upstream fallback,未经单独授权不上传镜像 |
|
||||
| 生产授权已给但 staging 尚未验收 | 先完成同 SHA staging 全量验收,报告证据并重新等用户确认;不得沿用较早授权 |
|
||||
| staging 缺少需求依赖的真实集成配置 | 将对应验收标为未完成并停止生产链;补齐配置后重验,或让用户基于明确限制作决定 |
|
||||
|
||||
## ai-proj 流程(强制)
|
||||
|
||||
任何改产品/代码行为的工作,动手前先在 ai-proj 立项 + 建 Task + 关联,实现/测试/交付回写;
|
||||
commit/PR 引用 `REQ-...`。纯文档/工具/只读排查除外。详见仓库 `AGENTS.md` / `CLAUDE.md`。
|
||||
@@ -0,0 +1,70 @@
|
||||
# Production handoff recovery
|
||||
|
||||
仅在生产发布被 coding-session handoff 阻塞、manifest 进入 `failed_closed`,或存在 `needs_review` / 不确定命令时读取。
|
||||
目标是保留 fail-closed 语义,在明确授权下终结歧义状态,并证明没有误重放命令。
|
||||
|
||||
## 先冻结发布,不先解锁
|
||||
|
||||
- 停止发布切换和自动重试;记录 release ID、候选 SHA、manifest ID、阻塞发生阶段与原始错误。
|
||||
- 不把“继续”“再试一次”解释为 replay、force-end 或生产发布授权。向用户展示证据后,确认语句应绑定 manifest、
|
||||
条目数量或 command ID、目标 action/outcome、是否禁止 replay,以及要继续发布的精确 SHA。
|
||||
- 不直接更新 handoff、command、execution 表来改变状态。优先走已部署版本的内部治理 API;只有 API 无法恢复且
|
||||
已获得对应操作授权时,才可调用该版本现有 domain repository,并保留 lifecycle event 与 audit log。
|
||||
|
||||
## 只读证据盘点
|
||||
|
||||
对 manifest 中每条 item 核对并保存摘要:
|
||||
|
||||
- command ID、session/project/computer ID、command status、execution state;
|
||||
- manifest 记录的 authority term、transport generation、execution generation,以及当前实际值;
|
||||
- command/execution lease 是否过期,outbox 是否仍有 active/pending 记录;
|
||||
- session 中是否还有其他活跃命令或新事件;
|
||||
- daemon acknowledgement、result/receipt、审计事件是否能证明执行或未执行。
|
||||
|
||||
若 lease/outbox 仍活跃、存在新命令、证据相互矛盾,或无法排除外部副作用,停止恢复并请求新的人工判断。
|
||||
|
||||
## Action 与 outcome 必须匹配证据
|
||||
|
||||
- `no_action / not_executed`:只有权威证据能证明命令从未执行,且治理接口允许该组合时使用。
|
||||
- `terminate / terminated`:用于显式受控终结仍处于 uncertain/active 语义的命令;先通过 domain 操作取消 command、
|
||||
force-end execution、完成 session 并写审计,再完成 reconciliation,不产生 replay。
|
||||
- `mark_failed / failed`:证据确认失败、且不能安全恢复为成功或未执行时使用。
|
||||
- `replay / replayed_success`:仅在用户明确授权 replay 且 exactly-once/幂等边界得到证明时使用。发布解卡绝不能默认 replay。
|
||||
|
||||
不要为了迎合预先选择的 outcome 忽略现场证据;如果授权与可证明事实不兼容,停止并把差异报告给用户。
|
||||
|
||||
## 受治理恢复顺序
|
||||
|
||||
1. 使用精确 manifest/item 建立或读取 reconciliation case。
|
||||
2. 取得具备 action、evidence digest、operator 和有效期约束的审批。
|
||||
3. 记录 decision;执行 domain 终结或治理 apply;随后用权威运行态证据 confirm terminal outcome。
|
||||
4. 若 apply 返回 `COMMAND_AUTHORITY_CHANGED`,不要覆盖或绕过。重新读取当前三类 generation 和新活动:
|
||||
- generation 只因刚完成的受控终结而变化,且无新命令、lease/outbox 时,可在同一授权 action 下幂等续办;
|
||||
- generation 对应新工作或原因不明时,停止并重新审批。
|
||||
5. 每个 item 都 terminal 后,确认 manifest 自动或受治理地进入 `reconciled`,再启动新的发布尝试。
|
||||
|
||||
凭据失败发生在事务前时应视为零变更并记录。不要反复猜测 owner 凭据;不得打印连接串或密钥。若必须使用运行时
|
||||
`slark_app` 连接,只能通过已部署 domain repository、正确的 per-transaction project/user RLS context 和审计路径操作。
|
||||
|
||||
## 零重放与发布恢复验收
|
||||
|
||||
恢复完成至少证明:
|
||||
|
||||
- `terminalCount == totalCount`,每条 decision action 与 terminal outcome 等于用户授权;
|
||||
- 禁止 replay 的场景下,decision action=`replay` 数和 execution replay attempt 增量均为 0;
|
||||
- `terminate/terminated` 场景下,command=`cancelled`、execution=`force_ended`,并存在对应 lifecycle/audit 证据;
|
||||
- 旧 manifest=`reconciled`,没有 active handoff reservation 残留。
|
||||
|
||||
继续生产发布时使用新 governed release / handoff manifest,不复用 failed-closed manifest。重新检查候选仍是最新
|
||||
`origin/main`、同 SHA staging eligibility receipt 仍有效、工作树干净;任何一项变化都回到 staging 与人工确认门禁。
|
||||
|
||||
发布成功后再独立执行一次 `scripts/verify-deploy.sh`,并只读核对:release=`succeeded/complete`、target/actual Web、
|
||||
Server、daemon、artifact SHA 全相等、lease 已释放、finished 已记录、新 manifest=`verified`、舰队在线数不低于基线。
|
||||
将旧 manifest reconciliation 与新发布证据一起回写 ai-proj。
|
||||
|
||||
## `--no-mirror` 的解释边界
|
||||
|
||||
- `pnpm release:prod` 默认走 `deploy.sh --backend --no-install --no-mirror`;不上传 daemon 镜像资产。
|
||||
- 发布过程仍可能在隔离 candidate 目录构建 daemon binary,用于同 SHA 验证或部署运行态 daemon;这不是镜像上传。
|
||||
- mirror freshness 告警表示镜像源仍旧,国内安装器可能回退到较慢 upstream。它不阻断当前生产运行态发布。
|
||||
- 补传 mirror 是单独的外部写操作,需要单独授权和凭据;不能为了消除告警在发布收尾时顺手执行。
|
||||
@@ -1,16 +1,10 @@
|
||||
{
|
||||
"name": "doubao-voice-plugin",
|
||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"skills": [
|
||||
{
|
||||
"name": "doubao-voice",
|
||||
"path": "./skills/SKILL.md"
|
||||
}
|
||||
],
|
||||
"install_name": "doubao-voice",
|
||||
"install_type": "skill",
|
||||
"dir_category": "integration"
|
||||
|
||||
@@ -322,6 +322,59 @@ npm run lint
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 既有契约与读模型迁移门禁(必须)
|
||||
|
||||
> **惨痛教训**:新写链路把真实数据写入新表,旧 API 仍读原表,前端虽然没改却从此看不到新数据。“后端已成功执行”不等于“用户能看到执行结果”。
|
||||
|
||||
开发计划涉及新表、新账本、新写路径、替换存储模型或接口版本时,必须先完成以下门禁。未通过时,不得把“新建平行表/新建平行 API”写成默认方案。
|
||||
|
||||
### 1. 先证明旧模型不能复用
|
||||
|
||||
- [ ] 已检查现有表、字段、索引、状态机和扩展字段(如 metadata/JSON)。
|
||||
- [ ] 已说明为什么增加字段、子表或现有类型无法满足需求。
|
||||
- [ ] 新表承载的是真正独立的实体或生命周期,而不是为同一业务实体建立第二个彼此脱节的世界。
|
||||
- [ ] 已区分“内部不可变证据/事件账本”和“产品对外读模型”;新建内部账本不代表必须更换原有产品接口。
|
||||
|
||||
### 2. 真实调用方查证
|
||||
|
||||
必须从对外接口向所有消费方反向追踪,不能只审查新后端写路径:
|
||||
|
||||
- [ ] 列出现有 API 路径、请求参数、响应结构和身份/分页语义。
|
||||
- [ ] 使用 `rg` 查找 Web、iOS、Android、定时任务、报表和第三方调用方。
|
||||
- [ ] 若仓库存在 `.codex-fe-ref/`,必须在其中查证配套前端的真实调用。
|
||||
- [ ] 开发计划的变更文件清单必须覆盖“写入 → 投影/查询 → API → 页面”完整链路。
|
||||
|
||||
### 3. 稳定契约默认不变
|
||||
|
||||
- 既有用户界面已消费的 API,默认保留路径和响应契约;除非用户明确批准破坏性迁移,不得通过新建版本接口把兼容成本转嫁给前端。
|
||||
- 同一业务概念只保留一个产品级读模型。内部账本可以拆分,但必须投影回既有读模型,或由原 API 无感聚合。
|
||||
- 日志、告警、信号或推测数据不得在查询降级时冒充业务事实(例如把 warning 当成交易记录)。
|
||||
|
||||
### 4. 不可避免新写模型时的强制迁移计划
|
||||
|
||||
若确有独立生命周期、不可变审计或 1:N/N:N 证据需求,可以增加新表,但开发计划必须同时包含:
|
||||
|
||||
1. **写入兼容**:双写,或从新账本向既有读模型做事务性/幂等投影。
|
||||
2. **历史回填**:有界、可恢复、可重跑,且不猜测无法证明的归属。
|
||||
3. **去重身份**:定义跨旧/新数据源的稳定业务键,并用数据库唯一约束或等价强保证防重。
|
||||
4. **读取切换**:定义何时以新证据为准、旧数据如何兼容,以及结果数量/金额/状态对账门槛。
|
||||
5. **回滚策略**:回滚新写入时仍能读取已产生的真实业务事实,不删除或隐藏已成功数据。
|
||||
6. **可观测性**:监控新写入成功但旧读模型缺失、投影延迟、去重冲突和回填差异。
|
||||
|
||||
### 5. 用户可见性是必须验收项
|
||||
|
||||
测试不得只证明“新写路径成功”。至少要有一个真实业务记录贯穿测试,同时证明:
|
||||
|
||||
- [ ] 新写路径产生了正确事实。
|
||||
- [ ] 原有对外 API 可以立即或在约定 SLA 内返回该记录。
|
||||
- [ ] 每个真实消费页面/客户端都能正确解码并展示。
|
||||
- [ ] 时间、方向、状态、数量、金额与唯一标识在数据库、API 和 UI 之间一致。
|
||||
- [ ] 部分失败、重试、重复投递、迟到数据和回滚后仍不丢数、不重复、不冒充。
|
||||
|
||||
开发计划必须把上述内容落成明确的变更文件、任务、测试用例和发布门禁,不得只在“风险”章节留一句提醒。
|
||||
|
||||
---
|
||||
|
||||
## 开发计划文档模板
|
||||
|
||||
```markdown
|
||||
@@ -1695,3 +1748,4 @@ migrate -path migrations -database "postgres://..." up
|
||||
|------|------|----------|--------|
|
||||
| V1.0 | 2026-01-26 | 初始版本,创建 req-dev 技能 | Claude + qiudl |
|
||||
| V1.1 | 2026-01-29 | 添加 iOS 端开发规范(SwiftUI + MVVM 架构) | Claude Opus 4.5 |
|
||||
| V1.2 | 2026-08-26 | 新增既有契约与读模型迁移强制门禁,防止新写链路与原 API/前端脱节 | Codex |
|
||||
|
||||
@@ -41,7 +41,8 @@ analysis → design → dev → review → testing → [待部署池] → releas
|
||||
- PRD 文档是提交评审的前置条件;代码评审是测试的前置条件
|
||||
- **force=true 禁止自动使用** — 门禁未通过时必须 AskUserQuestion 确认 + 记录跳过原因
|
||||
- **评审必须用户确认** — 禁止 AI 自审批
|
||||
- **归档前门禁检查** — `/req done` 按需求类型(code/skill/ops)动态检查
|
||||
- **归档前 AC 逐条验收(Gate 0,强制)** — `/req done` 必须先提取需求描述中的验收标准逐条确认,无 AC 或有未确认项均阻断,用户必须提供证据或说明跳过原因
|
||||
- **归档前类型化门禁检查** — Gate 0 通过后,`/req done` 再按需求类型(code/skill/ops)动态检查
|
||||
- **部署是项目级动作**,由 `/req deploy` 统一触发
|
||||
- **需求完成后必须 git 提交并 push** — commit 格式:`feat(skill): REQ-XXXX 需求标题`
|
||||
- **操作前先确认实际 ID** — 从 URL 提取 ID(如 `/requirements/897` → ID=897)
|
||||
@@ -393,6 +394,16 @@ Deploy Gate 3: 证据完整 ── 验收任务有文档,含检查项表格 +
|
||||
9. `ai-proj req advance --id <id> --to released` 批量推进(仅 Gate 1-3 全部通过的需求)
|
||||
|
||||
**`/req done [REQ-ID]`** — 类型化归档门禁 + git commit + push + `ai-proj req archive --id <id>`:
|
||||
|
||||
**Gate 0(强制):AC 验收逐条确认** — 在所有类型检查之前执行:
|
||||
1. `ai-proj req get --id <id>` 获取需求描述
|
||||
2. 提取 `## 验收标准` 章节下的所有 `- [ ]` / `- [x]` 条目
|
||||
3. **无验收标准**:AskUserQuestion 警告并要求用户确认为何无 AC,必须说明跳过原因才能继续
|
||||
4. **有未勾选项(`- [ ]`)**:逐条列出,AskUserQuestion 请用户对每条提供验证证据(截图/curl 输出/日志)或明确标记为 N/A + 说明原因
|
||||
5. **全部已勾选(`- [x]`)**:展示 AC 摘要,直接继续
|
||||
6. AC 确认通过后,将每条 AC 的验证结果追加到需求描述(`ai-proj req update`),格式:`- [x] {原AC内容}(验证于 YYYY-MM-DD)`
|
||||
|
||||
**类型检查(Gate 0 通过后)**:
|
||||
- **推断类型**:有 implementation → code;无 implementation 有 prd/test → skill;仅 deploy → ops
|
||||
- **code 检查**:delivery_stage=released + deploy 任务完成 + verification 任务完成(PDV 通过) + 部署文档 + 所有任务完成
|
||||
- **skill 检查**:delivery_stage≥testing + 所有任务完成
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "req-prd-plugin",
|
||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
||||
"version": "2.0.0",
|
||||
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||
"version": "2.2.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: req-prd
|
||||
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
|
||||
description: 产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。
|
||||
---
|
||||
|
||||
# 产品需求设计 Skill (req-prd)
|
||||
@@ -16,7 +16,66 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
||||
|
||||
**插件扩展**:
|
||||
- `req-compare` — 对比式 PRD 编写(系统平移/竞品借鉴时激活)
|
||||
- `req-prototype` — UI 原型生成
|
||||
- `req-prototype` — UI 模块在 PRD/缺陷收敛后生成、上传并关联 HTML 原型
|
||||
- `defect-analysis` — 设计访谈确认后,对最新版 PRD 反复审计和修订直至收敛
|
||||
|
||||
## 产品需求文档双写门禁
|
||||
|
||||
本技能创建或修改的所有正式需求文档都必须同时保存到:
|
||||
|
||||
1. 当前产品仓库的本地 Markdown 文件;
|
||||
2. Requirement 对应角色任务的 ai-proj Task Document。
|
||||
|
||||
适用文档至少包括原始诉求/讨论记录、PRD、缺陷优化记录、原型版本与评审记录。Requirement description 只保存已确认的讨论摘要,不能替代 Task Document。
|
||||
|
||||
### 路径与任务映射
|
||||
|
||||
优先遵循仓库已有文档目录和命名约定;没有约定时使用:
|
||||
|
||||
| 文档 | 本地默认路径 | ai-proj 任务角色 |
|
||||
|------|--------------|------------------|
|
||||
| 需求讨论记录 | `docs/product/{REQ-ID}-{slug}-discussion.md` | `documentation` |
|
||||
| PRD(含缺陷修订和原型回填) | `docs/product/{REQ-ID}-{slug}-prd.md` | `prd` |
|
||||
|
||||
同一 Requirement、同一角色只维护一个当前任务文档。不得把本地文件路径当成 ai-proj 持久化,也不得只把远程 Task Document 导出一次后继续单边修改。
|
||||
|
||||
### 每次写入协议
|
||||
|
||||
1. 修改前同时读取本地文件与 ai-proj Task Document;任一不存在则基于另一份初始化,二者都不存在才新建空模板;
|
||||
2. 若两份内容不一致,比较文档 ID、版本、更新时间和内容摘要,保留双方未知内容并显式合并;无法安全合并时停止并请用户选择,禁止静默覆盖;
|
||||
3. 先用安全文件编辑方式写入本地 Markdown,再创建或更新对应 Task Document;
|
||||
4. 写后重新读取两端,计算或比较内容摘要,确认正文一致,并记录本地路径、task_id、document_id、version/updated_at;
|
||||
5. 任一端写入或复读失败都属于未完成的部分写入:保留已成功一端用于恢复,立即报告并停止后续阶段,不得宣称“已保存”“已收敛”或提交评审。
|
||||
|
||||
问答每一轮、每次 PRD 修订、每轮 defect 处置和每次原型回填都执行该协议;不能等到流程结束再一次性补传。
|
||||
|
||||
## 模块设计访谈模式
|
||||
|
||||
设计模块、系统、跨域流程,或目标/边界/业务规则尚未确定时,必须先执行问答式设计访谈,不得直接补全假设后生成 PRD。用户明确要求“你问我答”时也进入此模式。范围小、规则已完整确认的需求可以直接编写 PRD。
|
||||
|
||||
进入此模式后,**完整读取并执行** [references/design-interview-and-defect-loop.md](references/design-interview-and-defect-loop.md)。该协议定义:
|
||||
|
||||
- 每轮只问一个会改变方案的关键问题;
|
||||
- 将问题、AI 建议、用户原话、决策和未决项逐轮写入 ai-proj 需求的讨论文档;
|
||||
- 讨论结论经用户确认后,才能创建或更新 PRD;
|
||||
- 使用 `defect-analysis` 对最新版 PRD 执行“审计 → 修订 → 全量重审”循环;
|
||||
- UI 模块在 PRD 收敛后使用 `req-prototype` 生成独立 HTML 原型、上传关联 Requirement、回填 PRD 并完成可访问性与关键状态校验;
|
||||
- 原型评审改变产品行为时,回到问答、PRD 修订和 `defect-analysis` 全量重审,再生成新原型版本;
|
||||
- 讨论文档缺失、写入失败、用户未确认、原型未验证,或仍有未处置的致命/高严重度缺陷时,不得宣称设计完成或提交评审。
|
||||
|
||||
## HTML 原型完成闸门
|
||||
|
||||
模块包含用户界面、用户操作流程或可视状态时,HTML 原型是产品设计交付物,不是评审后的可选补充。默认执行 `/req prototype upload [REQ-ID]`,具体生成、上传、iframe 回填和验证规则由 `req-prototype` 定义。
|
||||
|
||||
必须满足:
|
||||
|
||||
1. 原型基于最新版、已完成缺陷收敛的 PRD,并记录 PRD 文档标识、版本或内容摘要;
|
||||
2. 覆盖核心入口、主流程以及 PRD 明确要求的空态、失败态、无权限态和确认/撤销反馈;
|
||||
3. 将本地 HTML 源文件通过 ai-proj 上传到 OSS;上传后重新读取 Requirement,确认 OSS URL/版本已关联,并验证 URL 可访问、iframe 可展示、核心交互可操作;
|
||||
4. 将 iframe、原型版本、版本说明和验证结果双写到本地 PRD 与 prd 角色 Task Document,并把生成、反馈、修订和确认双写到本地讨论记录与 documentation 任务文档;
|
||||
5. 用户明确确认最终 PRD 与原型表达的是同一方案。
|
||||
|
||||
纯后端、批处理、基础设施等确实没有用户界面的模块可以跳过,但必须在讨论文档和 PRD `4.2` 中记录“无 UI,原型不适用”的理由及用户确认,不得静默省略。
|
||||
|
||||
## 客户原话原则(REQ-20260416-0017 P1-8)
|
||||
|
||||
@@ -108,10 +167,21 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
||||
|
||||
### 4.2 界面原型
|
||||
|
||||
> 使用 `/req prototype [REQ-ID]` 基于 PRD 自动生成 Stitch 原型。
|
||||
> 生成后截图将自动回填到此章节。
|
||||
> UI 模块使用 `/req prototype upload [REQ-ID]` 基于最新版 PRD 生成并上传 HTML 原型。
|
||||
> 原型必须用 iframe 展示;Stitch 可作为视觉探索的可选输入,不能代替最终 HTML 原型闭环。
|
||||
|
||||
[执行 `/req prototype` 后自动填充]
|
||||
**原型基线**:
|
||||
- PRD 文档/版本:...
|
||||
- 原型版本与说明:...
|
||||
- Requirement 关联状态:已验证 | 未验证
|
||||
- 可访问性/关键交互验证:...
|
||||
|
||||
<iframe src="[prototype_url]"
|
||||
width="100%" height="600" frameborder="0"
|
||||
style="border-radius:8px;border:1px solid #e5e7eb;">
|
||||
</iframe>
|
||||
|
||||
[无 UI 模块填写:原型不适用的理由、讨论记录位置和用户确认原话]
|
||||
|
||||
## 5. 技术要求
|
||||
### 5.1 性能要求
|
||||
@@ -361,6 +431,8 @@ mcp__ai-proj__link_tasks_to_requirement
|
||||
|
||||
### 文档管理
|
||||
|
||||
以下 MCP 操作只完成 ai-proj 侧写入;每次调用前后都必须按“产品需求文档双写门禁”同步并校验本地 Markdown。
|
||||
|
||||
```bash
|
||||
# 创建 PRD 文档并关联任务
|
||||
mcp__ai-proj__create-and-attach
|
||||
@@ -378,6 +450,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- taskId: 任务ID
|
||||
```
|
||||
|
||||
导出命令不能代替双写校验:导出后仍需确认目标路径符合仓库约定、正文与 Task Document 当前版本一致,且没有覆盖本地新增内容。
|
||||
|
||||
---
|
||||
|
||||
## 功能设计流程
|
||||
@@ -395,6 +469,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- 需求池(ai-proj 需求列表)
|
||||
```
|
||||
|
||||
若命中“模块设计访谈模式”,本阶段改为执行访谈协议并持续写入 ai-proj 讨论文档;访谈未确认前不进入 PRD 定稿。
|
||||
|
||||
### 2. 需求分析
|
||||
|
||||
```
|
||||
@@ -419,10 +495,44 @@ mcp__ai-proj__export_task_document_to_file
|
||||
|
||||
输出:
|
||||
- PRD 文档
|
||||
- 原型设计
|
||||
- 可生成原型的界面状态与交互规格
|
||||
```
|
||||
|
||||
### 4. 评审验证
|
||||
### 4. 缺陷收敛
|
||||
|
||||
```
|
||||
输入:
|
||||
- 已确认讨论结论
|
||||
- 最新版完整 PRD
|
||||
|
||||
执行:
|
||||
- defect-analysis 全维度审计
|
||||
- 接受项修订 PRD
|
||||
- 对修订后的完整 PRD 重新审计,直至一轮 0 个新缺陷
|
||||
|
||||
输出:
|
||||
- 已收敛 PRD
|
||||
- 缺陷处置记录
|
||||
```
|
||||
|
||||
### 5. HTML 原型与反馈闭环
|
||||
|
||||
```
|
||||
适用:
|
||||
- 所有包含界面、用户操作或可视状态的模块
|
||||
|
||||
执行:
|
||||
- 调用 req-prototype 的 upload 模式生成独立 HTML
|
||||
- 上传并关联 Requirement
|
||||
- iframe 回填 PRD,验证访问和关键交互
|
||||
- 请用户评审;行为性反馈回到问答 → PRD → defect-analysis → 新原型版本
|
||||
|
||||
输出:
|
||||
- 已验证、已关联的 HTML 原型
|
||||
- PRD 与讨论文档中的版本/反馈/确认记录
|
||||
```
|
||||
|
||||
### 6. 评审验证
|
||||
|
||||
```
|
||||
评审维度:
|
||||
@@ -436,6 +546,10 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- 修改意见
|
||||
```
|
||||
|
||||
模块设计访谈模式下,本阶段必须调用 `defect-analysis`,并按访谈协议将每轮发现、处置、PRD 修订和收敛结论回写到同一讨论文档。
|
||||
|
||||
UI 模块还必须核对最终 HTML 原型与最新版 PRD 一致,并取得用户对二者的联合确认;无 UI 模块则核对已记录的不适用理由和用户确认。
|
||||
|
||||
---
|
||||
|
||||
## 竞品分析
|
||||
@@ -480,6 +594,16 @@ mcp__ai-proj__export_task_document_to_file
|
||||
|
||||
### PRD 完整性检查
|
||||
|
||||
- [ ] 模块/系统设计已完成单轮单问访谈,且全过程已写入 ai-proj 讨论文档
|
||||
- [ ] 讨论记录与 PRD 均已保存到仓库本地 Markdown 和对应 ai-proj Task Document
|
||||
- [ ] 两端复读正文一致,交付说明包含本地路径、task/document 标识和远程版本
|
||||
- [ ] 讨论结论已由用户明确确认
|
||||
- [ ] `defect-analysis` 已基于最新版 PRD 收敛到一轮 0 个新缺陷
|
||||
- [ ] 无未处置的致命/高严重度缺陷
|
||||
- [ ] UI 模块 HTML 原型已生成、上传并关联 Requirement;无 UI 模块已记录不适用理由和用户确认
|
||||
- [ ] 原型基线指向最新版 PRD,PRD `4.2` 已回填 iframe、版本说明和验证结果
|
||||
- [ ] 原型反馈导致的行为变更已回到问答、PRD 和 defect 全量重审,并生成新原型版本
|
||||
- [ ] 用户已联合确认最终 PRD 与 HTML 原型
|
||||
- [ ] 背景与目标明确
|
||||
- [ ] 用户群体定义清晰
|
||||
- [ ] 功能需求完整
|
||||
@@ -492,6 +616,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
### 交互设计检查
|
||||
|
||||
- [ ] 用户流程完整
|
||||
- [ ] HTML 原型覆盖核心入口、主流程及 PRD 指定的关键状态
|
||||
- [ ] 原型 URL 可访问,Requirement 关联可读取,iframe 可展示,核心交互可操作
|
||||
- [ ] 边界情况处理
|
||||
- [ ] 错误提示友好
|
||||
- [ ] 反馈及时
|
||||
@@ -512,7 +638,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
## 常用工具
|
||||
|
||||
### 原型设计
|
||||
- **Stitch** (Google AI) — 集成在 `/req prototype`,自动从 PRD 生成原型
|
||||
- **HTML upload(默认交付)** — `/req prototype upload` 生成可交互独立 HTML,上传后以 iframe 关联 Requirement 和 PRD
|
||||
- **Stitch** (Google AI) — `/req prototype` 视觉探索与多屏草图,可作为 HTML 原型输入但不替代最终闭环
|
||||
- Figma — 手动精细设计
|
||||
- Sketch
|
||||
- Axure
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
# 模块设计访谈、缺陷收敛与 HTML 原型闭环协议
|
||||
|
||||
本协议用于模块、系统、跨域流程等需要先澄清关键产品决策的设计任务。目标是让设计依据可追溯,让 PRD 在提交评审前经过可验证的缺陷收敛,并让 UI 模块通过可访问的 HTML 原型完成交互验证。
|
||||
|
||||
## 1. 进入与退出条件
|
||||
|
||||
满足任一条件时进入访谈模式:
|
||||
|
||||
- 用户明确要求“你问我答”、逐项讨论或产品访谈;
|
||||
- 设计对象是模块、系统、跨域流程或涉及多个角色/组织;
|
||||
- 目标、范围、数据归属、权限、状态流转、冲突优先级、异常策略中存在关键未决项。
|
||||
|
||||
需求范围小、上述决策均已明确时,可以直接编写 PRD。不要为了流程而重复询问用户已经回答的问题。
|
||||
|
||||
访谈模式只有同时满足以下条件才可结束:
|
||||
|
||||
1. 未决问题已清零,或明确列为非目标/后续项;
|
||||
2. AI 已给出结构化讨论结论;
|
||||
3. 用户明确确认讨论结论;
|
||||
4. PRD 已按结论创建或更新;
|
||||
5. `defect-analysis` 已对最新版 PRD 收敛;
|
||||
6. UI 模块的 HTML 原型已生成、上传、关联、回填和验证;无 UI 模块已记录不适用理由并获得用户确认;
|
||||
7. 用户联合确认收敛后的最终 PRD 与原型(或无 UI 的跳过结论)。
|
||||
|
||||
## 2. 讨论文档是跨轮次事实源
|
||||
|
||||
当当前工作已有 ai-proj Requirement 时,在提第一个问题前查找其已关联的讨论文档;没有时创建一个 documentation 角色的关联任务,并为任务创建文档:
|
||||
|
||||
- 任务标题:`【讨论】需求讨论: {需求标题}`
|
||||
- 文档标题:`{REQ-ID} 需求讨论记录`
|
||||
- 本地文件:优先使用仓库约定;默认 `docs/product/{REQ-ID}-{slug}-discussion.md`
|
||||
- 一个 Requirement 只维护一个当前讨论文档,不因会话中断重复创建。
|
||||
|
||||
查找时同时核对 Requirement 关联关系、任务角色和标题,不能只按相似标题猜测。发现多个候选讨论文档时,列出标识和最近更新时间,请用户指定或授权合并;在此之前不得静默选择其中一个继续写入。
|
||||
|
||||
初始化文档时,先把触发本次设计的用户原始消息按时间和消息边界逐条写入“原始诉求”,再记录 `Q001`。不得只留下 AI 总结而丢失原始上下文。
|
||||
|
||||
“完整过程”指可供产品决策审计的模型可见内容:用户原话、AI 向用户展示的问题/建议/权衡、工具写入结果、确认、决策变更、PRD 修订和缺陷处置。不得记录或声称记录隐藏推理、系统提示、访问凭据及其他不可披露的内部信息。
|
||||
|
||||
若尚未指定 Requirement,先请用户提供已有 Requirement,或明确授权创建。取得 Requirement 和讨论文档前不得开始声称“已留痕”的正式访谈;不得仅为执行本技能本身擅自创建 Requirement。用户明确要求“创建需求并设计”才构成创建授权。
|
||||
|
||||
每次恢复会话时,先读取 Requirement、现有 PRD,以及讨论记录/PRD 的本地文件和 ai-proj Task Document,从最后一个未决问题继续。两端持久化内容必须一致;模型记忆不能覆盖文档中的用户原话和已确认决策。
|
||||
|
||||
### 本地与 ai-proj 双写
|
||||
|
||||
- 讨论记录和 PRD 的每次新增或修订,都必须同步到仓库本地 Markdown 与对应 ai-proj Task Document;本地文件用于代码库评审和版本控制,Task Document 用于需求关联、跨会话恢复和团队查看。
|
||||
- 修改前读取两端。内容不一致时按版本、更新时间和摘要显式合并,保留双方未知内容;不能判断时停止并请用户选择,禁止以任一旧副本覆盖另一端。
|
||||
- 每轮问答按顺序完成:更新本地讨论文件 → 更新 documentation 任务文档 → 复读两端并核对正文/摘要 → 再向用户提出下一问。
|
||||
- 每次 PRD/defect/原型回填按同样协议更新本地 PRD 文件和 prd 任务文档。默认本地路径为 `docs/product/{REQ-ID}-{slug}-prd.md`,已有项目约定优先。
|
||||
- 任一端失败时记录“部分写入”及成功端的路径/标识,停止后续流程。恢复时从成功端与失败前最后版本合并,禁止重复追加同一 Q/Round/Prototype 编号。
|
||||
|
||||
### 写入纪律
|
||||
|
||||
- 提问时先写入问题原文、问题意图和 AI 建议,再向用户提问。
|
||||
- 收到回答后,先把用户原话和由此形成的决策写入,再提出下一问。
|
||||
- 每轮使用稳定编号 `Q001`、`Q002`……;重试写入时复用编号,禁止重复追加同一轮。
|
||||
- AI 提供推荐方案或选项时,为待确认内容写出明确编号或完整原文。用户仅回复“确认”“是”“前者”等短答案时,最终决策必须引用对应编号和被确认的完整内容,不能只记录孤立短词。
|
||||
- 用户原话逐字保留在引用块中;AI 的解释、推论和建议必须分栏,不能伪装成用户决定。访问令牌、密码、私钥及依法需要保护的个人敏感信息不得落库,用 `[敏感信息已脱敏]` 替代并注明脱敏原因。
|
||||
- 文档以追加式记录为主。状态为“待回答”的问题块可以在收到回答后原位补全一次;变为“已确认”后不得静默改写。纠正已确认结论时追加“决策变更”,并引用被替代的编号。
|
||||
- 更新整篇文档前重新读取最新版并保留未知内容;若读取后文档又发生变化,基于最新版合并后重试,不能用旧副本覆盖其他会话的记录。
|
||||
- 写入后读取本地文件和 ai-proj Task Document,确认本轮编号、正文和内容摘要一致。任一写入或校验失败时立即报告,停止进入下一轮,且不得声称“已记录”。
|
||||
- Requirement 描述只同步用户确认后的“讨论结论”摘要;完整过程保留在讨论文档中。
|
||||
|
||||
## 3. 单轮单问访谈
|
||||
|
||||
每轮只问一个会实质改变产品方案的问题。优先按依赖关系覆盖以下决策面,而不是机械地逐项提问:
|
||||
|
||||
1. 用户问题、目标与成功指标;
|
||||
2. 角色、主体和数据归属;
|
||||
3. 范围、非目标及版本边界;
|
||||
4. 实体关系与基数,例如一对一、一对多、多对多;
|
||||
5. 权限来源、授权人和信任边界;
|
||||
6. 创建、加入、变更、退出、撤销等状态与生命周期;
|
||||
7. 多来源冲突时的优先级和人工覆盖规则;
|
||||
8. 失败、超时、失联、重复请求和恢复策略;
|
||||
9. 兼容、迁移、审计、数据隔离和验收方式。
|
||||
|
||||
问题应让用户做产品决策,不要求用户代替 AI 设计实现细节。用户让 AI 建议时,先给出一个推荐方案和主要权衡,再请用户确认或修正。若回答引入新的实体、状态或例外规则,沿其影响继续追问;若答案已能从用户原话或现有文档确定,则直接记录,不重复确认。
|
||||
|
||||
每轮记录以下内容:
|
||||
|
||||
```markdown
|
||||
### Q001 · {决策主题}
|
||||
|
||||
- 状态:待回答 | 已确认 | 已替代
|
||||
- AI 问题(原文):...
|
||||
- 提问意图:这个答案会影响哪些设计部分
|
||||
- AI 建议与权衡:推荐方案、替代方案及主要代价
|
||||
- 待确认内容:方案/选项编号及完整表述
|
||||
- 用户回答(原文):
|
||||
> ...
|
||||
- 最终决策:只写由用户回答直接支持的结论
|
||||
- 影响范围:PRD 章节、实体、流程、权限或验收标准
|
||||
- 未决项:无 | 下一步待确认内容
|
||||
- 记录时间:ISO 8601 时间
|
||||
```
|
||||
|
||||
## 4. 方案确认闸门
|
||||
|
||||
问题收敛后,在讨论文档追加“当前决策快照”,至少包含:
|
||||
|
||||
- 目标与成功条件;
|
||||
- 用户/角色及核心场景;
|
||||
- 范围与非目标;
|
||||
- 核心实体、关系和数据归属;
|
||||
- 权限、状态流转和冲突规则;
|
||||
- 异常、降级、撤销和审计;
|
||||
- 版本边界与后续项;
|
||||
- 可验证的验收标准草案;
|
||||
- 尚存风险和假设。
|
||||
|
||||
然后向用户展示同一份摘要并询问是否确认。只有用户明确表示确认,才能:
|
||||
|
||||
1. 将摘要同步到 Requirement 描述的 `## 讨论结论`;
|
||||
2. 创建或更新 PRD;
|
||||
3. 进入缺陷收敛循环。
|
||||
|
||||
每一步完成后重新读取目标对象确认写入成功。讨论结论未同步成功时不得开始写 PRD;PRD 未写入或读取到的内容与本次版本不一致时不得开始缺陷审计。
|
||||
|
||||
若用户修改任何结论,记录为新的问答或“决策变更”,更新快照后重新确认。
|
||||
|
||||
## 5. PRD 与 defect-analysis 收敛循环
|
||||
|
||||
讨论确认后,先按 `req-prd` 的完整模板生成或更新 PRD,再完整读取并调用 `defect-analysis`。每次审计都以**当前最新版完整 PRD**、已确认讨论记录和必要的真实代码/数据契约为输入,不能只审查上轮改动片段。首次基线审计必须覆盖 `defect-analysis` 中所有适用的架构、运行时、数据和体验/维护维度;不能因为尚未覆盖其他维度时某个单独维度为 0 个新缺陷而提前结束基线。
|
||||
|
||||
循环执行:
|
||||
|
||||
1. `defect-analysis` 检查最新版 PRD,并按其规则输出带严重度和轮次的缺陷;
|
||||
2. 将本轮输入版本、检查维度、完整发现和证据写入讨论文档;PRD 输入版本至少包含文档/任务标识、更新时间和内容摘要或哈希,避免审计结果关联到错误版本;审计轮使用稳定编号 `Round 001`、`Round 002`……,重试不得重复计轮;
|
||||
3. 对每个发现标记处置:接受、误报、延后;
|
||||
4. 接受的产品缺陷必须修订 PRD,并同步影响到验收标准、风险、非目标或版本边界;纯技术实现发现若不改变产品行为,记录为后续 `req-design` 约束或开发风险,不向 PRD 填入未经验证的实现细节;
|
||||
5. 误报必须记录反证;延后必须记录原因、风险、负责人或后续需求,不得静默忽略;
|
||||
6. 记录 PRD 修改摘要和仍未解决的问题,重新读取 PRD 确认修订已经持久化;
|
||||
7. 对修改后的完整 PRD 重新调用 `defect-analysis`。
|
||||
|
||||
若某个修复会改变已确认的目标、范围、实体关系、权限、用户流程、冲突规则或验收口径,不能由 AI 静默应用。将它追加为新的问答或“决策变更”,说明缺陷证据、推荐方案和代价,获得用户确认并更新决策快照后,再修订 PRD;随后重新开始最新版 PRD 的全量审计。
|
||||
|
||||
完成全维度基线后,只有 `defect-analysis` 对最新版完整 PRD 出现一轮“0 个新缺陷”时才能标记 PRD 收敛。达到 20 轮仍有新发现只是阶段复盘点:汇总剩余风险并请求用户决定是否继续;不得把“达到轮数”写成“已收敛”。用户已明确要求持续审计时,按该技能规则继续下一阶段。
|
||||
|
||||
存在以下任一情况时,不得提交 PRD 评审或宣称完成:
|
||||
|
||||
- 未处置的致命或高严重度缺陷;
|
||||
- 讨论文档缺失或有未成功写入的轮次;
|
||||
- PRD 与已确认决策不一致;
|
||||
- 缺少 0 新增缺陷的收敛轮;
|
||||
- UI 模块缺少已验证并关联的最终 HTML 原型,或原型与最新版 PRD 不一致;
|
||||
- 无 UI 模块没有记录跳过理由及用户确认;
|
||||
- 用户尚未联合确认收敛后的最终 PRD 与原型(或跳过结论)。
|
||||
|
||||
## 6. HTML 原型闭环
|
||||
|
||||
### 6.1 适用性判断
|
||||
|
||||
PRD 包含页面、表单、列表、可视状态、用户操作或跨页面流程时,必须执行 `req-prototype` 的 HTML upload 模式。Stitch 截图或其他静态图片可以辅助探索,但不能替代可交互 HTML、Requirement 关联和 iframe 回填。
|
||||
|
||||
纯后端、批处理、基础设施等无用户界面的模块可以跳过。跳过前必须把理由、影响范围和待确认内容写入讨论文档,取得用户明确确认,并在 PRD `4.2 界面原型` 留下“不适用”记录。
|
||||
|
||||
### 6.2 生成基线与覆盖范围
|
||||
|
||||
1. 重新读取最新版 PRD,记录任务/文档标识、更新时间、版本和内容摘要或哈希;
|
||||
2. 从功能需求、交互设计和验收标准提取页面清单、角色入口、主流程与关键状态;
|
||||
3. 调用 `req-prototype` 生成独立 HTML。至少覆盖核心入口、主流程,以及 PRD 明确要求的空态、加载态、失败态、无权限态、确认和撤销反馈;
|
||||
4. 原型不得引入 PRD 未确认的新权限、状态、自动化规则或默认值。为了连贯展示所作的推断必须显式标注为待确认,不能伪装成既定需求。
|
||||
|
||||
### 6.3 上传、关联、回填与验证
|
||||
|
||||
1. 将 HTML 源文件保存到仓库约定目录(默认 `docs/prototypes/`),再通过 `upload_prototype` 上传到 ai-proj 配置的 OSS,并记录 Requirement 数字 ID、OSS URL、版本说明和上传时间;
|
||||
2. 重新读取 Requirement,确认返回的 OSS URL/版本确实已关联。仅有本地文件或上传成功响应不足以通过;
|
||||
3. 将 iframe、PRD 基线、原型版本、版本说明和验证结果同时回填本地 PRD 与 prd 角色 Task Document;
|
||||
4. 用浏览器或等价方式验证 URL 可访问、iframe 可展示、核心导航和交互可操作、关键状态可识别。使用临时浏览器时按环境规则关闭;
|
||||
5. 将生成输入、上传结果、验证证据和待确认差异写入讨论文档。任何写入或验证失败都必须停止,不得声称原型已完成。
|
||||
|
||||
### 6.4 用户评审与回流
|
||||
|
||||
向用户展示最终关联的原型,并请其同时检查信息结构、流程、状态、权限提示和关键文案:
|
||||
|
||||
- 仅视觉样式、间距、颜色等不改变产品行为的反馈,可以直接生成新原型版本,并记录修改摘要;
|
||||
- 反馈改变目标、范围、实体关系、权限、状态、流程、异常策略、默认值或验收口径时,追加新的问答/决策变更,更新决策快照和 PRD,重新执行完整 `defect-analysis`,收敛后再生成新 HTML 原型版本;
|
||||
- 每个新版本都必须重新执行关联、PRD 回填和可访问性/交互验证,不得覆盖或伪造历史版本;
|
||||
- 只有用户明确确认“最终 PRD 与当前原型一致”后,模块产品设计才可结束。
|
||||
|
||||
## 7. 讨论文档结构
|
||||
|
||||
```markdown
|
||||
# {REQ-ID} 需求讨论记录
|
||||
|
||||
## 元数据
|
||||
- Requirement:...
|
||||
- 状态:访谈中 | 待方案确认 | PRD 优化中 | 原型制作中 | 待最终确认 | 已收敛
|
||||
- 最新 PRD:任务/文档标识
|
||||
- 更新时间:...
|
||||
|
||||
## 原始诉求
|
||||
> 用户原话,按时间追加
|
||||
|
||||
## 问答记录
|
||||
### Q001 · ...
|
||||
...
|
||||
|
||||
## 决策变更
|
||||
### D001 · 替代 Qxxx 的结论
|
||||
...
|
||||
|
||||
## 当前决策快照
|
||||
...
|
||||
|
||||
## 未决问题
|
||||
- ...
|
||||
|
||||
## 方案确认
|
||||
- 用户确认原话:...
|
||||
- 确认时间:...
|
||||
|
||||
## PRD / 缺陷优化记录
|
||||
### Round 1 · {检查维度}
|
||||
- PRD 版本/摘要:...
|
||||
- 新缺陷:...
|
||||
- 处置与证据:...
|
||||
- PRD 修订:...
|
||||
- 剩余风险:...
|
||||
|
||||
## HTML 原型记录
|
||||
### Prototype v1 · {版本说明}
|
||||
- PRD 基线:任务/文档标识、版本、更新时间、摘要或哈希
|
||||
- 是否适用:是 | 否(理由与用户确认)
|
||||
- 原型 URL:...
|
||||
- Requirement 关联校验:...
|
||||
- iframe / 可访问性 / 关键交互验证:...
|
||||
- 用户反馈:...
|
||||
- 行为性变更回流:无 | 对应 Q/D、PRD 版本和 defect 轮次
|
||||
- 状态:待验证 | 待用户确认 | 已替代 | 已确认
|
||||
|
||||
## 收敛结论
|
||||
- 收敛轮次:...
|
||||
- 0 新增缺陷证据:...
|
||||
- 最终原型版本/URL:... | 无 UI,不适用(确认记录:...)
|
||||
- PRD 与原型一致性确认:...
|
||||
- 未解决的中/低风险及接受理由:...
|
||||
- 用户最终确认原话:...
|
||||
```
|
||||
|
||||
## 8. 最终交付说明
|
||||
|
||||
最终回复必须同时给出:
|
||||
|
||||
- ai-proj Requirement 标识;
|
||||
- 讨论任务/文档标识;
|
||||
- 讨论记录本地路径及双写一致性状态;
|
||||
- PRD 任务/文档标识;
|
||||
- PRD 本地路径及双写一致性状态;
|
||||
- 问答轮数、缺陷审计轮数和收敛轮;
|
||||
- HTML 原型版本、URL、Requirement 关联与验证状态;无 UI 时给出跳过理由和用户确认;
|
||||
- 仍被接受的中/低风险;
|
||||
- 用户两次确认:讨论方案确认、最终 PRD 与原型(或无 UI 结论)的联合确认。
|
||||
|
||||
任何标识或写入状态无法验证时,用“未验证/未写入”如实标注。
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "req-prototype-plugin",
|
||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
||||
"version": "2.0.0",
|
||||
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||
"version": "2.2.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
---
|
||||
name: req-prototype
|
||||
description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 PRD 自动生成 UI 原型截图;(2) AI 编写 HTML 原型并上传关联到需求详情页 iframe。当执行 /req prototype 或需要生成/上传界面原型时使用。
|
||||
arguments: [REQ-ID] [upload|edit|variant] [--device desktop|mobile|tablet] [--model pro|flash] [--note "..."] [--prompt "..."]
|
||||
description: 原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。
|
||||
---
|
||||
|
||||
# 原型设计 Skill (req-prototype)
|
||||
|
||||
用法:`/req prototype <REQ-ID> [subcommand] [options]`
|
||||
|
||||
## 概述
|
||||
|
||||
支持两种原型工作流:
|
||||
|
||||
| 模式 | 命令 | 适用场景 | 输出 |
|
||||
|------|------|----------|------|
|
||||
| **HTML 上传** | `/req prototype upload` | 快速展示、评审用静态原型 | iframe 嵌入需求详情页 |
|
||||
| **Stitch AI** | `/req prototype` | 精细 UI 设计、多屏交互 | 截图回填 PRD 文档 |
|
||||
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 本地 HTML 源文件 + OSS URL + Requirement 关联 + PRD iframe |
|
||||
| **Stitch AI** | `/req prototype` | 精细 UI 视觉探索、多屏草图 | 截图回填 PRD,后续仍需转为 HTML 正式原型 |
|
||||
|
||||
## 前置条件
|
||||
|
||||
@@ -22,41 +23,57 @@ arguments: [REQ-ID] [upload|edit|variant] [--device desktop|mobile|tablet] [--mo
|
||||
| 检查项 | 方式 | 失败处理 |
|
||||
|--------|------|----------|
|
||||
| 需求存在 | `mcp__ai-proj__get_requirement` | 报错:需求不存在 |
|
||||
| 后端运行中(upload 模式)| `curl http://localhost:8080/api/v1/health` | 报错:后端未启动 |
|
||||
| PRD 文档存在(Stitch 模式)| 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd |
|
||||
| PRD 文档存在(两种模式)| 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd |
|
||||
| PRD 已完成 defect 收敛(正式 HTML 模式) | 读取讨论文档的收敛轮和最新版 PRD 标识 | 报错:先完成 req-prd/defect-analysis 收敛 |
|
||||
| UI 原型适用 | PRD 含页面、操作流程或可视状态 | 无 UI 时记录不适用理由与用户确认,不生成空壳原型 |
|
||||
|
||||
## HTML 原型持久化门禁
|
||||
|
||||
正式 HTML 原型必须上传到 ai-proj 配置的 OSS(对象存储),并以 OSS HTTPS URL 关联 Requirement。仅生成本地文件、`file://` URL、临时 HTTP 服务或聊天附件都不算完成。
|
||||
|
||||
- 本地源文件优先遵循仓库约定;默认保存为 `docs/prototypes/{REQ-ID}-{slug}-v{N}.html`,纳入版本控制。
|
||||
- OSS 上传必须通过 `mcp__ai-proj__upload_prototype` 或 ai-proj 提供的等价正式接口完成,禁止绕过 Requirement 关联自行上传后只粘贴 URL。
|
||||
- `/tmp` 只能存放编码或校验过程中的临时副本,不能作为原型交付位置。
|
||||
- 上传后必须复读 Requirement,确认 `prototype_urls`/版本记录指向本次 OSS URL;再验证 URL 可访问、响应为 `text/html` 且可内联展示。
|
||||
- OSS 地址必须由 ai-proj 长期管理,不能把短期预签名 URL 写入 PRD;访问控制与 iframe 策略由 ai-proj 统一提供。
|
||||
- 原型元数据和 iframe 回填属于 PRD 修订,必须同时更新本地 PRD Markdown 与 prd 角色 Task Document,并复读校验一致。
|
||||
|
||||
## 子命令
|
||||
|
||||
### 0. `/req prototype upload [REQ-ID] [--note "版本说明"]` — 上传 HTML 原型(**推荐**)
|
||||
|
||||
**适用场景**:快速为需求关联一个带样式的 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览交互流程。
|
||||
**适用场景**:为 UI 模块生成正式 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览和验证交互流程。模块产品设计默认使用此模式完成原型闸门。
|
||||
|
||||
**执行流程**:
|
||||
|
||||
```
|
||||
1. 获取需求信息(mcp__ai-proj__get_requirement)
|
||||
2. 读取 PRD 或需求描述,提炼 UI 关键信息
|
||||
3. AI 编写带完整样式的 HTML 原型文件(见设计规范)
|
||||
4. 保存到 /tmp/proto_<req_id>_<timestamp>.html
|
||||
5. 获取本地 JWT token(登录 API)
|
||||
6. 上传到后端(multipart POST)
|
||||
7. 确认上传成功,输出预览 URL
|
||||
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id,并定位唯一 PRD 与讨论文档
|
||||
2. 完整读取最新版 PRD,记录任务/文档 ID、版本、更新时间和内容摘要或哈希;正式交付还要核对 defect 收敛轮
|
||||
3. 从 PRD 提取页面清单、角色入口、主流程、关键状态和验收条件,形成覆盖矩阵
|
||||
4. AI 编写带完整样式和必要原生交互的独立 HTML 原型文件(见设计规范)
|
||||
5. 保存到仓库原型目录(默认 docs/prototypes/<REQ-ID>-<slug>-v<N>.html),并做结构、大小和敏感信息检查
|
||||
6. 从本地源文件 Base64 编码;如工具需要,可在 /tmp 创建临时编码副本
|
||||
7. 调用 mcp__ai-proj__upload_prototype 上传到 OSS(传入 requirementId + base64 content)
|
||||
8. 重新读取 Requirement,确认 OSS URL/版本已关联;不得只相信上传响应
|
||||
9. 将 iframe、PRD 基线、原型版本/说明和验证状态双写到本地 PRD 与 prd 角色 Task Document
|
||||
10. 打开最终 URL 或需求详情页,验证 iframe 展示和核心交互;记录证据后关闭临时浏览器
|
||||
11. 将生成、关联、验证、用户反馈和版本状态双写到本地讨论记录与 documentation 角色 Task Document
|
||||
```
|
||||
|
||||
**Step 5-6 执行方式**:
|
||||
**Step 6-7 执行方式**:
|
||||
|
||||
```bash
|
||||
# 5. 获取 token(本地开发环境)
|
||||
TOKEN=$(curl -s http://localhost:8080/api/v1/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"username":"qiudl","password":"Admin@2026~"}' \
|
||||
| python3 -c 'import sys,json; print(json.load(sys.stdin)["data"]["access_token"])')
|
||||
# 6. Base64 编码本地 HTML 源文件
|
||||
B64=$(base64 < docs/prototypes/<REQ-ID>-<slug>-v<N>.html)
|
||||
```
|
||||
|
||||
# 6. 上传 HTML 原型并关联到需求
|
||||
curl -s -X POST "http://localhost:8080/api/v1/requirements/<REQ_DB_ID>/prototype" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@/tmp/proto_<req_id>_<timestamp>.html;type=text/html" \
|
||||
-F "version_note=<--note 的值或空>"
|
||||
```
|
||||
# 7. 通过 MCP 工具上传到 OSS(无需本地后端)
|
||||
mcp__ai-proj__upload_prototype(
|
||||
requirementId = <需求数字ID>,
|
||||
content = <B64 字符串>,
|
||||
versionNote = <--note 的值或"初稿 v1">
|
||||
)
|
||||
```
|
||||
|
||||
**成功响应**:
|
||||
@@ -64,15 +81,17 @@ curl -s -X POST "http://localhost:8080/api/v1/requirements/<REQ_DB_ID>/prototype
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "原型已上传并关联到需求 <id>(version=N/A)",
|
||||
"data": {
|
||||
"url": "/api/v1/uploads/prototypes/proto_xxx.html",
|
||||
"version_note": "...",
|
||||
"uploaded_at": "..."
|
||||
"url": "https://<ai-proj-oss-domain>/prototypes/<uuid>.html",
|
||||
"versionNote": "...",
|
||||
"uploadedAt": "...",
|
||||
"requirementId": <id>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**效果**:需求详情页(`/requirements/<id>` 或 `/platform/requirements/<id>`)自动出现「原型预览」卡片,iframe 加载上传的 HTML。
|
||||
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 OSS 上的 HTML 文件。**无需本地后端运行**。OSS 的具体厂商和域名由 ai-proj 服务配置,技能不得硬编码 COS、S3 或其他厂商地址。
|
||||
|
||||
**参数**:
|
||||
|
||||
@@ -102,6 +121,9 @@ AI 生成的 HTML 原型必须满足以下要求:
|
||||
- 覆盖需求描述中的核心功能点
|
||||
- 展示关键数据状态(列表、表单、卡片等)
|
||||
- 按钮/操作有视觉反馈样式(hover 色等)
|
||||
- 对 PRD 明确要求的空态、加载态、失败态、无权限态、二次确认和撤销反馈提供可切换或可识别的展示
|
||||
- 不得自行引入 PRD 未确认的权限、状态、自动化规则或默认值;不可避免的展示推断必须标为待确认
|
||||
- 不包含访问令牌、真实手机号/邮箱、生产数据等敏感信息
|
||||
|
||||
**模板参考**(顶部 topbar + 侧边栏 + 主内容区):
|
||||
|
||||
@@ -146,6 +168,44 @@ AI 生成的 HTML 原型必须满足以下要求:
|
||||
|
||||
---
|
||||
|
||||
#### HTML 原型 PRD 回填
|
||||
|
||||
定位 PRD `### 4.2 界面原型`,写入或更新以下内容;保留历史版本记录,不把旧 URL 静默改写成新版本:
|
||||
|
||||
```markdown
|
||||
### 4.2 界面原型
|
||||
|
||||
**原型基线**:
|
||||
- PRD 任务/文档:#... / #...
|
||||
- PRD 版本/更新时间/摘要:...
|
||||
- defect 收敛轮:Round ...(0 个新缺陷)
|
||||
- HTML 原型:v... · [版本说明]
|
||||
- Requirement 关联:已复读验证
|
||||
- 验证结果:URL 可访问;iframe 可展示;核心交互通过
|
||||
|
||||
<iframe src="[prototype_url]"
|
||||
width="100%" height="600" frameborder="0"
|
||||
style="border-radius:8px;border:1px solid #e5e7eb;">
|
||||
</iframe>
|
||||
```
|
||||
|
||||
原型反馈改变目标、范围、实体关系、权限、状态、流程、异常策略、默认值或验收口径时,不得只改 HTML。回到 `req-prd` 追加问答/决策变更,修订 PRD,重新执行完整 `defect-analysis`,收敛后再上传新原型版本。纯视觉反馈可以直接生成新版本,但仍需重新关联、回填和验证。
|
||||
|
||||
#### HTML 上传后验证清单
|
||||
|
||||
- [ ] 上传响应成功且 Requirement 复读能看到同一 URL/版本
|
||||
- [ ] URL 为 ai-proj 返回的持久化 OSS HTTPS 地址,不是本地或临时地址
|
||||
- [ ] URL 不是短期预签名地址,响应 `Content-Type` 为 `text/html` 且不会强制下载
|
||||
- [ ] 仓库中保留与该 OSS 版本对应的 HTML 源文件
|
||||
- [ ] 原型 URL 返回可展示的 HTML,不是下载错误页、登录页或 404
|
||||
- [ ] 需求详情页使用 iframe 展示,没有降级为截图或图片
|
||||
- [ ] 核心入口、主流程和覆盖矩阵中的关键状态可识别/可操作
|
||||
- [ ] 600px iframe 下内容可用,没有关键操作被固定栏遮挡
|
||||
- [ ] 浏览器控制台无阻断交互的错误,原型不依赖外部 CDN
|
||||
- [ ] PRD `4.2` 与讨论文档均记录基线、版本、URL、验证和反馈状态
|
||||
|
||||
---
|
||||
|
||||
### 1. `/req prototype [REQ-ID]` — Stitch AI 生成原型
|
||||
|
||||
**流程**:
|
||||
@@ -159,6 +219,7 @@ AI 生成的 HTML 原型必须满足以下要求:
|
||||
6. 生成页面(mcp__stitch__generate_screen_from_text)
|
||||
7. 获取截图(mcp__stitch__get_screen)
|
||||
8. 回填 PRD「4.2 界面原型」章节
|
||||
9. 若用于模块正式交付,将选定设计转换为 HTML upload 原型,并完成关联、iframe 和验证闭环
|
||||
```
|
||||
|
||||
**参数**:
|
||||
@@ -280,11 +341,12 @@ generated_at: "<timestamp>"
|
||||
|
||||
| 异常 | 处理 |
|
||||
|------|------|
|
||||
| 后端 500 / `column prototype_urls does not exist` | 需执行数据库迁移:`psql -U <owner> -d <db> -c "ALTER TABLE requirements ADD COLUMN IF NOT EXISTS prototype_urls JSONB DEFAULT '[]';"` |
|
||||
| token 获取失败(401)| 检查用户名密码,或改用生产环境 token |
|
||||
| 需求 ID 不存在(404)| 确认使用数据库自增 ID,而非 display_id(REQ-xxx) |
|
||||
| `mcp__ai-proj__upload_prototype` 返回失败 | 检查 requirementId 是否为数字 ID(非 display_id REQ-xxx);不得降级为只留本地文件 |
|
||||
| HTML 文件超过 5MB | 精简样式或拆分多版本上传 |
|
||||
| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 |
|
||||
| base64 命令失败 | macOS 用 `base64 < file`,Linux 用 `base64 -w 0 < file` |
|
||||
| Requirement 复读没有新 URL | 视为关联失败,停止回填“已验证”,检查 requirementId 和上传响应后再处理 |
|
||||
| URL 可访问但关键交互失败 | 修复 HTML、上传新版本并重新验证,不覆盖失败版本的记录 |
|
||||
|
||||
### 原型展示规则
|
||||
|
||||
@@ -303,6 +365,8 @@ generated_at: "<timestamp>"
|
||||
|
||||
> 背景:REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。
|
||||
|
||||
Stitch 截图只用于视觉探索,不满足模块产品设计的最终 HTML 原型闸门。
|
||||
|
||||
|
||||
### Stitch 模式
|
||||
|
||||
|
||||
@@ -23,10 +23,11 @@ description: 复盘总结。自动采集数据、计算质量评分、跨需求
|
||||
### 2. 质量评分(Quality Score)
|
||||
|
||||
```
|
||||
QS = lookback_pass_rate × 0.3
|
||||
+ audit_defect_score × 0.3
|
||||
+ cr_density_score × 0.2
|
||||
+ test_pass_rate × 0.2
|
||||
QS = lookback_pass_rate × 0.25
|
||||
+ audit_defect_score × 0.25
|
||||
+ cr_density_score × 0.15
|
||||
+ test_pass_rate × 0.15
|
||||
+ karpathy_score × 0.20 ← Karpathy 四原则执行质量
|
||||
|
||||
audit_defect_score:
|
||||
0 缺陷 = 100
|
||||
@@ -38,8 +39,26 @@ audit_defect_score:
|
||||
cr_density_score:
|
||||
100 - (发现数 / 变更行数 × 1000)
|
||||
下限 0,上限 100
|
||||
|
||||
karpathy_score(四原则执行质量,各 25 分,共 100):
|
||||
Think Before PRD (25):
|
||||
PRD 无返工 → 25 | 因需求误解返工 1 次 → 15 | ≥2 次 → 0
|
||||
Simplicity (25):
|
||||
CR 第六视角无 Scope 违规 → 25 | 1 个 Low → 20 | ≥1 个 Medium+ → 10 | High+ → 0
|
||||
Surgical (25):
|
||||
check-surgical.sh PASS + CR 无顺手改 → 25 | 警告但未阻塞 → 15 | FAIL → 0
|
||||
Goal-Driven (25):
|
||||
dev-coding 有验证脚本记录(VP-Steps 先于代码执行)→ 25 | 事后补写 → 15 | 无 → 0
|
||||
```
|
||||
|
||||
**Karpathy 数据来源**(按优先级):
|
||||
1. dev-coding 任务文档中是否有「验证脚本」节
|
||||
2. CR 报告第六视角的发现数和严重度
|
||||
3. `git log` 中是否有 check-surgical.sh baseline 更新提交(说明有过违规)
|
||||
4. PRD 任务文档的版本数(> 1 说明有返工)
|
||||
|
||||
**无数据时**:各维度默认 20 分(中性),在报告中标注 `(无记录,按中性计算)`
|
||||
|
||||
### 3. 历史趋势对比
|
||||
|
||||
读取 `memory/retro_metrics.md` 的明细数据:
|
||||
@@ -87,10 +106,12 @@ AI: "近 5 次需求中 3 次 audit 发现了 {缺陷类型}。
|
||||
|
||||
追加一行到明细:
|
||||
```
|
||||
| REQ-xxx | 2026-04-18 | 5h44m | 92 | 2 | 279 | 3 | frontend |
|
||||
| REQ-xxx | 2026-04-18 | 5h44m | 92 | 2 | 279 | 3 | frontend | 85 |
|
||||
```
|
||||
|
||||
更新汇总:重新计算近 10 次平均值和趋势箭头(↑↓→)。
|
||||
列说明:`REQ | date | time | QS | audit_defects | changed_lines | cr_findings | type | karpathy_score`
|
||||
|
||||
更新汇总:重新计算近 10 次平均值和趋势箭头(↑↓→),包含 karpathy_score 趋势。
|
||||
|
||||
超过 30 条明细 → 最早的移入 `retro_metrics_archive.md`。
|
||||
|
||||
@@ -116,10 +137,19 @@ AI: "近 5 次需求中 3 次 audit 发现了 {缺陷类型}。
|
||||
## 质量指标
|
||||
| 指标 | 本次 | 近10次均 | 对比 |
|
||||
|------|------|---------|------|
|
||||
| 质量分 | 92 | 85 | ↑ |
|
||||
| 质量分 (QS) | 92 | 85 | ↑ |
|
||||
| audit 缺陷 | 2(低) | 3.2 | ↓ |
|
||||
| CR 发现 | 0 | 1.5 | ↓ |
|
||||
| 测试通过率 | 100% | 95% | ↑ |
|
||||
| Karpathy 分 | 85 | 78 | ↑ |
|
||||
|
||||
## Karpathy 四原则评分
|
||||
| 原则 | 得分 | 说明 |
|
||||
|------|------|------|
|
||||
| Think Before PRD | 25/25 | PRD 无返工 |
|
||||
| Simplicity | 20/25 | CR 第六视角发现 1 个 Low |
|
||||
| Surgical | 25/25 | check-surgical.sh PASS |
|
||||
| Goal-Driven | 15/25 | 验证脚本为事后补写 |
|
||||
|
||||
## git 统计
|
||||
| 提交数 | 变更文件 | +行 | -行 |
|
||||
|
||||
@@ -87,12 +87,24 @@ done
|
||||
**报告格式**:
|
||||
```
|
||||
### 约定检查 (Gate 0B)
|
||||
| 脚本 | 结果 | 详情 |
|
||||
|------|------|------|
|
||||
| check-architecture.sh | ✅ PASS | 5 rules, all within baseline |
|
||||
| check-modal-safety.sh | ✅ PASS | 0 violations |
|
||||
| 脚本 | 类型 | 结果 | 详情 |
|
||||
|------|------|------|------|
|
||||
| check-architecture.sh | Ratchet | ✅ PASS | 5 rules, all within baseline |
|
||||
| check-modal-safety.sh | Hard wall | ✅ PASS | 0 violations |
|
||||
| check-surgical.sh | Ratchet | ✅ PASS | 0 format-only violations (baseline=0) |
|
||||
```
|
||||
|
||||
**本项目已建立的约定检查脚本**:
|
||||
|
||||
| 脚本 | 类型 | 检测内容 | 来源 |
|
||||
|------|------|---------|------|
|
||||
| `check-architecture.sh` | Ratchet | Handler 直接引用 database/ 层 | 分层架构规范 |
|
||||
| `check-modal-safety.sh` | Hard wall | Modal.success 后立即操作 UI | REQ-20260416 |
|
||||
| `check-surgical.sh` | Ratchet | PR diff 中疑似仅注释/格式变更的文件 | Karpathy Surgical(REQ-20260421-0003)|
|
||||
|
||||
> `check-surgical.sh` 使用 Ratchet 模式:`.surgical-baseline.json` 记录基线,违规数只能降不能升。
|
||||
> 首次无基线时仅告警,不阻塞。运行 `./scripts/check-surgical.sh baseline` 建立基线。
|
||||
|
||||
> 这样 Harness 建立的约定脚本会在每次 `/req test` 时自动运行,无需手动执行 `/harness report`。
|
||||
|
||||
---
|
||||
|
||||
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TEST_ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$TEST_ROOT"' EXIT
|
||||
|
||||
FIXTURE_REPO="$TEST_ROOT/repo"
|
||||
TEST_HOME="$TEST_ROOT/home"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/.claude-plugin"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/skills/references"
|
||||
mkdir -p "$TEST_HOME"
|
||||
cp "$PROJECT_DIR/install-skills.sh" "$FIXTURE_REPO/install-skills.sh"
|
||||
|
||||
write_manifest() {
|
||||
local plugin="$1" name="$2" version="$3" install_type="${4:-skill}"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin"
|
||||
cat > "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin/plugin.json" <<JSON
|
||||
{"name":"${plugin}-plugin","version":"${version}","install_name":"${name}","install_type":"${install_type}","dir_category":"dev"}
|
||||
JSON
|
||||
}
|
||||
|
||||
write_manifest example example 1.0.0
|
||||
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: example
|
||||
description: Installer fixture version one.
|
||||
---
|
||||
version one
|
||||
EOF
|
||||
printf 'reference one\n' > "$FIXTURE_REPO/skills-dev/example-plugin/skills/references/guide.md"
|
||||
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
test -f "$TEST_HOME/.agents/skills/example/references/guide.md"
|
||||
|
||||
# A repository version upgrade replaces an unchanged prior install.
|
||||
write_manifest example example 2.0.0
|
||||
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: example
|
||||
description: Installer fixture version two.
|
||||
---
|
||||
version two
|
||||
EOF
|
||||
# Reproduce rsync's quick-check edge case: changed content with identical size
|
||||
# and mtime must still replace the recorded, unmodified installation.
|
||||
touch -r "$TEST_HOME/.agents/skills/example/SKILL.md" "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
grep -q 'version two' "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||
grep -q '"version": "2.0.0"' "$TEST_HOME/.agents/.ai-proj-helper-installed-skills.json"
|
||||
|
||||
# A local edit is preserved even when the repository advances again.
|
||||
printf 'local edit\n' >> "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||
write_manifest example example 3.0.0
|
||||
printf 'repository version three\n' >> "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
|
||||
output="$(HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh")"
|
||||
grep -q 'local files were modified' <<<"$output"
|
||||
grep -q 'local edit' "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||
if grep -q 'repository version three' "$TEST_HOME/.agents/skills/example/SKILL.md"; then
|
||||
echo 'local modification was overwritten' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Legacy SKILL.md-only installs gain missing repository resources when their
|
||||
# existing content is an unchanged subset of the source.
|
||||
write_manifest legacy legacy 1.0.0
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references"
|
||||
cat > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: legacy
|
||||
description: Legacy installation fixture.
|
||||
---
|
||||
legacy content
|
||||
EOF
|
||||
printf 'legacy reference\n' > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references/guide.md"
|
||||
mkdir -p "$TEST_HOME/.agents/skills/legacy"
|
||||
cp "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" "$TEST_HOME/.agents/skills/legacy/SKILL.md"
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
test -f "$TEST_HOME/.agents/skills/legacy/references/guide.md"
|
||||
|
||||
# Command manifests become standard Codex skills, while explicit Claude
|
||||
# installs retain the legacy single-file command layout. Both must be stable on
|
||||
# a second run despite the Claude filename change.
|
||||
write_manifest sample-command sample-command 1.0.0 command
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills"
|
||||
cat > "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: sample-command
|
||||
description: Command installation fixture.
|
||||
---
|
||||
command content
|
||||
EOF
|
||||
|
||||
CODEX_TEST_HOME="$TEST_ROOT/codex-home"
|
||||
mkdir -p "$CODEX_TEST_HOME"
|
||||
HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
test -f "$CODEX_TEST_HOME/.agents/skills/sample-command/SKILL.md"
|
||||
test ! -e "$CODEX_TEST_HOME/.claude/commands/sample-command.md"
|
||||
codex_output="$(HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --dry-run)"
|
||||
grep -q '0 plugins would be installed/updated' <<<"$codex_output"
|
||||
if grep -q 'sample-command: local files were modified' <<<"$codex_output"; then
|
||||
echo 'Codex command skill was reported as modified' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CLAUDE_TEST_HOME="$TEST_ROOT/claude-home"
|
||||
mkdir -p "$CLAUDE_TEST_HOME"
|
||||
HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude >/dev/null
|
||||
test -f "$CLAUDE_TEST_HOME/.claude/commands/sample-command.md"
|
||||
claude_output="$(HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude --dry-run)"
|
||||
grep -q '0 plugins would be installed/updated' <<<"$claude_output"
|
||||
if grep -q 'sample-command: local files were modified' <<<"$claude_output"; then
|
||||
echo 'Claude command was reported as modified after filename conversion' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 'install-skills tests passed'
|
||||
@@ -22,6 +22,8 @@ PLUGIN_MAP = {
|
||||
"publish-plugin": ("publish", "skill", "core"),
|
||||
|
||||
# skills-dev
|
||||
"ai-proj-cicd-release-plugin": ("ai-proj-cicd-release", "skill", "dev"),
|
||||
"ai-proj-macos-release-plugin": ("ai-proj-macos-release", "skill", "dev"),
|
||||
"agent-browser-plugin": ("agent-browser", "skill", "dev"),
|
||||
"agent-swarm-plugin": ("agent-swarm", "skill", "dev"),
|
||||
"ai-chat-plugin": ("ai-chat", "skill", "dev"),
|
||||
@@ -44,6 +46,7 @@ PLUGIN_MAP = {
|
||||
"executing-plans-plugin": ("executing-plans", "skill", "dev"),
|
||||
"finishing-branch-plugin": ("finishing-a-development-branch","skill", "dev"), # name mismatch!
|
||||
"frontend-design-plugin": ("frontend-design", "skill", "dev"),
|
||||
"karpathy-guidelines-plugin": ("karpathy-guidelines", "skill", "dev"),
|
||||
"pull-request-plugin": ("pull-request", "skill", "dev"),
|
||||
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user