Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dec25562a4 | ||
|
|
d630b374a3 | ||
|
|
8fc1cd05b7 | ||
|
|
b859a84455 | ||
|
|
9a1400758e | ||
|
|
a58dd1aff3 | ||
|
|
bb5e6be73e | ||
|
|
ef0e9ca1f0 | ||
|
|
ad4e2b16a8 |
+35
-123
@@ -95,6 +95,32 @@
|
|||||||
],
|
],
|
||||||
"strict": false
|
"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",
|
"name": "db-migration-plugin",
|
||||||
"source": "./skills-dev/db-migration-plugin",
|
"source": "./skills-dev/db-migration-plugin",
|
||||||
@@ -111,7 +137,7 @@
|
|||||||
"name": "defect-analysis-plugin",
|
"name": "defect-analysis-plugin",
|
||||||
"source": "./skills-dev/defect-analysis-plugin",
|
"source": "./skills-dev/defect-analysis-plugin",
|
||||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"category": "utility",
|
"category": "utility",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"utility",
|
"utility",
|
||||||
@@ -329,7 +355,7 @@
|
|||||||
"name": "frontend-design-plugin",
|
"name": "frontend-design-plugin",
|
||||||
"source": "./skills-dev/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.",
|
"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",
|
"category": "development",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"development",
|
"development",
|
||||||
@@ -342,7 +368,7 @@
|
|||||||
"name": "karpathy-guidelines-plugin",
|
"name": "karpathy-guidelines-plugin",
|
||||||
"source": "./skills-dev/karpathy-guidelines-plugin",
|
"source": "./skills-dev/karpathy-guidelines-plugin",
|
||||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"category": "utility",
|
"category": "utility",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"utility",
|
"utility",
|
||||||
@@ -367,7 +393,7 @@
|
|||||||
"name": "review-checklist-plugin",
|
"name": "review-checklist-plugin",
|
||||||
"source": "./skills-dev/review-checklist-plugin",
|
"source": "./skills-dev/review-checklist-plugin",
|
||||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"category": "utility",
|
"category": "utility",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"utility",
|
"utility",
|
||||||
@@ -456,8 +482,8 @@
|
|||||||
{
|
{
|
||||||
"name": "req-prd-plugin",
|
"name": "req-prd-plugin",
|
||||||
"source": "./skills-req/req-prd-plugin",
|
"source": "./skills-req/req-prd-plugin",
|
||||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||||
"version": "2.0.0",
|
"version": "2.2.0",
|
||||||
"category": "productivity",
|
"category": "productivity",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"project-management",
|
"project-management",
|
||||||
@@ -469,8 +495,8 @@
|
|||||||
{
|
{
|
||||||
"name": "req-prototype-plugin",
|
"name": "req-prototype-plugin",
|
||||||
"source": "./skills-req/req-prototype-plugin",
|
"source": "./skills-req/req-prototype-plugin",
|
||||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||||
"version": "2.0.0",
|
"version": "2.2.0",
|
||||||
"category": "productivity",
|
"category": "productivity",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"project-management",
|
"project-management",
|
||||||
@@ -560,7 +586,7 @@
|
|||||||
"name": "doubao-voice-plugin",
|
"name": "doubao-voice-plugin",
|
||||||
"source": "./skills-integration/doubao-voice-plugin",
|
"source": "./skills-integration/doubao-voice-plugin",
|
||||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"category": "utility",
|
"category": "utility",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"utility",
|
"utility",
|
||||||
@@ -696,120 +722,6 @@
|
|||||||
"tools"
|
"tools"
|
||||||
],
|
],
|
||||||
"strict": false
|
"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
|
# ai-proj-helper
|
||||||
|
|
||||||
Claude Code 技能市场 + MCP 配置管理工具。
|
Codex 优先、兼容 Claude Code 的 Agent Skills 市场与 MCP 配置管理工具。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./init.sh
|
./install-skills.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
交互式配置 MCP 连接(默认 SSE 模式)+ 自动注册技能市场到 `~/.claude/plugins/known_marketplaces.json`。支持命令行参数:
|
默认安装到 Codex 标准目录 `~/.agents/skills`。Claude Code 的 MCP 与 marketplace 初始化使用:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./init.sh --mode sse --token aiproj_pk_xxx
|
./init.sh --mode sse --token aiproj_pk_xxx
|
||||||
@@ -18,11 +18,11 @@ Claude Code 技能市场 + MCP 配置管理工具。
|
|||||||
|
|
||||||
```
|
```
|
||||||
ai-proj-helper/
|
ai-proj-helper/
|
||||||
├── skills-core/ # 基础设施 (1): ai-proj
|
├── skills-core/ # 基础设施技能
|
||||||
├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
|
├── skills-dev/ # 开发与发布技能
|
||||||
├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
|
├── skills-req/ # 需求管理技能
|
||||||
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
|
├── skills-integration/ # 第三方集成技能
|
||||||
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
|
├── skills-biz/ # 商务技能
|
||||||
├── skills-personal/ # 个人(.gitignore 排除)
|
├── skills-personal/ # 个人(.gitignore 排除)
|
||||||
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
||||||
├── init.sh # MCP 初始化
|
├── init.sh # MCP 初始化
|
||||||
@@ -51,4 +51,4 @@ skills:
|
|||||||
|
|
||||||
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
|
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
|
||||||
- 其余 `skills-*` 目录均由 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`)
|
- **ai-proj 账号 + MCP API Key**:联系管理员获取(Key 格式: `aiproj_pk_xxx`)
|
||||||
|
|
||||||
### 一键部署(2 步搞定)
|
### 一键部署(2 步搞定)
|
||||||
@@ -76,17 +76,16 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
|
|||||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||||
cd ai-proj-helper
|
cd ai-proj-helper
|
||||||
|
|
||||||
# 2. 运行初始化(按提示输入 API Key 即可)
|
# 2. 默认安装到 Codex 的用户级标准目录 ~/.agents/skills
|
||||||
./init.sh
|
./install-skills.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
脚本会自动完成:
|
安装器会复制完整技能目录,包括 `SKILL.md`、references、scripts 和 assets。Codex 会自动发现 `~/.agents/skills` 中的技能;若没有出现,重启 Codex。
|
||||||
- 配置 MCP 服务器连接(`~/.claude/.mcp.json`)
|
|
||||||
- 注册技能市场到 Claude Code(`~/.claude/plugins/known_marketplaces.json`)
|
|
||||||
|
|
||||||
也支持命令行参数跳过交互:
|
Claude Code 用户显式选择 Claude 目标;需要同时配置 MCP 和 marketplace 时运行 `init.sh`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
./install-skills.sh --agent claude
|
||||||
./init.sh --mode sse --token aiproj_pk_xxx
|
./init.sh --mode sse --token aiproj_pk_xxx
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -163,7 +162,7 @@ skills:
|
|||||||
|
|
||||||
- **mode**: MCP 连接模式。`sse` 直连远程服务器(推荐),`stdio` 在本地启动 Node.js 进程
|
- **mode**: MCP 连接模式。`sse` 直连远程服务器(推荐),`stdio` 在本地启动 Node.js 进程
|
||||||
- **disabled**: 不需要的技能可以加到这里,重新运行 `./init.sh` 生效
|
- **disabled**: 不需要的技能可以加到这里,重新运行 `./init.sh` 生效
|
||||||
- **personal_dir**: 个人技能目录,默认不被 Git 跟踪
|
- **personal_dir**: 本机个人技能目录,默认不被 Git 跟踪,也不会写入公开 marketplace
|
||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|
||||||
@@ -171,13 +170,17 @@ skills:
|
|||||||
|
|
||||||
A: 需要先联系管理员获取 MCP API Key(格式 `aiproj_pk_xxx`),然后在提示处输入。
|
A: 需要先联系管理员获取 MCP API Key(格式 `aiproj_pk_xxx`),然后在提示处输入。
|
||||||
|
|
||||||
|
**Q: 安装后 Codex 没有识别到技能?**
|
||||||
|
|
||||||
|
A: 确认技能位于 `~/.agents/skills/<name>/SKILL.md`,然后重启 Codex。Codex CLI 也可用 `/skills` 查看。
|
||||||
|
|
||||||
**Q: 安装后 Claude Code 没有识别到技能?**
|
**Q: 安装后 Claude Code 没有识别到技能?**
|
||||||
|
|
||||||
A: 重启 Claude Code 后生效。如果仍不生效,检查 `~/.claude/plugins/known_marketplaces.json` 中是否包含 `ai-proj-helper` 条目。
|
A: 重启 Claude Code 后生效。如果仍不生效,检查 `~/.claude/plugins/known_marketplaces.json` 中是否包含 `ai-proj-helper` 条目。
|
||||||
|
|
||||||
**Q: 如何更新到最新版本?**
|
**Q: 如何更新到最新版本?**
|
||||||
|
|
||||||
A: 进入项目目录执行 `git pull`,然后重新运行 `./init.sh`。
|
A: 进入项目目录执行 `git pull`,然后运行 `./install-skills.sh`;Claude Code 用户增加 `--agent claude`。
|
||||||
|
|
||||||
**Q: 如何禁用不需要的技能?**
|
**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:
|
## 1. Clone the Gitea Repository
|
||||||
- Name: `claude-marketplace`
|
|
||||||
- Visibility: Private or Public (your choice)
|
|
||||||
- **Do NOT** initialize with README (we already have one)
|
|
||||||
|
|
||||||
## 2. Push to Gitea
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||||
git push -u origin main
|
cd ai-proj-helper
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. Test Installation
|
## 2. Test Installation
|
||||||
|
|
||||||
### Add the marketplace
|
### Add the marketplace
|
||||||
```bash
|
```bash
|
||||||
# SSH (recommended)
|
# SSH
|
||||||
/plugin marketplace add git@gitea.pipexerp.com:huangjun/claude-marketplace.git
|
/plugin marketplace add ssh://git@gitea.pipexerp.com:10022/pipexerp/ai-proj-helper.git
|
||||||
|
|
||||||
# OR HTTPS (requires credential configuration)
|
# 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
|
### List available plugins
|
||||||
@@ -42,12 +37,12 @@ git push -u origin main
|
|||||||
# Check for your installed plugins
|
# Check for your installed plugins
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. Update Plugins Later
|
## 3. Update Plugins Later
|
||||||
|
|
||||||
When you make changes and push updates:
|
When you make changes and push updates:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
cd /path/to/ai-proj-helper
|
||||||
|
|
||||||
# Make changes to plugins
|
# Make changes to plugins
|
||||||
# ...
|
# ...
|
||||||
@@ -67,7 +62,7 @@ Users update with:
|
|||||||
/plugin update ai-proj-plugin@coolbuy-claude-plugins
|
/plugin update ai-proj-plugin@coolbuy-claude-plugins
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. Private Repository Setup
|
## 4. Repository Authentication
|
||||||
|
|
||||||
If your Gitea repo is private, users need 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
|
3. Give it "Read repository" permissions
|
||||||
4. Copy the token and add to your environment
|
4. Copy the token and add to your environment
|
||||||
|
|
||||||
## 6. Structure Overview
|
## 5. Structure Overview
|
||||||
|
|
||||||
```
|
```
|
||||||
claude-marketplace/
|
ai-proj-helper/
|
||||||
├── .claude-plugin/
|
├── .claude-plugin/
|
||||||
│ └── marketplace.json # Catalog of all plugins
|
│ └── marketplace.json # Catalog of all plugins
|
||||||
├── plugins/
|
├── skills-core/ # Core plugins
|
||||||
│ ├── ai-proj-plugin/
|
├── skills-dev/ # Development and release plugins
|
||||||
│ │ ├── .claude-plugin/
|
├── skills-req/ # Requirement plugins
|
||||||
│ │ │ └── plugin.json # Plugin metadata
|
├── skills-integration/ # Integration plugins
|
||||||
│ │ └── skills/
|
├── skills-biz/ # Business plugins
|
||||||
│ │ └── SKILL.md # Skill definition
|
|
||||||
│ └── [33 more plugins...]
|
|
||||||
├── README.md # User documentation
|
├── README.md # User documentation
|
||||||
├── SETUP.md # This file
|
├── SETUP.md # This file
|
||||||
└── convert-skills.sh # Conversion script (reference)
|
├── generate-marketplace.py # Marketplace generator
|
||||||
|
└── install-skills.sh # Versioned local installer
|
||||||
```
|
```
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. ✅ Push to Gitea: `git push -u origin main`
|
1. ✅ Test locally: `/plugin marketplace add <url>`
|
||||||
2. ✅ Test locally: `/plugin marketplace add <url>`
|
2. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
||||||
3. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
3. ✅ Share with team: Send them the repository URL
|
||||||
4. ✅ Share with team: Send them the repository URL
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -123,7 +116,7 @@ claude-marketplace/
|
|||||||
- Check plugin name is correct
|
- Check plugin name is correct
|
||||||
- Ensure marketplace.json is valid: `cat .claude-plugin/marketplace.json | jq`
|
- 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)
|
- Skills are Agent Skills (auto-invoked by Claude when relevant)
|
||||||
- They don't create slash commands
|
- They don't create slash commands
|
||||||
- Check plugin installation: `/plugin list`
|
- Check plugin installation: `/plugin list`
|
||||||
|
|||||||
+40
-189
@@ -1,218 +1,69 @@
|
|||||||
# Skill Sync Guide
|
# 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
|
```bash
|
||||||
cd /path/to/claude-marketplace
|
git pull
|
||||||
./sync-skills.sh
|
./install-skills.sh --dry-run
|
||||||
|
./install-skills.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
This will:
|
Claude Code 需要显式选择目标:
|
||||||
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
|
```bash
|
||||||
code ~/.claude/skills/my-skill/SKILL.md
|
./install-skills.sh --agent claude
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Run Sync Script
|
安装器会复制完整技能目录,包括 `SKILL.md`、`references/`、`scripts/` 和 `assets/`。它用内容摘要区分仓库升级和本地修改:
|
||||||
|
|
||||||
|
- 目标未修改时,版本升级会自动安装。
|
||||||
|
- 旧版只安装了 `SKILL.md` 时,会安全补齐仓库中的其他同源文件。
|
||||||
|
- 目标存在本地修改时会跳过;确认覆盖后才使用 `--force`。
|
||||||
|
- `--cleanup` 会删除状态文件记录中已从仓库移除的技能,使用前先运行 `--dry-run --cleanup`。
|
||||||
|
|
||||||
|
按分类安装或查看清单:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/path/to/claude-marketplace
|
./install-skills.sh --list
|
||||||
./sync-skills.sh
|
./install-skills.sh --category dev
|
||||||
|
./install-skills.sh --exclude ai-proj-cicd-release
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Review Changes
|
## 将本机技能发布到仓库
|
||||||
|
|
||||||
|
不要批量复制整个 `~/.agents/skills/` 或其他 Agent 的安装目录。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
|
||||||
|
|
||||||
|
1. 选择确实属于本仓库、可供团队复用的技能。
|
||||||
|
2. 在对应 `skills-*/<name>-plugin/` 下放置 `.claude-plugin/plugin.json` 和完整 `skills/` 目录。
|
||||||
|
3. 清除用户名、绝对路径、内网地址、密钥标识和历史凭据;把环境差异改为从仓库配置解析。
|
||||||
|
4. 更新插件版本并运行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git status
|
|
||||||
git diff
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Commit & Push
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add .
|
|
||||||
git commit -m "Update skill: description of changes"
|
|
||||||
git push
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Team Updates
|
|
||||||
|
|
||||||
Team members update with:
|
|
||||||
```bash
|
|
||||||
/plugin marketplace update coolbuy-claude-plugins
|
|
||||||
/plugin update <plugin-name>@coolbuy-claude-plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
## Automated Sync (Optional)
|
|
||||||
|
|
||||||
### Git Hook (Pre-commit)
|
|
||||||
|
|
||||||
Auto-sync when committing changes to skills:
|
|
||||||
|
|
||||||
```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)
|
|
||||||
|
|
||||||
Sync daily at 9 AM:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
crontab -e
|
|
||||||
|
|
||||||
# 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
|
python3 generate-marketplace.py
|
||||||
|
claude plugin validate .
|
||||||
# Or edit directly
|
git diff --check
|
||||||
code .claude-plugin/marketplace.json
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Git Conflicts
|
5. 审核变更后通过分支和 PR 发布。
|
||||||
|
|
||||||
```bash
|
## 本地个人技能
|
||||||
# Discard local changes
|
|
||||||
git checkout .claude-plugin/marketplace.json
|
|
||||||
|
|
||||||
# Or merge manually
|
`skills-personal/` 受 `.gitignore` 保护,仅供当前机器使用。生成器明确排除此目录,避免
|
||||||
git mergetool
|
`marketplace.json` 引用公开克隆中不存在的文件。若个人技能要转为团队技能,应先按上面的发布流程完成脱敏和审核。
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
## 常见问题
|
||||||
|
|
||||||
### 1. Descriptive Frontmatter
|
**本地修改被跳过怎么办?**
|
||||||
|
|
||||||
Always include in `SKILL.md`:
|
先比较仓库源和 `~/.agents/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。Claude 目标改查 `~/.claude/skills/`。
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
name: skill-name
|
|
||||||
description: Clear, concise description of what this skill does
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Version Bumping
|
**marketplace 没更新?**
|
||||||
|
|
||||||
When making significant changes:
|
运行 `python3 generate-marketplace.py`,然后检查 `.claude-plugin/marketplace.json` 是否只包含受 Git 跟踪且真实存在的 source。
|
||||||
```bash
|
|
||||||
# Update version in plugin.json
|
|
||||||
{
|
|
||||||
"version": "1.1.0" # was 1.0.0
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Testing Before Sync
|
**如何移除技能?**
|
||||||
|
|
||||||
```bash
|
删除插件目录、重新生成 marketplace、提交变更。使用者随后执行 `./install-skills.sh --dry-run --cleanup`,确认后再去掉 `--dry-run`。
|
||||||
# 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.
|
|
||||||
|
|||||||
+6
-13
@@ -14,28 +14,27 @@ script_dir = Path(__file__).parent.resolve()
|
|||||||
config_file = script_dir / "claude-config.yaml"
|
config_file = script_dir / "claude-config.yaml"
|
||||||
marketplace_file = script_dir / ".claude-plugin" / "marketplace.json"
|
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 = [
|
SKILL_DIRS = [
|
||||||
("core", "skills-core"),
|
("core", "skills-core"),
|
||||||
("dev", "skills-dev"),
|
("dev", "skills-dev"),
|
||||||
("req", "skills-req"),
|
("req", "skills-req"),
|
||||||
("integration", "skills-integration"),
|
("integration", "skills-integration"),
|
||||||
("biz", "skills-biz"),
|
("biz", "skills-biz"),
|
||||||
("personal", "skills-personal"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def load_config():
|
def load_config():
|
||||||
"""Load claude-config.yaml and return disabled list + personal_dir."""
|
"""Load claude-config.yaml and return the disabled plugin list."""
|
||||||
disabled = []
|
disabled = []
|
||||||
personal = "skills-personal"
|
|
||||||
|
|
||||||
if config_file.exists() and HAS_YAML:
|
if config_file.exists() and HAS_YAML:
|
||||||
with open(config_file) as f:
|
with open(config_file) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
skills_cfg = cfg.get("skills", {})
|
skills_cfg = cfg.get("skills", {})
|
||||||
disabled = skills_cfg.get("disabled", []) or []
|
disabled = skills_cfg.get("disabled", []) or []
|
||||||
personal = skills_cfg.get("personal_dir", personal)
|
|
||||||
elif config_file.exists():
|
elif config_file.exists():
|
||||||
# Fallback: parse disabled list without PyYAML
|
# Fallback: parse disabled list without PyYAML
|
||||||
in_disabled = False
|
in_disabled = False
|
||||||
@@ -54,10 +53,7 @@ def load_config():
|
|||||||
disabled.append(val)
|
disabled.append(val)
|
||||||
elif stripped and not stripped.startswith("#"):
|
elif stripped and not stripped.startswith("#"):
|
||||||
break
|
break
|
||||||
if stripped.startswith("personal_dir:"):
|
return disabled
|
||||||
personal = stripped.split(":", 1)[1].strip().strip('"').strip("'")
|
|
||||||
|
|
||||||
return disabled, personal
|
|
||||||
|
|
||||||
|
|
||||||
# Category mapping
|
# Category mapping
|
||||||
@@ -116,15 +112,12 @@ def scan_plugins(directory, source_prefix, disabled):
|
|||||||
|
|
||||||
|
|
||||||
# Load config
|
# Load config
|
||||||
disabled_skills, personal_dir_name = load_config()
|
disabled_skills = load_config()
|
||||||
|
|
||||||
# Collect plugins from all skill directories
|
# Collect plugins from all skill directories
|
||||||
plugins = []
|
plugins = []
|
||||||
counts = {}
|
counts = {}
|
||||||
for label, dir_name in SKILL_DIRS:
|
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
|
skill_path = script_dir / dir_name
|
||||||
if not skill_path.is_dir():
|
if not skill_path.is_dir():
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ai-proj-helper 初始化脚本
|
# ai-proj-helper 初始化脚本
|
||||||
# 配置 MCP 连接 + 安装技能到 ~/.claude/skills/
|
# 配置 Claude MCP 连接 + 安装 Claude 技能
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -183,32 +183,13 @@ EOF
|
|||||||
fi
|
fi
|
||||||
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/ ..."
|
echo "📦 安装技能到 ~/.claude/skills/ ..."
|
||||||
SKILLS_DIR="$HOME/.claude/skills"
|
"$SCRIPT_DIR/install-skills.sh" --agent claude
|
||||||
mkdir -p "$SKILLS_DIR"
|
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 "✅ 技能安装完成"
|
||||||
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"
|
|
||||||
|
|
||||||
# ── Verify MCP connection ────────────────────────────────────────────
|
# ── Verify MCP connection ────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
@@ -270,7 +251,7 @@ if $HAS_CLAUDE; then
|
|||||||
else
|
else
|
||||||
echo " ✅ MCP 服务器 → $MCP_CONFIG"
|
echo " ✅ MCP 服务器 → $MCP_CONFIG"
|
||||||
fi
|
fi
|
||||||
echo " ✅ 技能 ($SKILL_COUNT 个) → $SKILLS_DIR"
|
echo " ✅ 技能 ($SKILL_COUNT 个) → ~/.claude/skills"
|
||||||
echo ""
|
echo ""
|
||||||
echo "重启 Claude Code 即可使用。"
|
echo "重启 Claude Code 即可使用。"
|
||||||
echo "如需更改配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
echo "如需更改配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
||||||
|
|||||||
+181
-63
@@ -1,13 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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:
|
# Usage:
|
||||||
# ./install-skills.sh [options]
|
# ./install-skills.sh [options]
|
||||||
#
|
#
|
||||||
# Options:
|
# Options:
|
||||||
|
# --agent <agent> Install target: codex (default) or claude
|
||||||
# --dry-run Preview changes without writing anything
|
# --dry-run Preview changes without writing anything
|
||||||
# --category <cat> Only install plugins in dir_category=<cat>
|
# --category <cat> Only install plugins in dir_category=<cat>
|
||||||
# Valid values: biz, core, dev, integration, personal, req
|
# Valid values: biz, core, dev, integration, personal, req
|
||||||
|
# --exclude <name> Skip one install_name (repeatable)
|
||||||
# --force Overwrite even if local files were modified
|
# --force Overwrite even if local files were modified
|
||||||
# --cleanup Remove locally installed skills that are no longer in repo
|
# --cleanup Remove locally installed skills that are no longer in repo
|
||||||
# --list List all available plugins without installing
|
# --list List all available plugins without installing
|
||||||
@@ -16,15 +18,18 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
SKILLS_DIR="${HOME}/.claude/skills"
|
SKILLS_DIR=""
|
||||||
COMMANDS_DIR="${HOME}/.claude/commands"
|
COMMANDS_DIR=""
|
||||||
STATE_FILE="${HOME}/.claude/.installed-skills.json"
|
STATE_FILE=""
|
||||||
|
|
||||||
|
AGENT_TARGET="codex"
|
||||||
DRY_RUN=false
|
DRY_RUN=false
|
||||||
CATEGORY_FILTER=""
|
CATEGORY_FILTER=""
|
||||||
|
EXCLUDED_NAMES=()
|
||||||
FORCE=false
|
FORCE=false
|
||||||
CLEANUP=false
|
CLEANUP=false
|
||||||
LIST_ONLY=false
|
LIST_ONLY=false
|
||||||
|
INSTALL_ACTION=false
|
||||||
|
|
||||||
# ── Colour helpers ─────────────────────────────────────────────────────────────
|
# ── Colour helpers ─────────────────────────────────────────────────────────────
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -42,11 +47,19 @@ dry() { echo -e "${YELLOW}[dry]${RESET} $*"; }
|
|||||||
# ── Argument parsing ───────────────────────────────────────────────────────────
|
# ── Argument parsing ───────────────────────────────────────────────────────────
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
--agent)
|
||||||
|
[[ $# -ge 2 ]] || { error "--agent requires codex or claude"; exit 1; }
|
||||||
|
AGENT_TARGET="$2"; shift ;;
|
||||||
--dry-run) DRY_RUN=true ;;
|
--dry-run) DRY_RUN=true ;;
|
||||||
--force) FORCE=true ;;
|
--force) FORCE=true ;;
|
||||||
--cleanup) CLEANUP=true ;;
|
--cleanup) CLEANUP=true ;;
|
||||||
--list) LIST_ONLY=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)
|
--help|-h)
|
||||||
grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//'
|
grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//'
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
@@ -57,6 +70,24 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
done
|
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 helpers (plain JSON via python3) ─────────────────────────────────────
|
||||||
state_get() {
|
state_get() {
|
||||||
# state_get <install_name> -> prints version or empty string
|
# state_get <install_name> -> prints version or empty string
|
||||||
@@ -72,14 +103,28 @@ except: pass
|
|||||||
fi
|
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() {
|
||||||
# state_set <install_name> <version> <install_type>
|
# state_set <install_name> <version> <install_type> <content_digest>
|
||||||
local name="$1" ver="$2" itype="$3"
|
local name="$1" ver="$2" itype="$3" digest="$4"
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import json,os
|
import json,os
|
||||||
f='$STATE_FILE'
|
f='$STATE_FILE'
|
||||||
d=json.load(open(f)) if os.path.exists(f) else {}
|
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)
|
json.dump(d,open(f,'w'),indent=2)
|
||||||
" 2>/dev/null
|
" 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
|
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.
|
# Resolve the actual source directory to rsync from.
|
||||||
# If skills/ has SKILL.md at the top level, use it directly.
|
# 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.
|
# 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"
|
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 a single plugin ────────────────────────────────────────────────────
|
||||||
install_plugin() {
|
install_plugin() {
|
||||||
|
INSTALL_ACTION=false
|
||||||
local json_path="$1"
|
local json_path="$1"
|
||||||
local plugin_dir
|
local plugin_dir
|
||||||
plugin_dir="$(dirname "$(dirname "$json_path")")" # strip /.claude-plugin/plugin.json
|
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)"
|
dir_category="$(read_field "$json_path" dir_category)"
|
||||||
version="$(read_field "$json_path" version)"
|
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)
|
# Skip if no install metadata (legacy plugin without our new fields)
|
||||||
if [[ -z "$install_name" || -z "$install_type" ]]; then
|
if [[ -z "$install_name" || -z "$install_type" ]]; then
|
||||||
warn "$(basename "$plugin_dir"): missing install_name/install_type, skipping"
|
warn "$(basename "$plugin_dir"): missing install_name/install_type, skipping"
|
||||||
@@ -190,35 +276,67 @@ install_plugin() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local effective_install_type="$install_type"
|
||||||
|
if [[ "$AGENT_TARGET" == "codex" ]]; then
|
||||||
|
effective_install_type="skill"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$LIST_ONLY" == true ]]; then
|
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
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check current installed version
|
|
||||||
local current_version
|
|
||||||
current_version="$(state_get "$install_name")"
|
|
||||||
|
|
||||||
# Skip if up-to-date (same version) and no force
|
|
||||||
if [[ "$current_version" == "$version" && "$FORCE" == false ]]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Conflict detection: warn if local files were modified
|
|
||||||
if [[ -n "$current_version" && "$FORCE" == false ]]; then
|
|
||||||
if has_local_modification "$install_name" "$install_type" "$skills_dir"; then
|
|
||||||
warn "$install_name: local files were modified — skipping (use --force to overwrite)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Resolve actual source (handles plugins where content sits one level deeper,
|
# Resolve actual source (handles plugins where content sits one level deeper,
|
||||||
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md)
|
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md).
|
||||||
local src_dir
|
local src_dir
|
||||||
src_dir="$(resolve_skills_src "$skills_dir")"
|
src_dir="$(resolve_skills_src "$skills_dir")"
|
||||||
|
|
||||||
|
local source_path target_path
|
||||||
|
if [[ "$effective_install_type" == "command" ]]; then
|
||||||
|
source_path="$src_dir/SKILL.md"
|
||||||
|
target_path="$COMMANDS_DIR/${install_name}.md"
|
||||||
|
else
|
||||||
|
source_path="$src_dir"
|
||||||
|
target_path="$SKILLS_DIR/$install_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e "$source_path" ]]; then
|
||||||
|
warn "$install_name: install source not found, skipping"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A recorded content digest distinguishes repository updates from user edits.
|
||||||
|
# Legacy state is adopted automatically only when the target is missing or
|
||||||
|
# already identical to the repository source.
|
||||||
|
local current_version recorded_digest source_digest target_digest
|
||||||
|
current_version="$(state_get "$install_name")"
|
||||||
|
recorded_digest="$(state_digest "$install_name")"
|
||||||
|
source_digest="$(content_digest "$source_path")"
|
||||||
|
target_digest="$(content_digest "$target_path")"
|
||||||
|
|
||||||
|
if [[ "$FORCE" == false && -n "$target_digest" && "$target_digest" == "$source_digest" ]]; then
|
||||||
|
if [[ "$DRY_RUN" == false && ( "$current_version" != "$version" || "$recorded_digest" != "$source_digest" ) ]]; then
|
||||||
|
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local legacy_subset=false
|
||||||
|
if [[ "$effective_install_type" == "skill" && -z "$recorded_digest" && -n "$target_digest" ]]; then
|
||||||
|
if is_compatible_subset "$source_path" "$target_path"; then
|
||||||
|
legacy_subset=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$FORCE" == false && -n "$target_digest" && "$legacy_subset" == false ]]; then
|
||||||
|
if [[ -z "$recorded_digest" || "$target_digest" != "$recorded_digest" ]]; then
|
||||||
|
warn "$install_name: local files were modified or have legacy unverified state — skipping (use --force once to adopt repository content)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Perform install
|
# Perform install
|
||||||
if [[ "$install_type" == "command" ]]; then
|
if [[ "$effective_install_type" == "command" ]]; then
|
||||||
# Single-file command → ~/.claude/commands/<name>.md
|
# Single-file command → ~/.claude/commands/<name>.md
|
||||||
local src_md="$src_dir/SKILL.md"
|
local src_md="$src_dir/SKILL.md"
|
||||||
if [[ ! -f "$src_md" ]]; then
|
if [[ ! -f "$src_md" ]]; then
|
||||||
@@ -228,25 +346,29 @@ install_plugin() {
|
|||||||
|
|
||||||
if [[ "$DRY_RUN" == true ]]; then
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
dry "$install_name → $COMMANDS_DIR/${install_name}.md"
|
dry "$install_name → $COMMANDS_DIR/${install_name}.md"
|
||||||
|
INSTALL_ACTION=true
|
||||||
else
|
else
|
||||||
mkdir -p "$COMMANDS_DIR"
|
mkdir -p "$COMMANDS_DIR"
|
||||||
cp "$src_md" "$COMMANDS_DIR/${install_name}.md"
|
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)"
|
ok "$install_name → command (v$version)"
|
||||||
|
INSTALL_ACTION=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
# Skill directory → ~/.claude/skills/<name>/
|
# Standard skill directory → the selected agent's discovery root.
|
||||||
local dst_dir="$SKILLS_DIR/$install_name"
|
local dst_dir="$SKILLS_DIR/$install_name"
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == true ]]; then
|
if [[ "$DRY_RUN" == true ]]; then
|
||||||
dry "$install_name → $dst_dir/"
|
dry "$install_name → $dst_dir/"
|
||||||
|
INSTALL_ACTION=true
|
||||||
else
|
else
|
||||||
mkdir -p "$dst_dir"
|
mkdir -p "$dst_dir"
|
||||||
# rsync resolved source (handles nested skills/ structures)
|
# rsync resolved source (handles nested skills/ structures)
|
||||||
rsync -a --delete "$src_dir/" "$dst_dir/"
|
rsync -a --delete "$src_dir/" "$dst_dir/"
|
||||||
state_set "$install_name" "$version" "$install_type"
|
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||||
ok "$install_name → skill (v$version)"
|
ok "$install_name → skill (v$version)"
|
||||||
|
INSTALL_ACTION=true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -307,19 +429,15 @@ main() {
|
|||||||
return
|
return
|
||||||
fi
|
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"
|
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
|
||||||
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
|
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
|
||||||
|
|
||||||
local installed=0 skipped=0
|
local installed=0
|
||||||
|
|
||||||
while IFS= read -r json_path; do
|
while IFS= read -r json_path; do
|
||||||
local before
|
|
||||||
before="$(state_all_names | wc -l || true)"
|
|
||||||
install_plugin "$json_path"
|
install_plugin "$json_path"
|
||||||
local after
|
if [[ "$INSTALL_ACTION" == true ]]; then
|
||||||
after="$(state_all_names | wc -l || true)"
|
|
||||||
if [[ "$after" -gt "$before" ]] || [[ "$DRY_RUN" == true ]]; then
|
|
||||||
((installed++)) || true
|
((installed++)) || true
|
||||||
fi
|
fi
|
||||||
done < <(find_plugins)
|
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",
|
"name": "defect-analysis-plugin",
|
||||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ description: 系统性设计缺陷分析。对需求方案/代码架构进行多
|
|||||||
|
|
||||||
- 每轮检查一个维度,输出发现的缺陷列表
|
- 每轮检查一个维度,输出发现的缺陷列表
|
||||||
- 如果某轮发现 0 个新缺陷 → **收敛,停止**
|
- 如果某轮发现 0 个新缺陷 → **收敛,停止**
|
||||||
- 如果 5 轮后仍有新发现 → 继续,最多 10 轮
|
- 如果 5 轮后仍有新发现 → 继续;20 轮作为阶段复盘点,不得误报为已收敛
|
||||||
|
- 达到 20 轮仍有新发现时,汇总剩余风险面并请求用户确认是否继续;用户已明确要求持续审计时可继续下一阶段
|
||||||
|
- 只有出现一轮 0 个新缺陷时才标记收敛;达到授权范围、时间或预算边界时应报告“尚未收敛”,不得伪装完成
|
||||||
- 每个缺陷标注严重度和轮次
|
- 每个缺陷标注严重度和轮次
|
||||||
|
|
||||||
## 输出格式
|
## 输出格式
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend-design-plugin",
|
"name": "frontend-design-plugin",
|
||||||
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
|
"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": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: frontend-design
|
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.
|
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 前端设计技能
|
# Frontend Design 前端设计技能
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "karpathy-guidelines",
|
"name": "karpathy-guidelines",
|
||||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"author": "qiudl",
|
"author": {
|
||||||
"source": "https://github.com/forrestchang/andrej-karpathy-skills",
|
"name": "qiudl"
|
||||||
"tags": ["coding-guidelines", "karpathy", "simplicity", "surgical", "goal-driven"],
|
},
|
||||||
"skills": ["karpathy-guidelines"]
|
"install_name": "karpathy-guidelines",
|
||||||
|
"install_type": "skill",
|
||||||
|
"dir_category": "dev"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "review-checklist-plugin",
|
"name": "review-checklist-plugin",
|
||||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,16 +13,17 @@ description: 项目级代码评审检查清单。按项目积累特定检查项
|
|||||||
|
|
||||||
## 使用方式
|
## 使用方式
|
||||||
|
|
||||||
1. `dev-review` 执行五视角扫描时,自动加载当前项目的检查清单
|
1. `dev-review` 执行五视角扫描时,先读取 `references/general.md`
|
||||||
2. 扫描完成后,逐条检查清单项
|
2. 如果仓库是 AI-Proj,读取 `references/ai-proj.md`;如果是 Coolbuy PaaS,读取 `references/coolbuy-paas.md`
|
||||||
3. 检查结果附加到 CR 报告的「项目检查清单」章节
|
3. 扫描完成后,逐条检查适用的清单项
|
||||||
|
4. 检查结果附加到 CR 报告的「项目检查清单」章节
|
||||||
|
|
||||||
## 检查清单文件
|
## 检查清单文件
|
||||||
|
|
||||||
```
|
```
|
||||||
review-checklist-plugin/
|
review-checklist/
|
||||||
├── skills/SKILL.md # 本文件
|
├── SKILL.md # 本文件
|
||||||
└── checklists/
|
└── references/
|
||||||
├── ai-proj.md # AI-Proj 项目清单
|
├── ai-proj.md # AI-Proj 项目清单
|
||||||
├── coolbuy-paas.md # 酷采3.0 项目清单
|
├── coolbuy-paas.md # 酷采3.0 项目清单
|
||||||
└── general.md # 通用清单(所有项目适用)
|
└── general.md # 通用清单(所有项目适用)
|
||||||
@@ -32,7 +33,7 @@ review-checklist-plugin/
|
|||||||
|
|
||||||
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
|
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
|
||||||
|
|
||||||
1. 打开对应项目的检查清单文件
|
1. 打开 `references/` 中对应项目的检查清单文件
|
||||||
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
|
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
|
||||||
3. 标注严重度和适用范围
|
3. 标注严重度和适用范围
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -18,6 +18,14 @@
|
|||||||
- [ ] JWT token 类型是否区分 access/refresh?— 教训:token 混用导致安全漏洞
|
- [ ] JWT token 类型是否区分 access/refresh?— 教训:token 混用导致安全漏洞
|
||||||
- [ ] bcrypt cost 是否使用 12?— 教训:默认 cost 10 导致登录失败
|
- [ ] 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
|
||||||
- [ ] Redis key 是否有 TTL?— 缺少 TTL 导致内存泄露
|
- [ ] Redis key 是否有 TTL?— 缺少 TTL 导致内存泄露
|
||||||
- [ ] Redis 不可用时是否降级到数据库?
|
- [ ] Redis 不可用时是否降级到数据库?
|
||||||
@@ -37,6 +45,6 @@
|
|||||||
|
|
||||||
## 通用
|
## 通用
|
||||||
|
|
||||||
- [ ] `.env` ��凭据文件是否被意外加入 git?
|
- [ ] `.env` 等凭据文件是否被意外加入 git?
|
||||||
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
|
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
|
||||||
- [ ] 错误日志是否包含足够的上下文信息?(user_id, tenant_id, request_id)
|
- [ ] 错误日志是否包含足够的上下文信息?(user_id, tenant_id, request_id)
|
||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
### 数据迁移
|
### 数据迁移
|
||||||
- [ ] 从酷采2.0迁移的字段映射是否正确?(varchar ID → bigint ID)
|
- [ ] 从酷采2.0迁移的字段映射是否正确?(varchar ID → bigint ID)
|
||||||
- [ ] 迁移脚本是否处理了酷采2.0���软删除标记(is_delete → deleted_at)?
|
- [ ] 迁移脚本是否处理了酷采2.0 的软删除标记(is_delete → deleted_at)?
|
||||||
|
|
||||||
## 前端(Vue 3 + Ant Design Vue)
|
## 前端(Vue 3 + Ant Design Vue)
|
||||||
|
|
||||||
+2
@@ -1,5 +1,7 @@
|
|||||||
# 通用代码评审检查清单
|
# 通用代码评审检查清单
|
||||||
|
|
||||||
|
每次代码审查都应加载本清单。
|
||||||
|
|
||||||
适用于所有项目,补充六视角扫描法(五传统视角 + Karpathy Scope 视角)。
|
适用于所有项目,补充六视角扫描法(五传统视角 + Karpathy Scope 视角)。
|
||||||
|
|
||||||
## Karpathy 反模式速查(Scope 审计者视角辅助)
|
## Karpathy 反模式速查(Scope 审计者视角辅助)
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "doubao-voice-plugin",
|
"name": "doubao-voice-plugin",
|
||||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
"skills": [
|
|
||||||
{
|
|
||||||
"name": "doubao-voice",
|
|
||||||
"path": "./skills/SKILL.md"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"install_name": "doubao-voice",
|
"install_name": "doubao-voice",
|
||||||
"install_type": "skill",
|
"install_type": "skill",
|
||||||
"dir_category": "integration"
|
"dir_category": "integration"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "req-prd-plugin",
|
"name": "req-prd-plugin",
|
||||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||||
"version": "2.0.0",
|
"version": "2.2.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: req-prd
|
name: req-prd
|
||||||
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
|
description: 产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。
|
||||||
---
|
---
|
||||||
|
|
||||||
# 产品需求设计 Skill (req-prd)
|
# 产品需求设计 Skill (req-prd)
|
||||||
@@ -16,7 +16,66 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
|||||||
|
|
||||||
**插件扩展**:
|
**插件扩展**:
|
||||||
- `req-compare` — 对比式 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)
|
## 客户原话原则(REQ-20260416-0017 P1-8)
|
||||||
|
|
||||||
@@ -108,10 +167,21 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
|||||||
|
|
||||||
### 4.2 界面原型
|
### 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. 技术要求
|
||||||
### 5.1 性能要求
|
### 5.1 性能要求
|
||||||
@@ -361,6 +431,8 @@ mcp__ai-proj__link_tasks_to_requirement
|
|||||||
|
|
||||||
### 文档管理
|
### 文档管理
|
||||||
|
|
||||||
|
以下 MCP 操作只完成 ai-proj 侧写入;每次调用前后都必须按“产品需求文档双写门禁”同步并校验本地 Markdown。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 创建 PRD 文档并关联任务
|
# 创建 PRD 文档并关联任务
|
||||||
mcp__ai-proj__create-and-attach
|
mcp__ai-proj__create-and-attach
|
||||||
@@ -378,6 +450,8 @@ mcp__ai-proj__export_task_document_to_file
|
|||||||
- taskId: 任务ID
|
- taskId: 任务ID
|
||||||
```
|
```
|
||||||
|
|
||||||
|
导出命令不能代替双写校验:导出后仍需确认目标路径符合仓库约定、正文与 Task Document 当前版本一致,且没有覆盖本地新增内容。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 功能设计流程
|
## 功能设计流程
|
||||||
@@ -395,6 +469,8 @@ mcp__ai-proj__export_task_document_to_file
|
|||||||
- 需求池(ai-proj 需求列表)
|
- 需求池(ai-proj 需求列表)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
若命中“模块设计访谈模式”,本阶段改为执行访谈协议并持续写入 ai-proj 讨论文档;访谈未确认前不进入 PRD 定稿。
|
||||||
|
|
||||||
### 2. 需求分析
|
### 2. 需求分析
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -419,10 +495,44 @@ mcp__ai-proj__export_task_document_to_file
|
|||||||
|
|
||||||
输出:
|
输出:
|
||||||
- PRD 文档
|
- 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 完整性检查
|
### 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 — 手动精细设计
|
- Figma — 手动精细设计
|
||||||
- Sketch
|
- Sketch
|
||||||
- Axure
|
- 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",
|
"name": "req-prototype-plugin",
|
||||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||||
"version": "2.0.0",
|
"version": "2.2.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "qiudl"
|
"name": "qiudl"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
---
|
---
|
||||||
name: req-prototype
|
name: req-prototype
|
||||||
description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 PRD 自动生成 UI 原型截图;(2) AI 编写 HTML 原型并上传关联到需求详情页 iframe。当执行 /req prototype 或需要生成/上传界面原型时使用。
|
description: 原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。
|
||||||
arguments: <REQ-ID> [subcommand] [options]
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 原型设计 Skill (req-prototype)
|
# 原型设计 Skill (req-prototype)
|
||||||
|
|
||||||
|
用法:`/req prototype <REQ-ID> [subcommand] [options]`
|
||||||
|
|
||||||
## 概述
|
## 概述
|
||||||
|
|
||||||
支持两种原型工作流:
|
支持两种原型工作流:
|
||||||
|
|
||||||
| 模式 | 命令 | 适用场景 | 输出 |
|
| 模式 | 命令 | 适用场景 | 输出 |
|
||||||
|------|------|----------|------|
|
|------|------|----------|------|
|
||||||
| **HTML 上传** | `/req prototype upload` | 快速展示、评审用静态原型 | iframe 嵌入需求详情页 |
|
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 本地 HTML 源文件 + OSS URL + Requirement 关联 + PRD iframe |
|
||||||
| **Stitch AI** | `/req prototype` | 精细 UI 设计、多屏交互 | 截图回填 PRD 文档 |
|
| **Stitch AI** | `/req prototype` | 精细 UI 视觉探索、多屏草图 | 截图回填 PRD,后续仍需转为 HTML 正式原型 |
|
||||||
|
|
||||||
## 前置条件
|
## 前置条件
|
||||||
|
|
||||||
@@ -22,35 +23,52 @@ arguments: <REQ-ID> [subcommand] [options]
|
|||||||
| 检查项 | 方式 | 失败处理 |
|
| 检查项 | 方式 | 失败处理 |
|
||||||
|--------|------|----------|
|
|--------|------|----------|
|
||||||
| 需求存在 | `mcp__ai-proj__get_requirement` | 报错:需求不存在 |
|
| 需求存在 | `mcp__ai-proj__get_requirement` | 报错:需求不存在 |
|
||||||
| 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 原型(**推荐**)
|
### 0. `/req prototype upload [REQ-ID] [--note "版本说明"]` — 上传 HTML 原型(**推荐**)
|
||||||
|
|
||||||
**适用场景**:快速为需求关联一个带样式的 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览交互流程。
|
**适用场景**:为 UI 模块生成正式 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览和验证交互流程。模块产品设计默认使用此模式完成原型闸门。
|
||||||
|
|
||||||
**执行流程**:
|
**执行流程**:
|
||||||
|
|
||||||
```
|
```
|
||||||
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id
|
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id,并定位唯一 PRD 与讨论文档
|
||||||
2. 读取 PRD 或需求描述,提炼 UI 关键信息
|
2. 完整读取最新版 PRD,记录任务/文档 ID、版本、更新时间和内容摘要或哈希;正式交付还要核对 defect 收敛轮
|
||||||
3. AI 编写带完整样式的 HTML 原型文件(见设计规范)
|
3. 从 PRD 提取页面清单、角色入口、主流程、关键状态和验收条件,形成覆盖矩阵
|
||||||
4. 保存到 /tmp/proto_<req_id>_<timestamp>.html
|
4. AI 编写带完整样式和必要原生交互的独立 HTML 原型文件(见设计规范)
|
||||||
5. Base64 编码:base64 < /tmp/proto_<req_id>_<timestamp>.html
|
5. 保存到仓库原型目录(默认 docs/prototypes/<REQ-ID>-<slug>-v<N>.html),并做结构、大小和敏感信息检查
|
||||||
6. 调用 mcp__ai-proj__upload_prototype 上传(传入 requirementId + base64 content)
|
6. 从本地源文件 Base64 编码;如工具需要,可在 /tmp 创建临时编码副本
|
||||||
7. 确认上传成功,输出 COS 预览 URL
|
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
|
```bash
|
||||||
# 5. Base64 编码 HTML 文件
|
# 6. Base64 编码本地 HTML 源文件
|
||||||
B64=$(base64 < /tmp/proto_<req_id>_<timestamp>.html)
|
B64=$(base64 < docs/prototypes/<REQ-ID>-<slug>-v<N>.html)
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
# 6. 通过 MCP 工具上传(无需本地后端)
|
# 7. 通过 MCP 工具上传到 OSS(无需本地后端)
|
||||||
mcp__ai-proj__upload_prototype(
|
mcp__ai-proj__upload_prototype(
|
||||||
requirementId = <需求数字ID>,
|
requirementId = <需求数字ID>,
|
||||||
content = <B64 字符串>,
|
content = <B64 字符串>,
|
||||||
@@ -65,7 +83,7 @@ mcp__ai-proj__upload_prototype(
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "原型已上传并关联到需求 <id>(version=N/A)",
|
"message": "原型已上传并关联到需求 <id>(version=N/A)",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "https://ai-proj-1252326374.cos.ap-beijing.myqcloud.com/prototypes/<uuid>.html",
|
"url": "https://<ai-proj-oss-domain>/prototypes/<uuid>.html",
|
||||||
"versionNote": "...",
|
"versionNote": "...",
|
||||||
"uploadedAt": "...",
|
"uploadedAt": "...",
|
||||||
"requirementId": <id>
|
"requirementId": <id>
|
||||||
@@ -73,7 +91,7 @@ mcp__ai-proj__upload_prototype(
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 COS 上的 HTML 文件。**无需本地后端运行**。
|
**效果**:需求详情页自动出现「原型预览」卡片,iframe 加载 OSS 上的 HTML 文件。**无需本地后端运行**。OSS 的具体厂商和域名由 ai-proj 服务配置,技能不得硬编码 COS、S3 或其他厂商地址。
|
||||||
|
|
||||||
**参数**:
|
**参数**:
|
||||||
|
|
||||||
@@ -103,6 +121,9 @@ AI 生成的 HTML 原型必须满足以下要求:
|
|||||||
- 覆盖需求描述中的核心功能点
|
- 覆盖需求描述中的核心功能点
|
||||||
- 展示关键数据状态(列表、表单、卡片等)
|
- 展示关键数据状态(列表、表单、卡片等)
|
||||||
- 按钮/操作有视觉反馈样式(hover 色等)
|
- 按钮/操作有视觉反馈样式(hover 色等)
|
||||||
|
- 对 PRD 明确要求的空态、加载态、失败态、无权限态、二次确认和撤销反馈提供可切换或可识别的展示
|
||||||
|
- 不得自行引入 PRD 未确认的权限、状态、自动化规则或默认值;不可避免的展示推断必须标为待确认
|
||||||
|
- 不包含访问令牌、真实手机号/邮箱、生产数据等敏感信息
|
||||||
|
|
||||||
**模板参考**(顶部 topbar + 侧边栏 + 主内容区):
|
**模板参考**(顶部 topbar + 侧边栏 + 主内容区):
|
||||||
|
|
||||||
@@ -147,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 生成原型
|
### 1. `/req prototype [REQ-ID]` — Stitch AI 生成原型
|
||||||
|
|
||||||
**流程**:
|
**流程**:
|
||||||
@@ -160,6 +219,7 @@ AI 生成的 HTML 原型必须满足以下要求:
|
|||||||
6. 生成页面(mcp__stitch__generate_screen_from_text)
|
6. 生成页面(mcp__stitch__generate_screen_from_text)
|
||||||
7. 获取截图(mcp__stitch__get_screen)
|
7. 获取截图(mcp__stitch__get_screen)
|
||||||
8. 回填 PRD「4.2 界面原型」章节
|
8. 回填 PRD「4.2 界面原型」章节
|
||||||
|
9. 若用于模块正式交付,将选定设计转换为 HTML upload 原型,并完成关联、iframe 和验证闭环
|
||||||
```
|
```
|
||||||
|
|
||||||
**参数**:
|
**参数**:
|
||||||
@@ -281,10 +341,12 @@ generated_at: "<timestamp>"
|
|||||||
|
|
||||||
| 异常 | 处理 |
|
| 异常 | 处理 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `mcp__ai-proj__upload_prototype` 返回失败 | 检查 requirementId 是否为数字 ID(非 display_id REQ-xxx) |
|
| `mcp__ai-proj__upload_prototype` 返回失败 | 检查 requirementId 是否为数字 ID(非 display_id REQ-xxx);不得降级为只留本地文件 |
|
||||||
| HTML 文件超过 5MB | 精简样式或拆分多版本上传 |
|
| HTML 文件超过 5MB | 精简样式或拆分多版本上传 |
|
||||||
| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 |
|
| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 |
|
||||||
| base64 命令失败 | macOS 用 `base64 < file`,Linux 用 `base64 -w 0 < file` |
|
| 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 后可正常使用。
|
> 背景:REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。
|
||||||
|
|
||||||
|
Stitch 截图只用于视觉探索,不满足模块产品设计的最终 HTML 原型闸门。
|
||||||
|
|
||||||
|
|
||||||
### Stitch 模式
|
### Stitch 模式
|
||||||
|
|
||||||
|
|||||||
Executable
+114
@@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
TEST_ROOT="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$TEST_ROOT"' EXIT
|
||||||
|
|
||||||
|
FIXTURE_REPO="$TEST_ROOT/repo"
|
||||||
|
TEST_HOME="$TEST_ROOT/home"
|
||||||
|
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/.claude-plugin"
|
||||||
|
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/skills/references"
|
||||||
|
mkdir -p "$TEST_HOME"
|
||||||
|
cp "$PROJECT_DIR/install-skills.sh" "$FIXTURE_REPO/install-skills.sh"
|
||||||
|
|
||||||
|
write_manifest() {
|
||||||
|
local plugin="$1" name="$2" version="$3" install_type="${4:-skill}"
|
||||||
|
mkdir -p "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin"
|
||||||
|
cat > "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin/plugin.json" <<JSON
|
||||||
|
{"name":"${plugin}-plugin","version":"${version}","install_name":"${name}","install_type":"${install_type}","dir_category":"dev"}
|
||||||
|
JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
write_manifest example example 1.0.0
|
||||||
|
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||||
|
---
|
||||||
|
name: example
|
||||||
|
description: Installer fixture version one.
|
||||||
|
---
|
||||||
|
version one
|
||||||
|
EOF
|
||||||
|
printf 'reference one\n' > "$FIXTURE_REPO/skills-dev/example-plugin/skills/references/guide.md"
|
||||||
|
|
||||||
|
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||||
|
test -f "$TEST_HOME/.agents/skills/example/references/guide.md"
|
||||||
|
|
||||||
|
# A repository version upgrade replaces an unchanged prior install.
|
||||||
|
write_manifest example example 2.0.0
|
||||||
|
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||||
|
---
|
||||||
|
name: example
|
||||||
|
description: Installer fixture version two.
|
||||||
|
---
|
||||||
|
version two
|
||||||
|
EOF
|
||||||
|
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||||
|
grep -q 'version two' "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||||
|
grep -q '"version": "2.0.0"' "$TEST_HOME/.agents/.ai-proj-helper-installed-skills.json"
|
||||||
|
|
||||||
|
# A local edit is preserved even when the repository advances again.
|
||||||
|
printf 'local edit\n' >> "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||||
|
write_manifest example example 3.0.0
|
||||||
|
printf 'repository version three\n' >> "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
|
||||||
|
output="$(HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh")"
|
||||||
|
grep -q 'local files were modified' <<<"$output"
|
||||||
|
grep -q 'local edit' "$TEST_HOME/.agents/skills/example/SKILL.md"
|
||||||
|
if grep -q 'repository version three' "$TEST_HOME/.agents/skills/example/SKILL.md"; then
|
||||||
|
echo 'local modification was overwritten' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Legacy SKILL.md-only installs gain missing repository resources when their
|
||||||
|
# existing content is an unchanged subset of the source.
|
||||||
|
write_manifest legacy legacy 1.0.0
|
||||||
|
mkdir -p "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references"
|
||||||
|
cat > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" <<'EOF'
|
||||||
|
---
|
||||||
|
name: legacy
|
||||||
|
description: Legacy installation fixture.
|
||||||
|
---
|
||||||
|
legacy content
|
||||||
|
EOF
|
||||||
|
printf 'legacy reference\n' > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references/guide.md"
|
||||||
|
mkdir -p "$TEST_HOME/.agents/skills/legacy"
|
||||||
|
cp "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" "$TEST_HOME/.agents/skills/legacy/SKILL.md"
|
||||||
|
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||||
|
test -f "$TEST_HOME/.agents/skills/legacy/references/guide.md"
|
||||||
|
|
||||||
|
# Command manifests become standard Codex skills, while explicit Claude
|
||||||
|
# installs retain the legacy single-file command layout. Both must be stable on
|
||||||
|
# a second run despite the Claude filename change.
|
||||||
|
write_manifest sample-command sample-command 1.0.0 command
|
||||||
|
mkdir -p "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills"
|
||||||
|
cat > "$FIXTURE_REPO/skills-dev/sample-command-plugin/skills/SKILL.md" <<'EOF'
|
||||||
|
---
|
||||||
|
name: sample-command
|
||||||
|
description: Command installation fixture.
|
||||||
|
---
|
||||||
|
command content
|
||||||
|
EOF
|
||||||
|
|
||||||
|
CODEX_TEST_HOME="$TEST_ROOT/codex-home"
|
||||||
|
mkdir -p "$CODEX_TEST_HOME"
|
||||||
|
HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||||
|
test -f "$CODEX_TEST_HOME/.agents/skills/sample-command/SKILL.md"
|
||||||
|
test ! -e "$CODEX_TEST_HOME/.claude/commands/sample-command.md"
|
||||||
|
codex_output="$(HOME="$CODEX_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --dry-run)"
|
||||||
|
grep -q '0 plugins would be installed/updated' <<<"$codex_output"
|
||||||
|
if grep -q 'sample-command: local files were modified' <<<"$codex_output"; then
|
||||||
|
echo 'Codex command skill was reported as modified' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLAUDE_TEST_HOME="$TEST_ROOT/claude-home"
|
||||||
|
mkdir -p "$CLAUDE_TEST_HOME"
|
||||||
|
HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude >/dev/null
|
||||||
|
test -f "$CLAUDE_TEST_HOME/.claude/commands/sample-command.md"
|
||||||
|
claude_output="$(HOME="$CLAUDE_TEST_HOME" "$FIXTURE_REPO/install-skills.sh" --agent claude --dry-run)"
|
||||||
|
grep -q '0 plugins would be installed/updated' <<<"$claude_output"
|
||||||
|
if grep -q 'sample-command: local files were modified' <<<"$claude_output"; then
|
||||||
|
echo 'Claude command was reported as modified after filename conversion' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo 'install-skills tests passed'
|
||||||
@@ -22,6 +22,8 @@ PLUGIN_MAP = {
|
|||||||
"publish-plugin": ("publish", "skill", "core"),
|
"publish-plugin": ("publish", "skill", "core"),
|
||||||
|
|
||||||
# skills-dev
|
# 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-browser-plugin": ("agent-browser", "skill", "dev"),
|
||||||
"agent-swarm-plugin": ("agent-swarm", "skill", "dev"),
|
"agent-swarm-plugin": ("agent-swarm", "skill", "dev"),
|
||||||
"ai-chat-plugin": ("ai-chat", "skill", "dev"),
|
"ai-chat-plugin": ("ai-chat", "skill", "dev"),
|
||||||
@@ -44,6 +46,7 @@ PLUGIN_MAP = {
|
|||||||
"executing-plans-plugin": ("executing-plans", "skill", "dev"),
|
"executing-plans-plugin": ("executing-plans", "skill", "dev"),
|
||||||
"finishing-branch-plugin": ("finishing-a-development-branch","skill", "dev"), # name mismatch!
|
"finishing-branch-plugin": ("finishing-a-development-branch","skill", "dev"), # name mismatch!
|
||||||
"frontend-design-plugin": ("frontend-design", "skill", "dev"),
|
"frontend-design-plugin": ("frontend-design", "skill", "dev"),
|
||||||
|
"karpathy-guidelines-plugin": ("karpathy-guidelines", "skill", "dev"),
|
||||||
"pull-request-plugin": ("pull-request", "skill", "dev"),
|
"pull-request-plugin": ("pull-request", "skill", "dev"),
|
||||||
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
|
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user