Compare commits
14
Commits
ef0e9ca1f0
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ffee89840 | ||
|
|
998b22e905 | ||
|
|
826bba8485 | ||
|
|
f5c5bd3f40 | ||
|
|
4e6ae9036a | ||
|
|
3b38deb078 | ||
|
|
16e58047a0 | ||
|
|
dec25562a4 | ||
|
|
d630b374a3 | ||
|
|
8fc1cd05b7 | ||
|
|
b859a84455 | ||
|
|
9a1400758e | ||
|
|
a58dd1aff3 | ||
|
|
bb5e6be73e |
@@ -401,6 +401,19 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "slark-cicd-plugin",
|
||||
"source": "./skills-dev/slark-cicd-plugin",
|
||||
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
|
||||
"version": "1.1.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-audit-plugin",
|
||||
"source": "./skills-req/req-audit-plugin",
|
||||
@@ -482,8 +495,8 @@
|
||||
{
|
||||
"name": "req-prd-plugin",
|
||||
"source": "./skills-req/req-prd-plugin",
|
||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
||||
"version": "2.0.0",
|
||||
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||
"version": "2.2.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
@@ -495,8 +508,8 @@
|
||||
{
|
||||
"name": "req-prototype-plugin",
|
||||
"source": "./skills-req/req-prototype-plugin",
|
||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
||||
"version": "2.0.0",
|
||||
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||
"version": "2.2.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# ai-proj-helper
|
||||
|
||||
Claude Code 技能市场 + MCP 配置管理工具。
|
||||
Codex 优先、兼容 Claude Code 的 Agent Skills 市场与 MCP 配置管理工具。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
./init.sh
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
交互式配置 MCP 连接(默认 SSE 模式)+ 自动注册技能市场到 `~/.claude/plugins/known_marketplaces.json`。支持命令行参数:
|
||||
默认安装到 Codex 标准目录 `~/.agents/skills`。Claude Code 的 MCP 与 marketplace 初始化使用:
|
||||
|
||||
```bash
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ai-proj-helper — 让 Claude Code 变成你的项目经理
|
||||
# ai-proj-helper — 让 Codex / Claude Code 变成你的项目经理
|
||||
|
||||
> 一套开箱即用的 Claude Code 技能包 + MCP 服务,帮你用自然语言管理需求、写代码、做评审、同步飞书,把 AI 助手变成真正的项目经理。
|
||||
> 一套遵循 Agent Skills 标准的技能包 + MCP 服务,支持 Codex,并兼容 Claude Code。
|
||||
|
||||
## 它能帮你做什么
|
||||
|
||||
@@ -66,7 +66,7 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
|
||||
|
||||
### 前置条件
|
||||
|
||||
- **Claude Code** 已安装([安装指南](https://docs.anthropic.com/en/docs/claude-code/overview))
|
||||
- **Codex**([Skills 文档](https://developers.openai.com/codex/skills))或 **Claude Code** 已安装
|
||||
- **ai-proj 账号 + MCP API Key**:联系管理员获取(Key 格式: `aiproj_pk_xxx`)
|
||||
|
||||
### 一键部署(2 步搞定)
|
||||
@@ -76,18 +76,16 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
|
||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
cd ai-proj-helper
|
||||
|
||||
# 2. 运行初始化(按提示输入 API Key 即可)
|
||||
./init.sh
|
||||
# 2. 默认安装到 Codex 的用户级标准目录 ~/.agents/skills
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
脚本会自动完成:
|
||||
- 配置 MCP 服务器连接(`~/.claude/.mcp.json`)
|
||||
- 注册技能市场到 Claude Code(`~/.claude/plugins/known_marketplaces.json`)
|
||||
- 安装完整技能目录到 `~/.claude/skills/`(包括 references、scripts 和 assets)
|
||||
安装器会复制完整技能目录,包括 `SKILL.md`、references、scripts 和 assets。Codex 会自动发现 `~/.agents/skills` 中的技能;若没有出现,重启 Codex。
|
||||
|
||||
也支持命令行参数跳过交互:
|
||||
Claude Code 用户显式选择 Claude 目标;需要同时配置 MCP 和 marketplace 时运行 `init.sh`:
|
||||
|
||||
```bash
|
||||
./install-skills.sh --agent claude
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
```
|
||||
|
||||
@@ -172,13 +170,17 @@ skills:
|
||||
|
||||
A: 需要先联系管理员获取 MCP API Key(格式 `aiproj_pk_xxx`),然后在提示处输入。
|
||||
|
||||
**Q: 安装后 Codex 没有识别到技能?**
|
||||
|
||||
A: 确认技能位于 `~/.agents/skills/<name>/SKILL.md`,然后重启 Codex。Codex CLI 也可用 `/skills` 查看。
|
||||
|
||||
**Q: 安装后 Claude Code 没有识别到技能?**
|
||||
|
||||
A: 重启 Claude Code 后生效。如果仍不生效,检查 `~/.claude/plugins/known_marketplaces.json` 中是否包含 `ai-proj-helper` 条目。
|
||||
|
||||
**Q: 如何更新到最新版本?**
|
||||
|
||||
A: 进入项目目录执行 `git pull`,然后重新运行 `./init.sh`。
|
||||
A: 进入项目目录执行 `git pull`,然后运行 `./install-skills.sh`;Claude Code 用户增加 `--agent claude`。
|
||||
|
||||
**Q: 如何禁用不需要的技能?**
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Setup Guide
|
||||
# Claude Code Marketplace Setup
|
||||
|
||||
本页只描述 Claude Code marketplace。Codex 用户直接运行 `./install-skills.sh`,技能默认安装到 `~/.agents/skills`。
|
||||
|
||||
## 1. Clone the Gitea Repository
|
||||
|
||||
@@ -114,7 +116,7 @@ ai-proj-helper/
|
||||
- Check plugin name is correct
|
||||
- Ensure marketplace.json is valid: `cat .claude-plugin/marketplace.json | jq`
|
||||
|
||||
**"Skills not working"**
|
||||
**"Skills not working in Claude Code"**
|
||||
- Skills are Agent Skills (auto-invoked by Claude when relevant)
|
||||
- They don't create slash commands
|
||||
- Check plugin installation: `/plugin list`
|
||||
|
||||
+10
-3
@@ -1,6 +1,6 @@
|
||||
# Skill Sync Guide
|
||||
|
||||
仓库中的插件是团队技能的发布源,本机 `~/.claude/skills/` 是安装目标。个人技能保留在
|
||||
仓库中的插件是团队技能的发布源。默认安装目标是 Codex 的用户级标准目录 `~/.agents/skills/`。个人技能保留在
|
||||
`skills-personal/` 或其他本机目录,不会进入公开 marketplace。
|
||||
|
||||
## 从仓库更新本机
|
||||
@@ -11,6 +11,12 @@ git pull
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
Claude Code 需要显式选择目标:
|
||||
|
||||
```bash
|
||||
./install-skills.sh --agent claude
|
||||
```
|
||||
|
||||
安装器会复制完整技能目录,包括 `SKILL.md`、`references/`、`scripts/` 和 `assets/`。它用内容摘要区分仓库升级和本地修改:
|
||||
|
||||
- 目标未修改时,版本升级会自动安装。
|
||||
@@ -23,11 +29,12 @@ git pull
|
||||
```bash
|
||||
./install-skills.sh --list
|
||||
./install-skills.sh --category dev
|
||||
./install-skills.sh --exclude ai-proj-cicd-release
|
||||
```
|
||||
|
||||
## 将本机技能发布到仓库
|
||||
|
||||
不要批量复制整个 `~/.claude/skills/`。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
|
||||
不要批量复制整个 `~/.agents/skills/` 或其他 Agent 的安装目录。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
|
||||
|
||||
1. 选择确实属于本仓库、可供团队复用的技能。
|
||||
2. 在对应 `skills-*/<name>-plugin/` 下放置 `.claude-plugin/plugin.json` 和完整 `skills/` 目录。
|
||||
@@ -51,7 +58,7 @@ git pull
|
||||
|
||||
**本地修改被跳过怎么办?**
|
||||
|
||||
先比较仓库源和 `~/.claude/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。
|
||||
先比较仓库源和 `~/.agents/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。Claude 目标改查 `~/.claude/skills/`。
|
||||
|
||||
**marketplace 没更新?**
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def load_config():
|
||||
def get_category_and_keywords(plugin_name):
|
||||
if any(x in plugin_name for x in ['dev-', 'coding', 'frontend']):
|
||||
return "development", ["development", "coding", "workflow"]
|
||||
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server']):
|
||||
elif any(x in plugin_name for x in ['ops-', 'deploy', 'server', 'slark-cicd']):
|
||||
return "devops", ["devops", "deployment", "operations"]
|
||||
elif any(x in plugin_name for x in ['ai-proj', 'req']):
|
||||
return "productivity", ["project-management", "tasks", "requirements"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# ai-proj-helper 初始化脚本
|
||||
# 配置 MCP 连接 + 安装技能到 ~/.claude/skills/
|
||||
# 配置 Claude MCP 连接 + 安装 Claude 技能
|
||||
|
||||
set -e
|
||||
|
||||
@@ -187,7 +187,8 @@ fi
|
||||
# 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/ ..."
|
||||
"$SCRIPT_DIR/install-skills.sh"
|
||||
"$SCRIPT_DIR/install-skills.sh" --agent claude
|
||||
SKILL_COUNT=$(python3 -c 'import json, os; p=os.path.expanduser("~/.claude/.installed-skills.json"); print(len(json.load(open(p))) if os.path.exists(p) else 0)' 2>/dev/null || echo 0)
|
||||
echo "✅ 技能安装完成"
|
||||
|
||||
# ── Verify MCP connection ────────────────────────────────────────────
|
||||
@@ -250,7 +251,7 @@ if $HAS_CLAUDE; then
|
||||
else
|
||||
echo " ✅ MCP 服务器 → $MCP_CONFIG"
|
||||
fi
|
||||
echo " ✅ 技能 ($SKILL_COUNT 个) → $SKILLS_DIR"
|
||||
echo " ✅ 技能 ($SKILL_COUNT 个) → ~/.claude/skills"
|
||||
echo ""
|
||||
echo "重启 Claude Code 即可使用。"
|
||||
echo "如需更改配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
||||
|
||||
+59
-17
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# install-skills.sh — Cross-machine Claude skill sync from ai-proj-helper
|
||||
# install-skills.sh — Cross-agent skill sync from ai-proj-helper
|
||||
#
|
||||
# Usage:
|
||||
# ./install-skills.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --agent <agent> Install target: codex (default) or claude
|
||||
# --dry-run Preview changes without writing anything
|
||||
# --category <cat> Only install plugins in dir_category=<cat>
|
||||
# Valid values: biz, core, dev, integration, personal, req
|
||||
# --exclude <name> Skip one install_name (repeatable)
|
||||
# --force Overwrite even if local files were modified
|
||||
# --cleanup Remove locally installed skills that are no longer in repo
|
||||
# --list List all available plugins without installing
|
||||
@@ -16,12 +18,14 @@
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_DIR="${HOME}/.claude/skills"
|
||||
COMMANDS_DIR="${HOME}/.claude/commands"
|
||||
STATE_FILE="${HOME}/.claude/.installed-skills.json"
|
||||
SKILLS_DIR=""
|
||||
COMMANDS_DIR=""
|
||||
STATE_FILE=""
|
||||
|
||||
AGENT_TARGET="codex"
|
||||
DRY_RUN=false
|
||||
CATEGORY_FILTER=""
|
||||
EXCLUDED_NAMES=()
|
||||
FORCE=false
|
||||
CLEANUP=false
|
||||
LIST_ONLY=false
|
||||
@@ -43,11 +47,19 @@ dry() { echo -e "${YELLOW}[dry]${RESET} $*"; }
|
||||
# ── Argument parsing ───────────────────────────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--agent)
|
||||
[[ $# -ge 2 ]] || { error "--agent requires codex or claude"; exit 1; }
|
||||
AGENT_TARGET="$2"; shift ;;
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--force) FORCE=true ;;
|
||||
--cleanup) CLEANUP=true ;;
|
||||
--list) LIST_ONLY=true ;;
|
||||
--category) CATEGORY_FILTER="$2"; shift ;;
|
||||
--category)
|
||||
[[ $# -ge 2 ]] || { error "--category requires a value"; exit 1; }
|
||||
CATEGORY_FILTER="$2"; shift ;;
|
||||
--exclude)
|
||||
[[ $# -ge 2 ]] || { error "--exclude requires an install_name"; exit 1; }
|
||||
EXCLUDED_NAMES+=("$2"); shift ;;
|
||||
--help|-h)
|
||||
grep '^#' "$0" | grep -v '!/usr' | sed 's/^# \?//'
|
||||
exit 0 ;;
|
||||
@@ -58,6 +70,24 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
done
|
||||
|
||||
case "$AGENT_TARGET" in
|
||||
codex)
|
||||
# ~/.agents/skills is the current user-level Codex discovery location and
|
||||
# is intentionally agent-neutral. Commands are installed as normal skills.
|
||||
SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.agents/skills}"
|
||||
STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.agents/.ai-proj-helper-installed-skills.json}"
|
||||
;;
|
||||
claude)
|
||||
SKILLS_DIR="${AI_PROJ_HELPER_SKILLS_DIR:-${HOME}/.claude/skills}"
|
||||
COMMANDS_DIR="${AI_PROJ_HELPER_COMMANDS_DIR:-${HOME}/.claude/commands}"
|
||||
STATE_FILE="${AI_PROJ_HELPER_STATE_FILE:-${HOME}/.claude/.installed-skills.json}"
|
||||
;;
|
||||
*)
|
||||
error "Unsupported agent: $AGENT_TARGET (expected codex or claude)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# ── State helpers (plain JSON via python3) ─────────────────────────────────────
|
||||
state_get() {
|
||||
# state_get <install_name> -> prints version or empty string
|
||||
@@ -94,7 +124,7 @@ state_set() {
|
||||
import json,os
|
||||
f='$STATE_FILE'
|
||||
d=json.load(open(f)) if os.path.exists(f) else {}
|
||||
d['$name']={'version':'$ver','install_type':'$itype','content_digest':'$digest'}
|
||||
d['$name']={'version':'$ver','install_type':'$itype','content_digest':'$digest','agent':'$AGENT_TARGET'}
|
||||
json.dump(d,open(f,'w'),indent=2)
|
||||
" 2>/dev/null
|
||||
}
|
||||
@@ -149,7 +179,9 @@ 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:
|
||||
relative = path.name if target.is_file() else path.relative_to(target).as_posix()
|
||||
# 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():
|
||||
@@ -222,6 +254,11 @@ install_plugin() {
|
||||
dir_category="$(read_field "$json_path" dir_category)"
|
||||
version="$(read_field "$json_path" version)"
|
||||
|
||||
local excluded
|
||||
for excluded in ${EXCLUDED_NAMES[@]+"${EXCLUDED_NAMES[@]}"}; do
|
||||
[[ "$install_name" == "$excluded" ]] && return
|
||||
done
|
||||
|
||||
# Skip if no install metadata (legacy plugin without our new fields)
|
||||
if [[ -z "$install_name" || -z "$install_type" ]]; then
|
||||
warn "$(basename "$plugin_dir"): missing install_name/install_type, skipping"
|
||||
@@ -239,8 +276,13 @@ install_plugin() {
|
||||
return
|
||||
fi
|
||||
|
||||
local effective_install_type="$install_type"
|
||||
if [[ "$AGENT_TARGET" == "codex" ]]; then
|
||||
effective_install_type="skill"
|
||||
fi
|
||||
|
||||
if [[ "$LIST_ONLY" == true ]]; then
|
||||
echo " [$dir_category] $install_type:$install_name v$version"
|
||||
echo " [$dir_category] $effective_install_type:$install_name v$version"
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -250,7 +292,7 @@ install_plugin() {
|
||||
src_dir="$(resolve_skills_src "$skills_dir")"
|
||||
|
||||
local source_path target_path
|
||||
if [[ "$install_type" == "command" ]]; then
|
||||
if [[ "$effective_install_type" == "command" ]]; then
|
||||
source_path="$src_dir/SKILL.md"
|
||||
target_path="$COMMANDS_DIR/${install_name}.md"
|
||||
else
|
||||
@@ -274,13 +316,13 @@ install_plugin() {
|
||||
|
||||
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" "$install_type" "$source_digest"
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
local legacy_subset=false
|
||||
if [[ "$install_type" == "skill" && -z "$recorded_digest" && -n "$target_digest" ]]; then
|
||||
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
|
||||
@@ -294,7 +336,7 @@ install_plugin() {
|
||||
fi
|
||||
|
||||
# Perform install
|
||||
if [[ "$install_type" == "command" ]]; then
|
||||
if [[ "$effective_install_type" == "command" ]]; then
|
||||
# Single-file command → ~/.claude/commands/<name>.md
|
||||
local src_md="$src_dir/SKILL.md"
|
||||
if [[ ! -f "$src_md" ]]; then
|
||||
@@ -308,13 +350,13 @@ install_plugin() {
|
||||
else
|
||||
mkdir -p "$COMMANDS_DIR"
|
||||
cp "$src_md" "$COMMANDS_DIR/${install_name}.md"
|
||||
state_set "$install_name" "$version" "$install_type" "$source_digest"
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
ok "$install_name → command (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
|
||||
else
|
||||
# Skill directory → ~/.claude/skills/<name>/
|
||||
# Standard skill directory → the selected agent's discovery root.
|
||||
local dst_dir="$SKILLS_DIR/$install_name"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
@@ -323,8 +365,8 @@ install_plugin() {
|
||||
else
|
||||
mkdir -p "$dst_dir"
|
||||
# rsync resolved source (handles nested skills/ structures)
|
||||
rsync -a --delete "$src_dir/" "$dst_dir/"
|
||||
state_set "$install_name" "$version" "$install_type" "$source_digest"
|
||||
rsync -a --checksum --delete "$src_dir/" "$dst_dir/"
|
||||
state_set "$install_name" "$version" "$effective_install_type" "$source_digest"
|
||||
ok "$install_name → skill (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
@@ -387,7 +429,7 @@ main() {
|
||||
return
|
||||
fi
|
||||
|
||||
info "Installing Claude skills from: $REPO_DIR"
|
||||
info "Installing skills for $AGENT_TARGET from: $REPO_DIR"
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
|
||||
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "slark-cicd-plugin",
|
||||
"description": "Slark 仓库 staging、生产与 Desktop 安装包的端到端 CI/CD 发布技能。",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "slark-cicd",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
name: slark-cicd
|
||||
description: Slark 仓库 staging、生产和 Desktop 安装包的端到端 CI/CD 可执行 runbook。覆盖本地预推快检、PR 与内网 ci/internal-gate 门禁、合并 origin/main、生产前强制 staging 验收、审批式生产发布,以及在 m5max 构建签名、公证并上传 macOS/Windows Desktop 包到 OSS。当用户要在 slark(qiudl/qiu-slark)里发布/上线、部署到生产或 staging、发布 Desktop 安装包、盯 CI/合并 PR、复现或验证运行时行为、或排查发布链/推送路由问题时使用。
|
||||
---
|
||||
|
||||
# Slark CI/CD runbook
|
||||
|
||||
驱动 Slark 从改代码到上线的端到端流程。权威流程与完整细节见仓库文档
|
||||
`docs/cicd-staging-production.md`(本技能命令与之一致);本文件是可直接照做的分阶段清单。
|
||||
|
||||
仓库:`qiudl/qiu-slark`(本机克隆通常在 `/Users/donglinlai/coding/slark`)。所有命令在**仓库根**执行。
|
||||
`ai-proj` 相关命令加 `GODEBUG=netdns=go` 前缀。
|
||||
|
||||
## 铁律(先记死)
|
||||
|
||||
- GitHub `origin/main` 是唯一代码权威、合并入口与生产发布来源;`internal` 只用于 CI/镜像,永不发布。
|
||||
- 生产发布只接受**最新 `origin/main` 的精确 40 位 SHA**;`HEAD != origin/main` 会被 `deploy.sh` 拒绝。
|
||||
- 生产发布必须在**普通 clone** 中执行,且 `.git` 必须是目录;`release-prod.sh` / `deploy.sh` 会拒绝
|
||||
`.git` 为指针文件的 git worktree。不要污染现有 checkout:主目录脏或被占用时,新建干净的临时 clone。
|
||||
- **生产发布前必须先发布并验收 staging,不得跳过**:同一最新 `origin/main` 精确 SHA 必须先完成迁移演练、
|
||||
staging 正式部署、隔离检查和需求功能验收。把证据报告给用户后,必须再次取得明确的生产确认;开始 staging
|
||||
前获得的生产授权不能替代这次确认。未通过、未完成或用户未确认时停止,不得执行生产发布命令。
|
||||
- 审批式部署,永不自动:亲手敲的 `sudo`/`rm -rf`/`dd`/`curl|sh`/包安装是 `destructive`(NEVER_AUTO),
|
||||
**每次都要人审**;命中审批闸就**等人批**,绝不绕过、绝不把这些 key 加进 auto-approve 白名单。
|
||||
- staging 与生产硬隔离:staging 脚本带生产 IP 拒运行护栏、不 push origin、不反向 rsync。
|
||||
- 当前 Slark staging 权威目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`
|
||||
(Name=`slark-staging`,2026-08-18 核验公网 IP `15.135.112.181`)。公网 IP 自动分配,发布前必须按
|
||||
实例 ID 重查并确认 Name/状态;不得凭历史 IP 判断目标。
|
||||
- `82.157.141.202` 是 ai-proj 预生产宿主机。其 `/opt/slark-staging` cohost 是隔离的 Slark 兼容验收栈,
|
||||
但不是 Slark 独立预生产;只有任务明确指定 cohost 时才能使用,不得作为普通 Slark staging 的默认目标。
|
||||
- staging 发布若影响 `packages/daemon`、`packages/runtime`、Server/daemon 公共协议或 Desktop 公共运行链,
|
||||
必须把 `server-staging` 与 `daemon-staging` 更新到同一精确 SHA;两者版本不一致不得宣告 staging 成功。
|
||||
- 只修 PR 范围内的 CI 失败;不为过检去改 CI/workflow 或做无关改动。
|
||||
|
||||
## 选择链路
|
||||
|
||||
- 「发布/上线/部署生产」→ 生产发布链:阶段 1→2→3(同 SHA staging 验收)→ 人工确认 →4→5。
|
||||
- 「Desktop/桌面版打包、发布、上传 OSS」→ 阶段 1→2 后走 `docs/desktop-oss-release.md` 的 m5max 双平台链路。
|
||||
- 「盯 CI/合并 PR」→ 阶段 1→2(用 babysit 心态循环到 green + mergeable + 评论收口)。
|
||||
- 「复现/验证运行时行为、别碰生产」→ staging 预验链(阶段 3,可独立随时跑)。
|
||||
|
||||
## 阶段 1:PR 与内网 gate(`ci/internal-gate`)
|
||||
|
||||
真实门禁是内网 CI(GitHub Actions 已停用)。检查与自查:
|
||||
|
||||
```bash
|
||||
gh pr checks <PR> # 应见 ci/internal-gate
|
||||
gh pr view <PR> --json state,mergeable,mergeStateStatus,isDraft,reviewDecision
|
||||
```
|
||||
|
||||
- 基础门(全 PR):release-contract / member-gate / authz-matrix / controlled-content-exits /
|
||||
onconflict-predicate / migration-idempotency / wsl-path-translation / typecheck / test(全量)。
|
||||
- 条件外部门(按改动路径):改 server DB/迁移/schema → `postgresql-security`;改 web → `web-e2e`;
|
||||
android / daemon+desktop 各有门。
|
||||
- 本地复跑基础门可跑部分:`pnpm -r typecheck && pnpm test`。
|
||||
|
||||
红了:只修本 PR 范围内的失败。疑似无关的合并阻塞→先 merge 最新 `main`(可能别的 PR 已修)。
|
||||
`BLOCKED: <label> requires <VAR>` = runner 环境未配外部门命令,属运维问题,不是 PR 代码问题。
|
||||
|
||||
## 阶段 2:合并到 `origin/main`
|
||||
|
||||
合并前确认:`mergeable=MERGEABLE`、`mergeStateStatus=CLEAN`、非 draft、`ci/internal-gate` 绿、评论收口。
|
||||
|
||||
```bash
|
||||
gh pr merge <PR> --merge # 仓库风格:merge commit
|
||||
```
|
||||
|
||||
若本机 `main` 被其他 worktree 占用导致 `--delete-branch` 本地 checkout 失败(属本地副作用):
|
||||
|
||||
```bash
|
||||
gh pr view <PR> --json state,mergedAt,mergeCommit # 确认 GitHub 侧 MERGED
|
||||
git push origin --delete <feature-branch> # 删远端
|
||||
git branch -D <feature-branch> # 删本地(先切走)
|
||||
```
|
||||
|
||||
## 阶段 3:staging 真机预验(生产前强制,也可独立运行)
|
||||
|
||||
生产候选必须使用最新 `origin/main` 的同一精确 SHA。先执行迁移演练,再正式部署;随后完成隔离检查和本次需求的
|
||||
功能验收。验收不能只看通用 health:凡需求涉及真实集成(如飞书 OAuth),staging 缺少对应 provider/凭据时必须
|
||||
明确标为未完成并停止生产链,除非用户在看到该限制后明确接受。完成后报告目标实例、SHA、Server/Daemon revision、
|
||||
迁移演练、健康、隔离和功能结果,并等待用户再次确认是否进入生产。
|
||||
|
||||
### 3.1 当前权威路径:Slark 独立 staging
|
||||
|
||||
稳定目标是 AWS `ap-southeast-2` 实例 `i-013e5ca3fdfddc13e`(Name=`slark-staging`)。它使用自动分配
|
||||
公网 IP,因此每次部署前先查询当前 IP;2026-08-18 核验值为 `15.135.112.181`:
|
||||
|
||||
```bash
|
||||
aws ec2 describe-instances --region ap-southeast-2 \
|
||||
--instance-ids i-013e5ca3fdfddc13e \
|
||||
--query 'Reservations[0].Instances[0].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name,PublicIp:PublicIpAddress}' \
|
||||
--output table
|
||||
|
||||
export STAGING_SSH_KEY=~/.ssh/cloud-server-syd.pem
|
||||
export STAGING_REMOTE=ubuntu@15.135.112.181
|
||||
export STAGING_REMOTE_IP=15.135.112.181
|
||||
export STAGING_BASE=http://15.135.112.181
|
||||
|
||||
scripts/deploy-staging.sh --migrate-dry-run
|
||||
scripts/deploy-staging.sh
|
||||
STAGING_TOKEN=$(cat /tmp/.staging_token) scripts/staging-seed.sh
|
||||
scripts/staging-verify-isolation.sh
|
||||
```
|
||||
|
||||
不得把查询到的 Name 非 `slark-staging` 的机器当作目标。四件套细节与环境隔离约束见
|
||||
`docs/req-20260811-0059-staging-environment-design.md`。
|
||||
|
||||
### 3.2 非权威路径:ai-proj cohost(仅明确指定时)
|
||||
|
||||
ai-proj cohost 位于 `ubuntu@82.157.141.202:/opt/slark-staging`。全程使用隔离数据、数据库、密钥和状态目录,
|
||||
但宿主机身份仍是 ai-proj staging;普通“Slark 预生产”不得走这里。仅在任务明确要求 cohost 兼容验收时,
|
||||
先在**干净的独立 worktree**检出待验精确 SHA,再执行:
|
||||
|
||||
```bash
|
||||
STAGING_SSH_KEY=~/.ssh/ai_proj_stg.pem \
|
||||
STAGING_KNOWN_HOSTS_FILE=~/.ssh/known_hosts \
|
||||
STAGING_REMOTE=ubuntu@82.157.141.202 \
|
||||
STAGING_REMOTE_IP=82.157.141.202 \
|
||||
scripts/deploy-staging-cohost.sh
|
||||
```
|
||||
|
||||
如果改动影响 daemon/runtime/公共协议,还需用 Compose `daemon` profile 更新 `daemon-staging`,并核对
|
||||
Server/daemon revision 同为待验 SHA。
|
||||
|
||||
### 3.3 环境选择检查
|
||||
|
||||
普通 Slark staging 默认走 3.1;只有用户或需求明确说“ai-proj cohost”才走 3.2。任何验收都必须记录:
|
||||
环境稳定身份、当次 IP、待验 40 位 SHA、Server/daemon revision/status、Server health 和目标功能结果。
|
||||
|
||||
routed-remote 要 `network=enabled` 必须同时满足:① agent `workspace_access=write` +
|
||||
`repository_access=write`;② per-agent 工作区是可写 git worktree。细节见
|
||||
`docs/req-20260811-0059-staging-environment-design.md`。staging 刻意不碰 `deploy.sh` 的生产闸门。
|
||||
|
||||
## 阶段 4:生产发布(审批式)
|
||||
|
||||
**前置门禁**:阶段 3 已对同一 SHA 完成 staging 部署和验收,证据已报告,且用户在报告之后明确确认生产发布。
|
||||
缺任一项即停止;不得把 PR 合并授权、较早的生产授权或单纯的“继续”视为验收后确认。
|
||||
|
||||
**唯一姿势**:从干净的普通 clone 发布最新 `origin/main`(`HEAD == origin/main` 精确 SHA)。staging 可用
|
||||
独立 worktree,但生产脚本为保证同步与发布边界,会拒绝 worktree;不要在用户已有脏 checkout 中清理或发布。
|
||||
|
||||
```bash
|
||||
# 若当前仓库不是普通 clone,先在安全父目录创建一次性干净 clone:
|
||||
git clone https://github.com/qiudl/qiu-slark.git <clean-production-clone>
|
||||
cd <clean-production-clone>
|
||||
|
||||
git fetch origin main
|
||||
test -d .git # 必须通过;worktree 的 .git 是文件
|
||||
git status --porcelain # 必须干净
|
||||
git checkout --detach "$(git rev-parse origin/main)" # 在产品分支上时先 detach 到该 SHA
|
||||
|
||||
pnpm release:prod # = release-prod.sh → deploy.sh --backend --no-install --no-mirror
|
||||
# 备选:scripts/deploy.sh --pull --backend
|
||||
```
|
||||
|
||||
- `deploy.sh` 用 `check-production-release-sha.sh` 锁 `HEAD == origin/main` SHA,不符即拒。
|
||||
- `--backend` 才跑迁移:owner 连接(DDL 权)与运行时 `slark_app`(DML-only)分离;幂等、失败即非零。
|
||||
- 命中审批闸(发布/sudo)→ **等人批**;不要绕。脚本内部 SSH 载荷子进程的 sudo 不触发闸。
|
||||
- 普通工作 clone 发布完切回原分支:`git checkout <branch>`;一次性发布 clone 可保留作审计,清理时用可恢复方式。
|
||||
|
||||
### HANDOFF_BLOCKED 恢复入口
|
||||
|
||||
发布准备遇到 `HANDOFF_BLOCKED`、handoff manifest=`failed_closed` 或命令状态不确定时,停止发布切换;禁止靠重跑
|
||||
发布脚本、直接改表或默认 replay 来“解卡”。先把 manifest、命令、execution、lease/outbox 和审计证据做只读盘点,
|
||||
再让用户明确授权每条记录的 reconciliation action/outcome 及是否允许继续发布。恢复细节见
|
||||
[references/production-handoff-recovery.md](references/production-handoff-recovery.md);仅遇到该类事故时读取。
|
||||
|
||||
`COMMAND_AUTHORITY_CHANGED` 是有效并发护栏,不是可忽略错误:重新读取当前 authority/transport/execution generation,
|
||||
确认期间没有新活动,再在原授权范围内幂等续办。若发现新工作、活跃 lease/outbox 或无法解释的副作用,立即停止并
|
||||
重新请求决策。
|
||||
|
||||
## 阶段 5:发布后核查
|
||||
|
||||
```bash
|
||||
scripts/verify-deploy.sh # 健康(前端/api/health=200)、bundle、server/daemon SHA、迁移集、federation、凭据
|
||||
```
|
||||
|
||||
预期 `✓ deploy verification passed: server=<sha> daemon=<sha>` 且 `<sha> == origin/main`,舰队 `online ≥ 发布前`。
|
||||
完成前还要独立复核 governed release 账本为 `succeeded/complete`、四组件实际 SHA 均为目标 SHA、租约已释放、
|
||||
新 handoff manifest=`verified`;若本次处理过旧 manifest,还要核对其全部 case 已达授权终态且 replay 数为 0。
|
||||
|
||||
默认生产包装器使用 `--no-mirror`:构建 daemon candidate binary 用于运行态验证不等于上传镜像资产。镜像落后告警
|
||||
在该模式下是预期的非阻断结果;不得未经单独授权补传镜像。交付说明要明确国内安装器可能回退 upstream,避免把
|
||||
本地构建、生产 daemon 更新和镜像上传混为一谈。
|
||||
|
||||
## Desktop m5max 双平台发布
|
||||
|
||||
Desktop 安装包不走 Server 生产部署脚本。权威流程见仓库 `docs/desktop-oss-release.md`,已验证基线为
|
||||
REQ-20260819-0005 / Desktop 0.3.1:
|
||||
|
||||
- 版本 PR 通过 `ci/internal-gate` 并合并后,m5max 从最新 `origin/main` 精确 SHA 的干净普通 clone 构建。
|
||||
- m5max 原生构建、Developer ID 签名并公证/staple macOS DMG/ZIP;交叉构建 Windows x64 NSIS EXE。
|
||||
- Darwin 不能执行 Windows 原生 `smoke:windows`。只有发布负责人明确接手 Windows 原生验收时才能继续交叉打包,交付证据必须标注该边界。
|
||||
- 资产不回传开发机;由 m5max 直接上传 `xiaoqu-public-file/slark/desktop/releases/v<version>/`,manifest 最后更新。
|
||||
- `xiaoqu-public-file` 的 canonical 凭证源是发布控制机上的 `/Users/donglinlai/coding/param.rxt`(必须为 `0600`);AK/SK 分别位于 XML 标签 `ossAccessKeyId` / `ossAccessKeySecret`。不得改猜 Bitwarden、Keychain、通用 `credentials.env` 或 m5max 本地配置;只有该文件缺失、权限不符或标签解析为空时才停止并报告。
|
||||
- m5max 不持久化 OSS 凭证。发布控制机从 `param.rxt` 提取 AK/SK 后,只用 `printf '%s\n%s\n' ... | ssh m5max ...` 经 SSH stdin 传两行;远端用 `read -r` 接收并仅为当次 shell 导出 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`,随后运行上传脚本。禁止 `scp` 凭证文件、写远端临时文件或把值打印到日志。
|
||||
- m5max 非交互 SSH 必须显式补 `PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH`;已验证 `ossutil` 位于 `/Users/johnq/.local/bin/ossutil`。执行前检查 Node、三个安装包、精确 main SHA 和干净工作树,避免因交互 shell 环境差异重新猜路径。
|
||||
- m5max 默认出口若走 `utun`,只为当次 `ossutil` 使用 `--bind-address "$(ipconfig getifaddr en0)"`,不得修改整机 Tailscale/默认路由。
|
||||
- 完成前核对三份资产 SHA256/大小、macOS 签名与公证、公开 URL/manifest,并回写 ai-proj 证据。
|
||||
|
||||
## 推送路由自查(换机器/新克隆必做)
|
||||
|
||||
```bash
|
||||
git remote -v # origin 收发都应是 https://github.com/qiudl/qiu-slark.git
|
||||
git config --get-regexp '^url\.' # 有输出 = pushInsteadOf 改写,push 可能被静默重定向到内网
|
||||
scripts/git-release-governance.sh check-local
|
||||
scripts/git-release-governance.sh status
|
||||
```
|
||||
|
||||
## 故障分流
|
||||
|
||||
| 现象 | 处置 |
|
||||
| --- | --- |
|
||||
| `release-prod` 拒绝 HEAD≠origin/main | `git fetch origin main` 后 detach 到 origin/main SHA,工作树须干净 |
|
||||
| `release-prod` 拒绝 git worktree / `.git` 不是目录 | 改用干净的普通 clone,锁定最新 `origin/main`;不要在现有脏 checkout 中强行切换 |
|
||||
| `ci/internal-gate` red | 看 gate 分组日志找 FAIL 项;`pnpm -r typecheck && pnpm test` 本地复现修复 |
|
||||
| `BLOCKED: <label> requires <VAR>` | runner 未配外部门命令,报运维配 `SLARK_CI_*_CMD`,非 PR 问题 |
|
||||
| 合并阻塞但与 PR 无关 | merge 最新 `main` 再看 |
|
||||
| push 成功但 GitHub 没有 | 查 `git config --get-regexp '^url\.'`,移除 pushInsteadOf 或显式指定 GitHub URL |
|
||||
| staging routed-remote 恒断网 | 查两道放网杠杆(workspace_access=write + 可写 git worktree) |
|
||||
| cohost Server 已更新但 daemon 仍是旧 SHA | 用 `--profile daemon up -d daemon-staging` 更新 daemon;核对两容器 revision 后才算完成 |
|
||||
| cohost daemon 启动即退出/fatal | 看 `docker logs slark_daemon_staging`;修复凭据/环境或版本契约,禁止用旧 daemon 冒充验收通过 |
|
||||
| verify 失败 SHA 不符 | 部署到了旧码,重发 |
|
||||
| `HANDOFF_BLOCKED` / manifest=`failed_closed` | 停止切换并读取 handoff recovery 参考;只读盘点后取得逐项 action/outcome 授权,禁止默认 replay |
|
||||
| reconciliation 返回 `COMMAND_AUTHORITY_CHANGED` | 查当前 generation 与新活动;无新活动才在原授权内幂等续办,有变化则停止重新决策 |
|
||||
| `--no-mirror` 后提示镜像落后 | 预期非阻断;报告 upstream fallback,未经单独授权不上传镜像 |
|
||||
| 生产授权已给但 staging 尚未验收 | 先完成同 SHA staging 全量验收,报告证据并重新等用户确认;不得沿用较早授权 |
|
||||
| staging 缺少需求依赖的真实集成配置 | 将对应验收标为未完成并停止生产链;补齐配置后重验,或让用户基于明确限制作决定 |
|
||||
|
||||
## ai-proj 流程(强制)
|
||||
|
||||
任何改产品/代码行为的工作,动手前先在 ai-proj 立项 + 建 Task + 关联,实现/测试/交付回写;
|
||||
commit/PR 引用 `REQ-...`。纯文档/工具/只读排查除外。详见仓库 `AGENTS.md` / `CLAUDE.md`。
|
||||
@@ -0,0 +1,70 @@
|
||||
# Production handoff recovery
|
||||
|
||||
仅在生产发布被 coding-session handoff 阻塞、manifest 进入 `failed_closed`,或存在 `needs_review` / 不确定命令时读取。
|
||||
目标是保留 fail-closed 语义,在明确授权下终结歧义状态,并证明没有误重放命令。
|
||||
|
||||
## 先冻结发布,不先解锁
|
||||
|
||||
- 停止发布切换和自动重试;记录 release ID、候选 SHA、manifest ID、阻塞发生阶段与原始错误。
|
||||
- 不把“继续”“再试一次”解释为 replay、force-end 或生产发布授权。向用户展示证据后,确认语句应绑定 manifest、
|
||||
条目数量或 command ID、目标 action/outcome、是否禁止 replay,以及要继续发布的精确 SHA。
|
||||
- 不直接更新 handoff、command、execution 表来改变状态。优先走已部署版本的内部治理 API;只有 API 无法恢复且
|
||||
已获得对应操作授权时,才可调用该版本现有 domain repository,并保留 lifecycle event 与 audit log。
|
||||
|
||||
## 只读证据盘点
|
||||
|
||||
对 manifest 中每条 item 核对并保存摘要:
|
||||
|
||||
- command ID、session/project/computer ID、command status、execution state;
|
||||
- manifest 记录的 authority term、transport generation、execution generation,以及当前实际值;
|
||||
- command/execution lease 是否过期,outbox 是否仍有 active/pending 记录;
|
||||
- session 中是否还有其他活跃命令或新事件;
|
||||
- daemon acknowledgement、result/receipt、审计事件是否能证明执行或未执行。
|
||||
|
||||
若 lease/outbox 仍活跃、存在新命令、证据相互矛盾,或无法排除外部副作用,停止恢复并请求新的人工判断。
|
||||
|
||||
## Action 与 outcome 必须匹配证据
|
||||
|
||||
- `no_action / not_executed`:只有权威证据能证明命令从未执行,且治理接口允许该组合时使用。
|
||||
- `terminate / terminated`:用于显式受控终结仍处于 uncertain/active 语义的命令;先通过 domain 操作取消 command、
|
||||
force-end execution、完成 session 并写审计,再完成 reconciliation,不产生 replay。
|
||||
- `mark_failed / failed`:证据确认失败、且不能安全恢复为成功或未执行时使用。
|
||||
- `replay / replayed_success`:仅在用户明确授权 replay 且 exactly-once/幂等边界得到证明时使用。发布解卡绝不能默认 replay。
|
||||
|
||||
不要为了迎合预先选择的 outcome 忽略现场证据;如果授权与可证明事实不兼容,停止并把差异报告给用户。
|
||||
|
||||
## 受治理恢复顺序
|
||||
|
||||
1. 使用精确 manifest/item 建立或读取 reconciliation case。
|
||||
2. 取得具备 action、evidence digest、operator 和有效期约束的审批。
|
||||
3. 记录 decision;执行 domain 终结或治理 apply;随后用权威运行态证据 confirm terminal outcome。
|
||||
4. 若 apply 返回 `COMMAND_AUTHORITY_CHANGED`,不要覆盖或绕过。重新读取当前三类 generation 和新活动:
|
||||
- generation 只因刚完成的受控终结而变化,且无新命令、lease/outbox 时,可在同一授权 action 下幂等续办;
|
||||
- generation 对应新工作或原因不明时,停止并重新审批。
|
||||
5. 每个 item 都 terminal 后,确认 manifest 自动或受治理地进入 `reconciled`,再启动新的发布尝试。
|
||||
|
||||
凭据失败发生在事务前时应视为零变更并记录。不要反复猜测 owner 凭据;不得打印连接串或密钥。若必须使用运行时
|
||||
`slark_app` 连接,只能通过已部署 domain repository、正确的 per-transaction project/user RLS context 和审计路径操作。
|
||||
|
||||
## 零重放与发布恢复验收
|
||||
|
||||
恢复完成至少证明:
|
||||
|
||||
- `terminalCount == totalCount`,每条 decision action 与 terminal outcome 等于用户授权;
|
||||
- 禁止 replay 的场景下,decision action=`replay` 数和 execution replay attempt 增量均为 0;
|
||||
- `terminate/terminated` 场景下,command=`cancelled`、execution=`force_ended`,并存在对应 lifecycle/audit 证据;
|
||||
- 旧 manifest=`reconciled`,没有 active handoff reservation 残留。
|
||||
|
||||
继续生产发布时使用新 governed release / handoff manifest,不复用 failed-closed manifest。重新检查候选仍是最新
|
||||
`origin/main`、同 SHA staging eligibility receipt 仍有效、工作树干净;任何一项变化都回到 staging 与人工确认门禁。
|
||||
|
||||
发布成功后再独立执行一次 `scripts/verify-deploy.sh`,并只读核对:release=`succeeded/complete`、target/actual Web、
|
||||
Server、daemon、artifact SHA 全相等、lease 已释放、finished 已记录、新 manifest=`verified`、舰队在线数不低于基线。
|
||||
将旧 manifest reconciliation 与新发布证据一起回写 ai-proj。
|
||||
|
||||
## `--no-mirror` 的解释边界
|
||||
|
||||
- `pnpm release:prod` 默认走 `deploy.sh --backend --no-install --no-mirror`;不上传 daemon 镜像资产。
|
||||
- 发布过程仍可能在隔离 candidate 目录构建 daemon binary,用于同 SHA 验证或部署运行态 daemon;这不是镜像上传。
|
||||
- mirror freshness 告警表示镜像源仍旧,国内安装器可能回退到较慢 upstream。它不阻断当前生产运行态发布。
|
||||
- 补传 mirror 是单独的外部写操作,需要单独授权和凭据;不能为了消除告警在发布收尾时顺手执行。
|
||||
@@ -322,6 +322,59 @@ npm run lint
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 既有契约与读模型迁移门禁(必须)
|
||||
|
||||
> **惨痛教训**:新写链路把真实数据写入新表,旧 API 仍读原表,前端虽然没改却从此看不到新数据。“后端已成功执行”不等于“用户能看到执行结果”。
|
||||
|
||||
开发计划涉及新表、新账本、新写路径、替换存储模型或接口版本时,必须先完成以下门禁。未通过时,不得把“新建平行表/新建平行 API”写成默认方案。
|
||||
|
||||
### 1. 先证明旧模型不能复用
|
||||
|
||||
- [ ] 已检查现有表、字段、索引、状态机和扩展字段(如 metadata/JSON)。
|
||||
- [ ] 已说明为什么增加字段、子表或现有类型无法满足需求。
|
||||
- [ ] 新表承载的是真正独立的实体或生命周期,而不是为同一业务实体建立第二个彼此脱节的世界。
|
||||
- [ ] 已区分“内部不可变证据/事件账本”和“产品对外读模型”;新建内部账本不代表必须更换原有产品接口。
|
||||
|
||||
### 2. 真实调用方查证
|
||||
|
||||
必须从对外接口向所有消费方反向追踪,不能只审查新后端写路径:
|
||||
|
||||
- [ ] 列出现有 API 路径、请求参数、响应结构和身份/分页语义。
|
||||
- [ ] 使用 `rg` 查找 Web、iOS、Android、定时任务、报表和第三方调用方。
|
||||
- [ ] 若仓库存在 `.codex-fe-ref/`,必须在其中查证配套前端的真实调用。
|
||||
- [ ] 开发计划的变更文件清单必须覆盖“写入 → 投影/查询 → API → 页面”完整链路。
|
||||
|
||||
### 3. 稳定契约默认不变
|
||||
|
||||
- 既有用户界面已消费的 API,默认保留路径和响应契约;除非用户明确批准破坏性迁移,不得通过新建版本接口把兼容成本转嫁给前端。
|
||||
- 同一业务概念只保留一个产品级读模型。内部账本可以拆分,但必须投影回既有读模型,或由原 API 无感聚合。
|
||||
- 日志、告警、信号或推测数据不得在查询降级时冒充业务事实(例如把 warning 当成交易记录)。
|
||||
|
||||
### 4. 不可避免新写模型时的强制迁移计划
|
||||
|
||||
若确有独立生命周期、不可变审计或 1:N/N:N 证据需求,可以增加新表,但开发计划必须同时包含:
|
||||
|
||||
1. **写入兼容**:双写,或从新账本向既有读模型做事务性/幂等投影。
|
||||
2. **历史回填**:有界、可恢复、可重跑,且不猜测无法证明的归属。
|
||||
3. **去重身份**:定义跨旧/新数据源的稳定业务键,并用数据库唯一约束或等价强保证防重。
|
||||
4. **读取切换**:定义何时以新证据为准、旧数据如何兼容,以及结果数量/金额/状态对账门槛。
|
||||
5. **回滚策略**:回滚新写入时仍能读取已产生的真实业务事实,不删除或隐藏已成功数据。
|
||||
6. **可观测性**:监控新写入成功但旧读模型缺失、投影延迟、去重冲突和回填差异。
|
||||
|
||||
### 5. 用户可见性是必须验收项
|
||||
|
||||
测试不得只证明“新写路径成功”。至少要有一个真实业务记录贯穿测试,同时证明:
|
||||
|
||||
- [ ] 新写路径产生了正确事实。
|
||||
- [ ] 原有对外 API 可以立即或在约定 SLA 内返回该记录。
|
||||
- [ ] 每个真实消费页面/客户端都能正确解码并展示。
|
||||
- [ ] 时间、方向、状态、数量、金额与唯一标识在数据库、API 和 UI 之间一致。
|
||||
- [ ] 部分失败、重试、重复投递、迟到数据和回滚后仍不丢数、不重复、不冒充。
|
||||
|
||||
开发计划必须把上述内容落成明确的变更文件、任务、测试用例和发布门禁,不得只在“风险”章节留一句提醒。
|
||||
|
||||
---
|
||||
|
||||
## 开发计划文档模板
|
||||
|
||||
```markdown
|
||||
@@ -1695,3 +1748,4 @@ migrate -path migrations -database "postgres://..." up
|
||||
|------|------|----------|--------|
|
||||
| V1.0 | 2026-01-26 | 初始版本,创建 req-dev 技能 | Claude + qiudl |
|
||||
| V1.1 | 2026-01-29 | 添加 iOS 端开发规范(SwiftUI + MVVM 架构) | Claude Opus 4.5 |
|
||||
| V1.2 | 2026-08-26 | 新增既有契约与读模型迁移强制门禁,防止新写链路与原 API/前端脱节 | Codex |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "req-prd-plugin",
|
||||
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
|
||||
"version": "2.0.0",
|
||||
"description": "产品需求设计技能。覆盖问答、PRD、缺陷与 OSS 原型闭环,文档双写本地和 ai-proj。",
|
||||
"version": "2.2.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: req-prd
|
||||
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
|
||||
description: 产品设计与需求管理。用于 PRD、需求分析、用户故事、功能设计和原型规划,并将正式需求文档双写到本地仓库与 ai-proj Task Document。
|
||||
---
|
||||
|
||||
# 产品需求设计 Skill (req-prd)
|
||||
@@ -16,7 +16,66 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
||||
|
||||
**插件扩展**:
|
||||
- `req-compare` — 对比式 PRD 编写(系统平移/竞品借鉴时激活)
|
||||
- `req-prototype` — UI 原型生成
|
||||
- `req-prototype` — UI 模块在 PRD/缺陷收敛后生成、上传并关联 HTML 原型
|
||||
- `defect-analysis` — 设计访谈确认后,对最新版 PRD 反复审计和修订直至收敛
|
||||
|
||||
## 产品需求文档双写门禁
|
||||
|
||||
本技能创建或修改的所有正式需求文档都必须同时保存到:
|
||||
|
||||
1. 当前产品仓库的本地 Markdown 文件;
|
||||
2. Requirement 对应角色任务的 ai-proj Task Document。
|
||||
|
||||
适用文档至少包括原始诉求/讨论记录、PRD、缺陷优化记录、原型版本与评审记录。Requirement description 只保存已确认的讨论摘要,不能替代 Task Document。
|
||||
|
||||
### 路径与任务映射
|
||||
|
||||
优先遵循仓库已有文档目录和命名约定;没有约定时使用:
|
||||
|
||||
| 文档 | 本地默认路径 | ai-proj 任务角色 |
|
||||
|------|--------------|------------------|
|
||||
| 需求讨论记录 | `docs/product/{REQ-ID}-{slug}-discussion.md` | `documentation` |
|
||||
| PRD(含缺陷修订和原型回填) | `docs/product/{REQ-ID}-{slug}-prd.md` | `prd` |
|
||||
|
||||
同一 Requirement、同一角色只维护一个当前任务文档。不得把本地文件路径当成 ai-proj 持久化,也不得只把远程 Task Document 导出一次后继续单边修改。
|
||||
|
||||
### 每次写入协议
|
||||
|
||||
1. 修改前同时读取本地文件与 ai-proj Task Document;任一不存在则基于另一份初始化,二者都不存在才新建空模板;
|
||||
2. 若两份内容不一致,比较文档 ID、版本、更新时间和内容摘要,保留双方未知内容并显式合并;无法安全合并时停止并请用户选择,禁止静默覆盖;
|
||||
3. 先用安全文件编辑方式写入本地 Markdown,再创建或更新对应 Task Document;
|
||||
4. 写后重新读取两端,计算或比较内容摘要,确认正文一致,并记录本地路径、task_id、document_id、version/updated_at;
|
||||
5. 任一端写入或复读失败都属于未完成的部分写入:保留已成功一端用于恢复,立即报告并停止后续阶段,不得宣称“已保存”“已收敛”或提交评审。
|
||||
|
||||
问答每一轮、每次 PRD 修订、每轮 defect 处置和每次原型回填都执行该协议;不能等到流程结束再一次性补传。
|
||||
|
||||
## 模块设计访谈模式
|
||||
|
||||
设计模块、系统、跨域流程,或目标/边界/业务规则尚未确定时,必须先执行问答式设计访谈,不得直接补全假设后生成 PRD。用户明确要求“你问我答”时也进入此模式。范围小、规则已完整确认的需求可以直接编写 PRD。
|
||||
|
||||
进入此模式后,**完整读取并执行** [references/design-interview-and-defect-loop.md](references/design-interview-and-defect-loop.md)。该协议定义:
|
||||
|
||||
- 每轮只问一个会改变方案的关键问题;
|
||||
- 将问题、AI 建议、用户原话、决策和未决项逐轮写入 ai-proj 需求的讨论文档;
|
||||
- 讨论结论经用户确认后,才能创建或更新 PRD;
|
||||
- 使用 `defect-analysis` 对最新版 PRD 执行“审计 → 修订 → 全量重审”循环;
|
||||
- UI 模块在 PRD 收敛后使用 `req-prototype` 生成独立 HTML 原型、上传关联 Requirement、回填 PRD 并完成可访问性与关键状态校验;
|
||||
- 原型评审改变产品行为时,回到问答、PRD 修订和 `defect-analysis` 全量重审,再生成新原型版本;
|
||||
- 讨论文档缺失、写入失败、用户未确认、原型未验证,或仍有未处置的致命/高严重度缺陷时,不得宣称设计完成或提交评审。
|
||||
|
||||
## HTML 原型完成闸门
|
||||
|
||||
模块包含用户界面、用户操作流程或可视状态时,HTML 原型是产品设计交付物,不是评审后的可选补充。默认执行 `/req prototype upload [REQ-ID]`,具体生成、上传、iframe 回填和验证规则由 `req-prototype` 定义。
|
||||
|
||||
必须满足:
|
||||
|
||||
1. 原型基于最新版、已完成缺陷收敛的 PRD,并记录 PRD 文档标识、版本或内容摘要;
|
||||
2. 覆盖核心入口、主流程以及 PRD 明确要求的空态、失败态、无权限态和确认/撤销反馈;
|
||||
3. 将本地 HTML 源文件通过 ai-proj 上传到 OSS;上传后重新读取 Requirement,确认 OSS URL/版本已关联,并验证 URL 可访问、iframe 可展示、核心交互可操作;
|
||||
4. 将 iframe、原型版本、版本说明和验证结果双写到本地 PRD 与 prd 角色 Task Document,并把生成、反馈、修订和确认双写到本地讨论记录与 documentation 任务文档;
|
||||
5. 用户明确确认最终 PRD 与原型表达的是同一方案。
|
||||
|
||||
纯后端、批处理、基础设施等确实没有用户界面的模块可以跳过,但必须在讨论文档和 PRD `4.2` 中记录“无 UI,原型不适用”的理由及用户确认,不得静默省略。
|
||||
|
||||
## 客户原话原则(REQ-20260416-0017 P1-8)
|
||||
|
||||
@@ -108,10 +167,21 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
|
||||
|
||||
### 4.2 界面原型
|
||||
|
||||
> 使用 `/req prototype [REQ-ID]` 基于 PRD 自动生成 Stitch 原型。
|
||||
> 生成后截图将自动回填到此章节。
|
||||
> UI 模块使用 `/req prototype upload [REQ-ID]` 基于最新版 PRD 生成并上传 HTML 原型。
|
||||
> 原型必须用 iframe 展示;Stitch 可作为视觉探索的可选输入,不能代替最终 HTML 原型闭环。
|
||||
|
||||
[执行 `/req prototype` 后自动填充]
|
||||
**原型基线**:
|
||||
- PRD 文档/版本:...
|
||||
- 原型版本与说明:...
|
||||
- Requirement 关联状态:已验证 | 未验证
|
||||
- 可访问性/关键交互验证:...
|
||||
|
||||
<iframe src="[prototype_url]"
|
||||
width="100%" height="600" frameborder="0"
|
||||
style="border-radius:8px;border:1px solid #e5e7eb;">
|
||||
</iframe>
|
||||
|
||||
[无 UI 模块填写:原型不适用的理由、讨论记录位置和用户确认原话]
|
||||
|
||||
## 5. 技术要求
|
||||
### 5.1 性能要求
|
||||
@@ -361,6 +431,8 @@ mcp__ai-proj__link_tasks_to_requirement
|
||||
|
||||
### 文档管理
|
||||
|
||||
以下 MCP 操作只完成 ai-proj 侧写入;每次调用前后都必须按“产品需求文档双写门禁”同步并校验本地 Markdown。
|
||||
|
||||
```bash
|
||||
# 创建 PRD 文档并关联任务
|
||||
mcp__ai-proj__create-and-attach
|
||||
@@ -378,6 +450,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- taskId: 任务ID
|
||||
```
|
||||
|
||||
导出命令不能代替双写校验:导出后仍需确认目标路径符合仓库约定、正文与 Task Document 当前版本一致,且没有覆盖本地新增内容。
|
||||
|
||||
---
|
||||
|
||||
## 功能设计流程
|
||||
@@ -395,6 +469,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- 需求池(ai-proj 需求列表)
|
||||
```
|
||||
|
||||
若命中“模块设计访谈模式”,本阶段改为执行访谈协议并持续写入 ai-proj 讨论文档;访谈未确认前不进入 PRD 定稿。
|
||||
|
||||
### 2. 需求分析
|
||||
|
||||
```
|
||||
@@ -419,10 +495,44 @@ mcp__ai-proj__export_task_document_to_file
|
||||
|
||||
输出:
|
||||
- PRD 文档
|
||||
- 原型设计
|
||||
- 可生成原型的界面状态与交互规格
|
||||
```
|
||||
|
||||
### 4. 评审验证
|
||||
### 4. 缺陷收敛
|
||||
|
||||
```
|
||||
输入:
|
||||
- 已确认讨论结论
|
||||
- 最新版完整 PRD
|
||||
|
||||
执行:
|
||||
- defect-analysis 全维度审计
|
||||
- 接受项修订 PRD
|
||||
- 对修订后的完整 PRD 重新审计,直至一轮 0 个新缺陷
|
||||
|
||||
输出:
|
||||
- 已收敛 PRD
|
||||
- 缺陷处置记录
|
||||
```
|
||||
|
||||
### 5. HTML 原型与反馈闭环
|
||||
|
||||
```
|
||||
适用:
|
||||
- 所有包含界面、用户操作或可视状态的模块
|
||||
|
||||
执行:
|
||||
- 调用 req-prototype 的 upload 模式生成独立 HTML
|
||||
- 上传并关联 Requirement
|
||||
- iframe 回填 PRD,验证访问和关键交互
|
||||
- 请用户评审;行为性反馈回到问答 → PRD → defect-analysis → 新原型版本
|
||||
|
||||
输出:
|
||||
- 已验证、已关联的 HTML 原型
|
||||
- PRD 与讨论文档中的版本/反馈/确认记录
|
||||
```
|
||||
|
||||
### 6. 评审验证
|
||||
|
||||
```
|
||||
评审维度:
|
||||
@@ -436,6 +546,10 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- 修改意见
|
||||
```
|
||||
|
||||
模块设计访谈模式下,本阶段必须调用 `defect-analysis`,并按访谈协议将每轮发现、处置、PRD 修订和收敛结论回写到同一讨论文档。
|
||||
|
||||
UI 模块还必须核对最终 HTML 原型与最新版 PRD 一致,并取得用户对二者的联合确认;无 UI 模块则核对已记录的不适用理由和用户确认。
|
||||
|
||||
---
|
||||
|
||||
## 竞品分析
|
||||
@@ -480,6 +594,16 @@ mcp__ai-proj__export_task_document_to_file
|
||||
|
||||
### PRD 完整性检查
|
||||
|
||||
- [ ] 模块/系统设计已完成单轮单问访谈,且全过程已写入 ai-proj 讨论文档
|
||||
- [ ] 讨论记录与 PRD 均已保存到仓库本地 Markdown 和对应 ai-proj Task Document
|
||||
- [ ] 两端复读正文一致,交付说明包含本地路径、task/document 标识和远程版本
|
||||
- [ ] 讨论结论已由用户明确确认
|
||||
- [ ] `defect-analysis` 已基于最新版 PRD 收敛到一轮 0 个新缺陷
|
||||
- [ ] 无未处置的致命/高严重度缺陷
|
||||
- [ ] UI 模块 HTML 原型已生成、上传并关联 Requirement;无 UI 模块已记录不适用理由和用户确认
|
||||
- [ ] 原型基线指向最新版 PRD,PRD `4.2` 已回填 iframe、版本说明和验证结果
|
||||
- [ ] 原型反馈导致的行为变更已回到问答、PRD 和 defect 全量重审,并生成新原型版本
|
||||
- [ ] 用户已联合确认最终 PRD 与 HTML 原型
|
||||
- [ ] 背景与目标明确
|
||||
- [ ] 用户群体定义清晰
|
||||
- [ ] 功能需求完整
|
||||
@@ -492,6 +616,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
### 交互设计检查
|
||||
|
||||
- [ ] 用户流程完整
|
||||
- [ ] HTML 原型覆盖核心入口、主流程及 PRD 指定的关键状态
|
||||
- [ ] 原型 URL 可访问,Requirement 关联可读取,iframe 可展示,核心交互可操作
|
||||
- [ ] 边界情况处理
|
||||
- [ ] 错误提示友好
|
||||
- [ ] 反馈及时
|
||||
@@ -512,7 +638,8 @@ mcp__ai-proj__export_task_document_to_file
|
||||
## 常用工具
|
||||
|
||||
### 原型设计
|
||||
- **Stitch** (Google AI) — 集成在 `/req prototype`,自动从 PRD 生成原型
|
||||
- **HTML upload(默认交付)** — `/req prototype upload` 生成可交互独立 HTML,上传后以 iframe 关联 Requirement 和 PRD
|
||||
- **Stitch** (Google AI) — `/req prototype` 视觉探索与多屏草图,可作为 HTML 原型输入但不替代最终闭环
|
||||
- Figma — 手动精细设计
|
||||
- Sketch
|
||||
- Axure
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
# 模块设计访谈、缺陷收敛与 HTML 原型闭环协议
|
||||
|
||||
本协议用于模块、系统、跨域流程等需要先澄清关键产品决策的设计任务。目标是让设计依据可追溯,让 PRD 在提交评审前经过可验证的缺陷收敛,并让 UI 模块通过可访问的 HTML 原型完成交互验证。
|
||||
|
||||
## 1. 进入与退出条件
|
||||
|
||||
满足任一条件时进入访谈模式:
|
||||
|
||||
- 用户明确要求“你问我答”、逐项讨论或产品访谈;
|
||||
- 设计对象是模块、系统、跨域流程或涉及多个角色/组织;
|
||||
- 目标、范围、数据归属、权限、状态流转、冲突优先级、异常策略中存在关键未决项。
|
||||
|
||||
需求范围小、上述决策均已明确时,可以直接编写 PRD。不要为了流程而重复询问用户已经回答的问题。
|
||||
|
||||
访谈模式只有同时满足以下条件才可结束:
|
||||
|
||||
1. 未决问题已清零,或明确列为非目标/后续项;
|
||||
2. AI 已给出结构化讨论结论;
|
||||
3. 用户明确确认讨论结论;
|
||||
4. PRD 已按结论创建或更新;
|
||||
5. `defect-analysis` 已对最新版 PRD 收敛;
|
||||
6. UI 模块的 HTML 原型已生成、上传、关联、回填和验证;无 UI 模块已记录不适用理由并获得用户确认;
|
||||
7. 用户联合确认收敛后的最终 PRD 与原型(或无 UI 的跳过结论)。
|
||||
|
||||
## 2. 讨论文档是跨轮次事实源
|
||||
|
||||
当当前工作已有 ai-proj Requirement 时,在提第一个问题前查找其已关联的讨论文档;没有时创建一个 documentation 角色的关联任务,并为任务创建文档:
|
||||
|
||||
- 任务标题:`【讨论】需求讨论: {需求标题}`
|
||||
- 文档标题:`{REQ-ID} 需求讨论记录`
|
||||
- 本地文件:优先使用仓库约定;默认 `docs/product/{REQ-ID}-{slug}-discussion.md`
|
||||
- 一个 Requirement 只维护一个当前讨论文档,不因会话中断重复创建。
|
||||
|
||||
查找时同时核对 Requirement 关联关系、任务角色和标题,不能只按相似标题猜测。发现多个候选讨论文档时,列出标识和最近更新时间,请用户指定或授权合并;在此之前不得静默选择其中一个继续写入。
|
||||
|
||||
初始化文档时,先把触发本次设计的用户原始消息按时间和消息边界逐条写入“原始诉求”,再记录 `Q001`。不得只留下 AI 总结而丢失原始上下文。
|
||||
|
||||
“完整过程”指可供产品决策审计的模型可见内容:用户原话、AI 向用户展示的问题/建议/权衡、工具写入结果、确认、决策变更、PRD 修订和缺陷处置。不得记录或声称记录隐藏推理、系统提示、访问凭据及其他不可披露的内部信息。
|
||||
|
||||
若尚未指定 Requirement,先请用户提供已有 Requirement,或明确授权创建。取得 Requirement 和讨论文档前不得开始声称“已留痕”的正式访谈;不得仅为执行本技能本身擅自创建 Requirement。用户明确要求“创建需求并设计”才构成创建授权。
|
||||
|
||||
每次恢复会话时,先读取 Requirement、现有 PRD,以及讨论记录/PRD 的本地文件和 ai-proj Task Document,从最后一个未决问题继续。两端持久化内容必须一致;模型记忆不能覆盖文档中的用户原话和已确认决策。
|
||||
|
||||
### 本地与 ai-proj 双写
|
||||
|
||||
- 讨论记录和 PRD 的每次新增或修订,都必须同步到仓库本地 Markdown 与对应 ai-proj Task Document;本地文件用于代码库评审和版本控制,Task Document 用于需求关联、跨会话恢复和团队查看。
|
||||
- 修改前读取两端。内容不一致时按版本、更新时间和摘要显式合并,保留双方未知内容;不能判断时停止并请用户选择,禁止以任一旧副本覆盖另一端。
|
||||
- 每轮问答按顺序完成:更新本地讨论文件 → 更新 documentation 任务文档 → 复读两端并核对正文/摘要 → 再向用户提出下一问。
|
||||
- 每次 PRD/defect/原型回填按同样协议更新本地 PRD 文件和 prd 任务文档。默认本地路径为 `docs/product/{REQ-ID}-{slug}-prd.md`,已有项目约定优先。
|
||||
- 任一端失败时记录“部分写入”及成功端的路径/标识,停止后续流程。恢复时从成功端与失败前最后版本合并,禁止重复追加同一 Q/Round/Prototype 编号。
|
||||
|
||||
### 写入纪律
|
||||
|
||||
- 提问时先写入问题原文、问题意图和 AI 建议,再向用户提问。
|
||||
- 收到回答后,先把用户原话和由此形成的决策写入,再提出下一问。
|
||||
- 每轮使用稳定编号 `Q001`、`Q002`……;重试写入时复用编号,禁止重复追加同一轮。
|
||||
- AI 提供推荐方案或选项时,为待确认内容写出明确编号或完整原文。用户仅回复“确认”“是”“前者”等短答案时,最终决策必须引用对应编号和被确认的完整内容,不能只记录孤立短词。
|
||||
- 用户原话逐字保留在引用块中;AI 的解释、推论和建议必须分栏,不能伪装成用户决定。访问令牌、密码、私钥及依法需要保护的个人敏感信息不得落库,用 `[敏感信息已脱敏]` 替代并注明脱敏原因。
|
||||
- 文档以追加式记录为主。状态为“待回答”的问题块可以在收到回答后原位补全一次;变为“已确认”后不得静默改写。纠正已确认结论时追加“决策变更”,并引用被替代的编号。
|
||||
- 更新整篇文档前重新读取最新版并保留未知内容;若读取后文档又发生变化,基于最新版合并后重试,不能用旧副本覆盖其他会话的记录。
|
||||
- 写入后读取本地文件和 ai-proj Task Document,确认本轮编号、正文和内容摘要一致。任一写入或校验失败时立即报告,停止进入下一轮,且不得声称“已记录”。
|
||||
- Requirement 描述只同步用户确认后的“讨论结论”摘要;完整过程保留在讨论文档中。
|
||||
|
||||
## 3. 单轮单问访谈
|
||||
|
||||
每轮只问一个会实质改变产品方案的问题。优先按依赖关系覆盖以下决策面,而不是机械地逐项提问:
|
||||
|
||||
1. 用户问题、目标与成功指标;
|
||||
2. 角色、主体和数据归属;
|
||||
3. 范围、非目标及版本边界;
|
||||
4. 实体关系与基数,例如一对一、一对多、多对多;
|
||||
5. 权限来源、授权人和信任边界;
|
||||
6. 创建、加入、变更、退出、撤销等状态与生命周期;
|
||||
7. 多来源冲突时的优先级和人工覆盖规则;
|
||||
8. 失败、超时、失联、重复请求和恢复策略;
|
||||
9. 兼容、迁移、审计、数据隔离和验收方式。
|
||||
|
||||
问题应让用户做产品决策,不要求用户代替 AI 设计实现细节。用户让 AI 建议时,先给出一个推荐方案和主要权衡,再请用户确认或修正。若回答引入新的实体、状态或例外规则,沿其影响继续追问;若答案已能从用户原话或现有文档确定,则直接记录,不重复确认。
|
||||
|
||||
每轮记录以下内容:
|
||||
|
||||
```markdown
|
||||
### Q001 · {决策主题}
|
||||
|
||||
- 状态:待回答 | 已确认 | 已替代
|
||||
- AI 问题(原文):...
|
||||
- 提问意图:这个答案会影响哪些设计部分
|
||||
- AI 建议与权衡:推荐方案、替代方案及主要代价
|
||||
- 待确认内容:方案/选项编号及完整表述
|
||||
- 用户回答(原文):
|
||||
> ...
|
||||
- 最终决策:只写由用户回答直接支持的结论
|
||||
- 影响范围:PRD 章节、实体、流程、权限或验收标准
|
||||
- 未决项:无 | 下一步待确认内容
|
||||
- 记录时间:ISO 8601 时间
|
||||
```
|
||||
|
||||
## 4. 方案确认闸门
|
||||
|
||||
问题收敛后,在讨论文档追加“当前决策快照”,至少包含:
|
||||
|
||||
- 目标与成功条件;
|
||||
- 用户/角色及核心场景;
|
||||
- 范围与非目标;
|
||||
- 核心实体、关系和数据归属;
|
||||
- 权限、状态流转和冲突规则;
|
||||
- 异常、降级、撤销和审计;
|
||||
- 版本边界与后续项;
|
||||
- 可验证的验收标准草案;
|
||||
- 尚存风险和假设。
|
||||
|
||||
然后向用户展示同一份摘要并询问是否确认。只有用户明确表示确认,才能:
|
||||
|
||||
1. 将摘要同步到 Requirement 描述的 `## 讨论结论`;
|
||||
2. 创建或更新 PRD;
|
||||
3. 进入缺陷收敛循环。
|
||||
|
||||
每一步完成后重新读取目标对象确认写入成功。讨论结论未同步成功时不得开始写 PRD;PRD 未写入或读取到的内容与本次版本不一致时不得开始缺陷审计。
|
||||
|
||||
若用户修改任何结论,记录为新的问答或“决策变更”,更新快照后重新确认。
|
||||
|
||||
## 5. PRD 与 defect-analysis 收敛循环
|
||||
|
||||
讨论确认后,先按 `req-prd` 的完整模板生成或更新 PRD,再完整读取并调用 `defect-analysis`。每次审计都以**当前最新版完整 PRD**、已确认讨论记录和必要的真实代码/数据契约为输入,不能只审查上轮改动片段。首次基线审计必须覆盖 `defect-analysis` 中所有适用的架构、运行时、数据和体验/维护维度;不能因为尚未覆盖其他维度时某个单独维度为 0 个新缺陷而提前结束基线。
|
||||
|
||||
循环执行:
|
||||
|
||||
1. `defect-analysis` 检查最新版 PRD,并按其规则输出带严重度和轮次的缺陷;
|
||||
2. 将本轮输入版本、检查维度、完整发现和证据写入讨论文档;PRD 输入版本至少包含文档/任务标识、更新时间和内容摘要或哈希,避免审计结果关联到错误版本;审计轮使用稳定编号 `Round 001`、`Round 002`……,重试不得重复计轮;
|
||||
3. 对每个发现标记处置:接受、误报、延后;
|
||||
4. 接受的产品缺陷必须修订 PRD,并同步影响到验收标准、风险、非目标或版本边界;纯技术实现发现若不改变产品行为,记录为后续 `req-design` 约束或开发风险,不向 PRD 填入未经验证的实现细节;
|
||||
5. 误报必须记录反证;延后必须记录原因、风险、负责人或后续需求,不得静默忽略;
|
||||
6. 记录 PRD 修改摘要和仍未解决的问题,重新读取 PRD 确认修订已经持久化;
|
||||
7. 对修改后的完整 PRD 重新调用 `defect-analysis`。
|
||||
|
||||
若某个修复会改变已确认的目标、范围、实体关系、权限、用户流程、冲突规则或验收口径,不能由 AI 静默应用。将它追加为新的问答或“决策变更”,说明缺陷证据、推荐方案和代价,获得用户确认并更新决策快照后,再修订 PRD;随后重新开始最新版 PRD 的全量审计。
|
||||
|
||||
完成全维度基线后,只有 `defect-analysis` 对最新版完整 PRD 出现一轮“0 个新缺陷”时才能标记 PRD 收敛。达到 20 轮仍有新发现只是阶段复盘点:汇总剩余风险并请求用户决定是否继续;不得把“达到轮数”写成“已收敛”。用户已明确要求持续审计时,按该技能规则继续下一阶段。
|
||||
|
||||
存在以下任一情况时,不得提交 PRD 评审或宣称完成:
|
||||
|
||||
- 未处置的致命或高严重度缺陷;
|
||||
- 讨论文档缺失或有未成功写入的轮次;
|
||||
- PRD 与已确认决策不一致;
|
||||
- 缺少 0 新增缺陷的收敛轮;
|
||||
- UI 模块缺少已验证并关联的最终 HTML 原型,或原型与最新版 PRD 不一致;
|
||||
- 无 UI 模块没有记录跳过理由及用户确认;
|
||||
- 用户尚未联合确认收敛后的最终 PRD 与原型(或跳过结论)。
|
||||
|
||||
## 6. HTML 原型闭环
|
||||
|
||||
### 6.1 适用性判断
|
||||
|
||||
PRD 包含页面、表单、列表、可视状态、用户操作或跨页面流程时,必须执行 `req-prototype` 的 HTML upload 模式。Stitch 截图或其他静态图片可以辅助探索,但不能替代可交互 HTML、Requirement 关联和 iframe 回填。
|
||||
|
||||
纯后端、批处理、基础设施等无用户界面的模块可以跳过。跳过前必须把理由、影响范围和待确认内容写入讨论文档,取得用户明确确认,并在 PRD `4.2 界面原型` 留下“不适用”记录。
|
||||
|
||||
### 6.2 生成基线与覆盖范围
|
||||
|
||||
1. 重新读取最新版 PRD,记录任务/文档标识、更新时间、版本和内容摘要或哈希;
|
||||
2. 从功能需求、交互设计和验收标准提取页面清单、角色入口、主流程与关键状态;
|
||||
3. 调用 `req-prototype` 生成独立 HTML。至少覆盖核心入口、主流程,以及 PRD 明确要求的空态、加载态、失败态、无权限态、确认和撤销反馈;
|
||||
4. 原型不得引入 PRD 未确认的新权限、状态、自动化规则或默认值。为了连贯展示所作的推断必须显式标注为待确认,不能伪装成既定需求。
|
||||
|
||||
### 6.3 上传、关联、回填与验证
|
||||
|
||||
1. 将 HTML 源文件保存到仓库约定目录(默认 `docs/prototypes/`),再通过 `upload_prototype` 上传到 ai-proj 配置的 OSS,并记录 Requirement 数字 ID、OSS URL、版本说明和上传时间;
|
||||
2. 重新读取 Requirement,确认返回的 OSS URL/版本确实已关联。仅有本地文件或上传成功响应不足以通过;
|
||||
3. 将 iframe、PRD 基线、原型版本、版本说明和验证结果同时回填本地 PRD 与 prd 角色 Task Document;
|
||||
4. 用浏览器或等价方式验证 URL 可访问、iframe 可展示、核心导航和交互可操作、关键状态可识别。使用临时浏览器时按环境规则关闭;
|
||||
5. 将生成输入、上传结果、验证证据和待确认差异写入讨论文档。任何写入或验证失败都必须停止,不得声称原型已完成。
|
||||
|
||||
### 6.4 用户评审与回流
|
||||
|
||||
向用户展示最终关联的原型,并请其同时检查信息结构、流程、状态、权限提示和关键文案:
|
||||
|
||||
- 仅视觉样式、间距、颜色等不改变产品行为的反馈,可以直接生成新原型版本,并记录修改摘要;
|
||||
- 反馈改变目标、范围、实体关系、权限、状态、流程、异常策略、默认值或验收口径时,追加新的问答/决策变更,更新决策快照和 PRD,重新执行完整 `defect-analysis`,收敛后再生成新 HTML 原型版本;
|
||||
- 每个新版本都必须重新执行关联、PRD 回填和可访问性/交互验证,不得覆盖或伪造历史版本;
|
||||
- 只有用户明确确认“最终 PRD 与当前原型一致”后,模块产品设计才可结束。
|
||||
|
||||
## 7. 讨论文档结构
|
||||
|
||||
```markdown
|
||||
# {REQ-ID} 需求讨论记录
|
||||
|
||||
## 元数据
|
||||
- Requirement:...
|
||||
- 状态:访谈中 | 待方案确认 | PRD 优化中 | 原型制作中 | 待最终确认 | 已收敛
|
||||
- 最新 PRD:任务/文档标识
|
||||
- 更新时间:...
|
||||
|
||||
## 原始诉求
|
||||
> 用户原话,按时间追加
|
||||
|
||||
## 问答记录
|
||||
### Q001 · ...
|
||||
...
|
||||
|
||||
## 决策变更
|
||||
### D001 · 替代 Qxxx 的结论
|
||||
...
|
||||
|
||||
## 当前决策快照
|
||||
...
|
||||
|
||||
## 未决问题
|
||||
- ...
|
||||
|
||||
## 方案确认
|
||||
- 用户确认原话:...
|
||||
- 确认时间:...
|
||||
|
||||
## PRD / 缺陷优化记录
|
||||
### Round 1 · {检查维度}
|
||||
- PRD 版本/摘要:...
|
||||
- 新缺陷:...
|
||||
- 处置与证据:...
|
||||
- PRD 修订:...
|
||||
- 剩余风险:...
|
||||
|
||||
## HTML 原型记录
|
||||
### Prototype v1 · {版本说明}
|
||||
- PRD 基线:任务/文档标识、版本、更新时间、摘要或哈希
|
||||
- 是否适用:是 | 否(理由与用户确认)
|
||||
- 原型 URL:...
|
||||
- Requirement 关联校验:...
|
||||
- iframe / 可访问性 / 关键交互验证:...
|
||||
- 用户反馈:...
|
||||
- 行为性变更回流:无 | 对应 Q/D、PRD 版本和 defect 轮次
|
||||
- 状态:待验证 | 待用户确认 | 已替代 | 已确认
|
||||
|
||||
## 收敛结论
|
||||
- 收敛轮次:...
|
||||
- 0 新增缺陷证据:...
|
||||
- 最终原型版本/URL:... | 无 UI,不适用(确认记录:...)
|
||||
- PRD 与原型一致性确认:...
|
||||
- 未解决的中/低风险及接受理由:...
|
||||
- 用户最终确认原话:...
|
||||
```
|
||||
|
||||
## 8. 最终交付说明
|
||||
|
||||
最终回复必须同时给出:
|
||||
|
||||
- ai-proj Requirement 标识;
|
||||
- 讨论任务/文档标识;
|
||||
- 讨论记录本地路径及双写一致性状态;
|
||||
- PRD 任务/文档标识;
|
||||
- PRD 本地路径及双写一致性状态;
|
||||
- 问答轮数、缺陷审计轮数和收敛轮;
|
||||
- HTML 原型版本、URL、Requirement 关联与验证状态;无 UI 时给出跳过理由和用户确认;
|
||||
- 仍被接受的中/低风险;
|
||||
- 用户两次确认:讨论方案确认、最终 PRD 与原型(或无 UI 结论)的联合确认。
|
||||
|
||||
任何标识或写入状态无法验证时,用“未验证/未写入”如实标注。
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "req-prototype-plugin",
|
||||
"description": "原型生成与关联。支持 HTML 上传(/req prototype upload,iframe 嵌入详情页)和 Stitch AI 生成两种模式。",
|
||||
"version": "2.0.0",
|
||||
"description": "原型生成与关联。支持 HTML 本地留源、OSS 正式交付、Requirement/iframe 验证及 Stitch AI。",
|
||||
"version": "2.2.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
---
|
||||
name: req-prototype
|
||||
description: 原型生成与关联。支持两种模式:(1) Stitch AI 基于 PRD 自动生成 UI 原型截图;(2) AI 编写 HTML 原型并上传关联到需求详情页 iframe。当执行 /req prototype 或需要生成/上传界面原型时使用。
|
||||
arguments: <REQ-ID> [subcommand] [options]
|
||||
description: 原型生成与关联。生成可交互 HTML、上传到 ai-proj OSS 并关联 Requirement/PRD iframe,也支持 Stitch AI 视觉探索。
|
||||
---
|
||||
|
||||
# 原型设计 Skill (req-prototype)
|
||||
|
||||
用法:`/req prototype <REQ-ID> [subcommand] [options]`
|
||||
|
||||
## 概述
|
||||
|
||||
支持两种原型工作流:
|
||||
|
||||
| 模式 | 命令 | 适用场景 | 输出 |
|
||||
|------|------|----------|------|
|
||||
| **HTML 上传** | `/req prototype upload` | 快速展示、评审用静态原型 | iframe 嵌入需求详情页 |
|
||||
| **Stitch AI** | `/req prototype` | 精细 UI 设计、多屏交互 | 截图回填 PRD 文档 |
|
||||
| **HTML 上传** | `/req prototype upload` | UI 模块正式产品设计交付、评审与交互验证 | 本地 HTML 源文件 + OSS URL + Requirement 关联 + PRD iframe |
|
||||
| **Stitch AI** | `/req prototype` | 精细 UI 视觉探索、多屏草图 | 截图回填 PRD,后续仍需转为 HTML 正式原型 |
|
||||
|
||||
## 前置条件
|
||||
|
||||
@@ -22,35 +23,52 @@ arguments: <REQ-ID> [subcommand] [options]
|
||||
| 检查项 | 方式 | 失败处理 |
|
||||
|--------|------|----------|
|
||||
| 需求存在 | `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 原型(**推荐**)
|
||||
|
||||
**适用场景**:快速为需求关联一个带样式的 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览交互流程。
|
||||
**适用场景**:为 UI 模块生成正式 HTML 原型,直接在需求详情页以 iframe 展示,供评审人预览和验证交互流程。模块产品设计默认使用此模式完成原型闸门。
|
||||
|
||||
**执行流程**:
|
||||
|
||||
```
|
||||
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id
|
||||
2. 读取 PRD 或需求描述,提炼 UI 关键信息
|
||||
3. AI 编写带完整样式的 HTML 原型文件(见设计规范)
|
||||
4. 保存到 /tmp/proto_<req_id>_<timestamp>.html
|
||||
5. Base64 编码:base64 < /tmp/proto_<req_id>_<timestamp>.html
|
||||
6. 调用 mcp__ai-proj__upload_prototype 上传(传入 requirementId + base64 content)
|
||||
7. 确认上传成功,输出 COS 预览 URL
|
||||
1. 获取需求信息(mcp__ai-proj__get_requirement),取得数字 id,并定位唯一 PRD 与讨论文档
|
||||
2. 完整读取最新版 PRD,记录任务/文档 ID、版本、更新时间和内容摘要或哈希;正式交付还要核对 defect 收敛轮
|
||||
3. 从 PRD 提取页面清单、角色入口、主流程、关键状态和验收条件,形成覆盖矩阵
|
||||
4. AI 编写带完整样式和必要原生交互的独立 HTML 原型文件(见设计规范)
|
||||
5. 保存到仓库原型目录(默认 docs/prototypes/<REQ-ID>-<slug>-v<N>.html),并做结构、大小和敏感信息检查
|
||||
6. 从本地源文件 Base64 编码;如工具需要,可在 /tmp 创建临时编码副本
|
||||
7. 调用 mcp__ai-proj__upload_prototype 上传到 OSS(传入 requirementId + base64 content)
|
||||
8. 重新读取 Requirement,确认 OSS URL/版本已关联;不得只相信上传响应
|
||||
9. 将 iframe、PRD 基线、原型版本/说明和验证状态双写到本地 PRD 与 prd 角色 Task Document
|
||||
10. 打开最终 URL 或需求详情页,验证 iframe 展示和核心交互;记录证据后关闭临时浏览器
|
||||
11. 将生成、关联、验证、用户反馈和版本状态双写到本地讨论记录与 documentation 角色 Task Document
|
||||
```
|
||||
|
||||
**Step 5-6 执行方式**:
|
||||
**Step 6-7 执行方式**:
|
||||
|
||||
```bash
|
||||
# 5. Base64 编码 HTML 文件
|
||||
B64=$(base64 < /tmp/proto_<req_id>_<timestamp>.html)
|
||||
# 6. Base64 编码本地 HTML 源文件
|
||||
B64=$(base64 < docs/prototypes/<REQ-ID>-<slug>-v<N>.html)
|
||||
```
|
||||
|
||||
```
|
||||
# 6. 通过 MCP 工具上传(无需本地后端)
|
||||
# 7. 通过 MCP 工具上传到 OSS(无需本地后端)
|
||||
mcp__ai-proj__upload_prototype(
|
||||
requirementId = <需求数字ID>,
|
||||
content = <B64 字符串>,
|
||||
@@ -65,7 +83,7 @@ mcp__ai-proj__upload_prototype(
|
||||
"success": true,
|
||||
"message": "原型已上传并关联到需求 <id>(version=N/A)",
|
||||
"data": {
|
||||
"url": "https://ai-proj-1252326374.cos.ap-beijing.myqcloud.com/prototypes/<uuid>.html",
|
||||
"url": "https://<ai-proj-oss-domain>/prototypes/<uuid>.html",
|
||||
"versionNote": "...",
|
||||
"uploadedAt": "...",
|
||||
"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 色等)
|
||||
- 对 PRD 明确要求的空态、加载态、失败态、无权限态、二次确认和撤销反馈提供可切换或可识别的展示
|
||||
- 不得自行引入 PRD 未确认的权限、状态、自动化规则或默认值;不可避免的展示推断必须标为待确认
|
||||
- 不包含访问令牌、真实手机号/邮箱、生产数据等敏感信息
|
||||
|
||||
**模板参考**(顶部 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 生成原型
|
||||
|
||||
**流程**:
|
||||
@@ -160,6 +219,7 @@ AI 生成的 HTML 原型必须满足以下要求:
|
||||
6. 生成页面(mcp__stitch__generate_screen_from_text)
|
||||
7. 获取截图(mcp__stitch__get_screen)
|
||||
8. 回填 PRD「4.2 界面原型」章节
|
||||
9. 若用于模块正式交付,将选定设计转换为 HTML upload 原型,并完成关联、iframe 和验证闭环
|
||||
```
|
||||
|
||||
**参数**:
|
||||
@@ -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 | 精简样式或拆分多版本上传 |
|
||||
| iframe 不显示 | 检查 `prototype_urls` 字段是否非空:`mcp__ai-proj__get_requirement` 确认 |
|
||||
| base64 命令失败 | macOS 用 `base64 < file`,Linux 用 `base64 -w 0 < file` |
|
||||
| Requirement 复读没有新 URL | 视为关联失败,停止回填“已验证”,检查 requirementId 和上传响应后再处理 |
|
||||
| URL 可访问但关键交互失败 | 修复 HTML、上传新版本并重新验证,不覆盖失败版本的记录 |
|
||||
|
||||
### 原型展示规则
|
||||
|
||||
@@ -303,6 +365,8 @@ generated_at: "<timestamp>"
|
||||
|
||||
> 背景:REQ-20260420-0031 反馈原型图用图片方式展示,无法交互预览,改为 iframe 后可正常使用。
|
||||
|
||||
Stitch 截图只用于视觉探索,不满足模块产品设计的最终 HTML 原型闸门。
|
||||
|
||||
|
||||
### Stitch 模式
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ mkdir -p "$TEST_HOME"
|
||||
cp "$PROJECT_DIR/install-skills.sh" "$FIXTURE_REPO/install-skills.sh"
|
||||
|
||||
write_manifest() {
|
||||
local plugin="$1" name="$2" version="$3"
|
||||
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":"skill","dir_category":"dev"}
|
||||
{"name":"${plugin}-plugin","version":"${version}","install_name":"${name}","install_type":"${install_type}","dir_category":"dev"}
|
||||
JSON
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ 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/.claude/skills/example/references/guide.md"
|
||||
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
|
||||
@@ -42,18 +42,21 @@ description: Installer fixture version two.
|
||||
---
|
||||
version two
|
||||
EOF
|
||||
# Reproduce rsync's quick-check edge case: changed content with identical size
|
||||
# and mtime must still replace the recorded, unmodified installation.
|
||||
touch -r "$TEST_HOME/.agents/skills/example/SKILL.md" "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
grep -q 'version two' "$TEST_HOME/.claude/skills/example/SKILL.md"
|
||||
grep -q '"version": "2.0.0"' "$TEST_HOME/.claude/.installed-skills.json"
|
||||
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/.claude/skills/example/SKILL.md"
|
||||
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/.claude/skills/example/SKILL.md"
|
||||
if grep -q 'repository version three' "$TEST_HOME/.claude/skills/example/SKILL.md"; then
|
||||
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
|
||||
@@ -70,9 +73,45 @@ 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/.claude/skills/legacy"
|
||||
cp "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" "$TEST_HOME/.claude/skills/legacy/SKILL.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/.claude/skills/legacy/references/guide.md"
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user