chore(marketplace): add publish-plugin, rewrite init.sh, cleanup obsolete plugins

- Add publish-plugin: marketplace publish + Feishu bot notification
- Rewrite init.sh: SSE-first, fixed prod API, remove env selection
- Update CLAUDE.md, README.md, claude-config.yaml
- Update skills: req-plugin, req-prd-plugin, pull-request-plugin
- Delete sync-skills.sh (obsolete)
- Delete deprecated plugins: skills-ops/*, skills-projects/*, old skills-dev/req duplicates
- Regenerate marketplace.json (27 plugins)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 15:09:07 +10:30
parent 5878c1f852
commit dcdae8c636
79 changed files with 610 additions and 13407 deletions

View File

@@ -24,9 +24,9 @@
"strict": false "strict": false
}, },
{ {
"name": "agent-swarm-plugin", "name": "publish-plugin",
"source": "./skills-dev/agent-swarm-plugin", "source": "./skills-core/publish-plugin",
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.", "description": "发布 ai-proj-helper 技能市场更新并通知飞书群。当用户提到发布、publish、更新技能市场时自动激活。",
"version": "1.0.0", "version": "1.0.0",
"category": "utility", "category": "utility",
"keywords": [ "keywords": [
@@ -61,19 +61,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "dev-plugin",
"source": "./skills-dev/dev-plugin",
"description": "Plugin for dev",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{ {
"name": "dev-test-plugin", "name": "dev-test-plugin",
"source": "./skills-dev/dev-test-plugin", "source": "./skills-dev/dev-test-plugin",
@@ -87,43 +74,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "finishing-a-development-branch-plugin",
"source": "./skills-dev/finishing-a-development-branch-plugin",
"description": "Plugin for finishing-a-development-branch",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "frontend-design-plugin",
"source": "./skills-dev/frontend-design-plugin",
"description": "Plugin for frontend-design",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "gitea-plugin",
"source": "./skills-dev/gitea-plugin",
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{ {
"name": "pull-request-plugin", "name": "pull-request-plugin",
"source": "./skills-dev/pull-request-plugin", "source": "./skills-dev/pull-request-plugin",
@@ -137,44 +87,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "executing-plans-plugin",
"source": "./skills-req/executing-plans-plugin",
"description": "Plugin for executing-plans",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "req-commands-plugin",
"source": "./skills-req/req-commands-plugin",
"description": "需求命令详细参考。含撰写命令new/draft/edit/check/split/history/compare和流程命令submit/review/phase/next/deploy/done。",
"version": "2.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-deploy-plugin",
"source": "./skills-req/req-deploy-plugin",
"description": "Plugin for req-deploy",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{ {
"name": "req-dev-plugin", "name": "req-dev-plugin",
"source": "./skills-req/req-dev-plugin", "source": "./skills-req/req-dev-plugin",
@@ -214,19 +126,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "req-review-plugin",
"source": "./skills-req/req-review-plugin",
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{ {
"name": "req-test-gate-plugin", "name": "req-test-gate-plugin",
"source": "./skills-req/req-test-gate-plugin", "source": "./skills-req/req-test-gate-plugin",
@@ -240,83 +139,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "req-workflow-plugin",
"source": "./skills-req/req-workflow-plugin",
"description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "requirement-plugin",
"source": "./skills-req/requirement-plugin",
"description": "[已废弃] 需求撰写功能已合并到 req-plugin。请使用 /req 命令。",
"version": "2.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "openclaw-ops-plugin",
"source": "./skills-ops/openclaw-ops-plugin",
"description": "Plugin for openclaw-ops",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "openclaw-plugin",
"source": "./skills-ops/openclaw-plugin",
"description": "OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "ops-servers-plugin",
"source": "./skills-ops/ops-servers-plugin",
"description": "Plugin for ops-servers",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "ops-tools-plugin",
"source": "./skills-ops/ops-tools-plugin",
"description": "Plugin for ops-tools",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{ {
"name": "data-excel-plugin", "name": "data-excel-plugin",
"source": "./skills-integration/data-excel-plugin", "source": "./skills-integration/data-excel-plugin",
@@ -471,9 +293,9 @@
"strict": false "strict": false
}, },
{ {
"name": "coolbuy-legacy-plugin", "name": "gitea-plugin",
"source": "./skills-projects/coolbuy-legacy-plugin", "source": "./skills-personal/gitea-plugin",
"description": "酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。", "description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
"version": "1.0.0", "version": "1.0.0",
"category": "utility", "category": "utility",
"keywords": [ "keywords": [
@@ -483,10 +305,10 @@
"strict": false "strict": false
}, },
{ {
"name": "coolbuy-paas-plugin", "name": "openclaw-plugin",
"source": "./skills-projects/coolbuy-paas-plugin", "source": "./skills-personal/openclaw-plugin",
"description": "酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发以及酷采2.0系统对比测试。", "description": "OpenClaw (龙虾) 远程 AI 计算调度系统 - 概念设计与运维管理",
"version": "1.3.0", "version": "1.0.0",
"category": "utility", "category": "utility",
"keywords": [ "keywords": [
"utility", "utility",
@@ -495,21 +317,9 @@
"strict": false "strict": false
}, },
{ {
"name": "coolbuy-platform-plugin", "name": "ops-tools-plugin",
"source": "./skills-projects/coolbuy-platform-plugin", "source": "./skills-personal/ops-tools-plugin",
"description": "Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。", "description": "Plugin for ops-tools",
"version": "1.0.9",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "enjoysa-deploy-plugin",
"source": "./skills-projects/enjoysa-deploy-plugin",
"description": "EnjoySA 项目部署到新加坡服务器",
"version": "1.0.0", "version": "1.0.0",
"category": "devops", "category": "devops",
"keywords": [ "keywords": [
@@ -519,18 +329,6 @@
], ],
"strict": false "strict": false
}, },
{
"name": "enjoysa-plugin",
"source": "./skills-projects/enjoysa-plugin",
"description": "Plugin for enjoysa",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{ {
"name": "qiudl-personal-plugin", "name": "qiudl-personal-plugin",
"source": "./skills-personal/qiudl-personal-plugin", "source": "./skills-personal/qiudl-personal-plugin",
@@ -542,6 +340,19 @@
"tools" "tools"
], ],
"strict": false "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
} }
] ]
} }

3
.gitignore vendored
View File

@@ -11,6 +11,9 @@ skills-personal/
# MCP generated config # MCP generated config
.mcp.json .mcp.json
# MCP bridge (cloned by init.sh for stdio mode)
mcp-task-bridge/
# OS files # OS files
.DS_Store .DS_Store
Thumbs.db Thumbs.db

View File

@@ -8,27 +8,24 @@ Claude Code 技能市场 + MCP 配置管理工具。
./init.sh ./init.sh
``` ```
交互式配置 MCP 连接和生成 marketplace.json。支持命令行参数: 交互式配置 MCP 连接(默认 SSE 模式)。支持命令行参数:
```bash ```bash
./init.sh --mode stdio --env prod --token YOUR_TOKEN ./init.sh --mode sse --token aiproj_pk_xxx
``` ```
## 目录结构 ## 目录结构
``` ```
ai-proj-helper/ ai-proj-helper/
├── skills-dev/ # 开发 (9): dev, dev-arch, dev-coding, dev-test, frontend-design, agent-swarm, pull-request, finishing-a-development-branch, gitea ├── skills-core/ # 基础设施 (1): ai-proj
├── skills-req/ # 需求 (10): req, req-commands, req-dev, req-prd, req-review, req-test-gate, req-workflow, req-deploy, requirement, executing-plans ├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
├── skills-ops/ # 运维 (4): ops-tools, ops-servers, openclaw, openclaw-ops ├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice ├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance ├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
├── skills-workflow/ # 工作流 (7): ai-proj, save-session, reload-session, read-session, search-sessions, session, skill-manager
├── skills-projects/ # 项目 (5): coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
├── skills-personal/ # 个人(.gitignore 排除) ├── skills-personal/ # 个人(.gitignore 排除)
├── claude-config.yaml # 技能启用/禁用 + MCP 配置 ├── claude-config.yaml # 技能启用/禁用 + MCP 配置
├── init.sh # MCP + marketplace 初始化 ├── init.sh # MCP 初始化
├── sync-skills.sh # 从 ~/.claude/skills/ 同步技能
└── generate-marketplace.py └── generate-marketplace.py
``` ```
@@ -50,14 +47,6 @@ skills:
重新运行 `./init.sh``python3 generate-marketplace.py` 重新运行 `./init.sh``python3 generate-marketplace.py`
## MCP 环境
| 环境 | API 地址 |
|------|----------|
| dev | http://localhost:8080/api/v1 |
| staging | https://ai-staging.pipexerp.com/api/v1 |
| prod | https://ai.pipexerp.com/api/v1 |
## 技能目录说明 ## 技能目录说明
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具 - `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具

View File

@@ -11,7 +11,7 @@ Claude Code 技能市场 + MCP 配置管理工具。整合通用技能、项目
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. 运行初始化(交互式配置 MCP + 生成 marketplace # 2. 运行初始化(交互式配置 MCP 连接
./init.sh ./init.sh
# 3. 添加技能市场 # 3. 添加技能市场
@@ -21,7 +21,7 @@ cd ai-proj-helper
也可以使用命令行参数跳过交互: 也可以使用命令行参数跳过交互:
```bash ```bash
./init.sh --mode stdio --env prod --token YOUR_TOKEN ./init.sh --mode sse --token aiproj_pk_xxx
``` ```
## 目录结构 ## 目录结构
@@ -30,32 +30,29 @@ cd ai-proj-helper
ai-proj-helper/ ai-proj-helper/
├── .claude-plugin/marketplace.json # 自动生成 ├── .claude-plugin/marketplace.json # 自动生成
├── claude-config.yaml # 技能启用/禁用 + MCP 配置 ├── claude-config.yaml # 技能启用/禁用 + MCP 配置
├── init.sh # MCP + marketplace 初始化 ├── init.sh # MCP 初始化
├── sync-skills.sh # 同步本地技能
├── generate-marketplace.py # marketplace 生成器 ├── generate-marketplace.py # marketplace 生成器
├── skills-dev/ # 开发 (9) ├── skills-core/ # 基础设施 (1)
├── skills-req/ # 需求管理 (10) ├── skills-dev/ # 开发 (4)
├── skills-ops/ # 运维 (4) ├── skills-req/ # 需求管理 (4)
├── skills-integration/ # 第三方集成 (8) ├── skills-integration/ # 第三方集成 (8)
├── skills-biz/ # 商务 (4) ├── skills-biz/ # 商务 (4)
├── skills-workflow/ # 工作流 (7)
├── skills-projects/ # 项目特定 (5)
└── skills-personal/ # 个人(.gitignore 排除) └── skills-personal/ # 个人(.gitignore 排除)
``` ```
## 可用技能 (49) ## 可用技能 (26)
### skills-dev/ — 开发 (9) ### skills-core/ — 基础设施 (1)
dev, dev-arch, dev-coding, dev-test, frontend-design, agent-swarm, pull-request, finishing-a-development-branch, gitea ai-proj
### skills-req/ — 需求管理 (10) ### skills-dev/ — 开发 (4)
req, req-commands, req-dev, req-prd, req-review, req-test-gate, req-workflow, req-deploy, requirement, executing-plans dev-arch, dev-coding, dev-test, pull-request
### skills-ops/ — 运维 (4) ### skills-req/ — 需求管理 (4)
ops-tools, ops-servers, openclaw, openclaw-ops req, req-prd, req-dev, req-test-gate
### skills-integration/ — 第三方集成 (8) ### skills-integration/ — 第三方集成 (8)
@@ -65,13 +62,9 @@ feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel
biz-contract, biz-ops, biz-plan, finance biz-contract, biz-ops, biz-plan, finance
### skills-workflow/ — 工作流 (7) ### skills-personal/ — 个人 (5)
ai-proj, save-session, reload-session, read-session, search-sessions, session, skill-manager gitea, openclaw, ops-tools, qiudl-personal, req-deploy
### skills-projects/ — 项目特定 (5)
coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
## 配置管理 ## 配置管理
@@ -81,8 +74,7 @@ coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
version: "1.0" version: "1.0"
mcp: mcp:
mode: stdio # stdio | sse mode: sse # sse | stdio
env: prod # dev | staging | prod
skills: skills:
disabled: [] # 禁用的技能列表 disabled: [] # 禁用的技能列表
@@ -93,22 +85,6 @@ skills:
编辑 `claude-config.yaml` 添加要禁用的技能名称,然后重新运行 `./init.sh``python3 generate-marketplace.py` 编辑 `claude-config.yaml` 添加要禁用的技能名称,然后重新运行 `./init.sh``python3 generate-marketplace.py`
## 同步本地技能
`~/.claude/skills/` 中的技能同步到仓库:
```bash
./sync-skills.sh
```
## MCP 环境
| 环境 | API 地址 | 用途 |
|------|----------|------|
| dev | http://localhost:8080 | 本地开发 |
| staging | https://ai-staging.pipexerp.com | 测试环境 |
| prod | https://ai.pipexerp.com | 生产环境 |
## 作者 ## 作者
**Donglin Lai (qiudl)** - qiudl@zhiyuncai.com **Donglin Lai (qiudl)** - qiudl@zhiyuncai.com

View File

@@ -1,8 +1,7 @@
version: "1.0" version: "1.0"
mcp: mcp:
mode: stdio # stdio | sse mode: sse # sse | stdio
env: prod # dev | staging | prod
# Token 不存储在此文件,由 init.sh 引导配置 # Token 不存储在此文件,由 init.sh 引导配置
skills: skills:

View File

@@ -19,11 +19,8 @@ SKILL_DIRS = [
("core", "skills-core"), ("core", "skills-core"),
("dev", "skills-dev"), ("dev", "skills-dev"),
("req", "skills-req"), ("req", "skills-req"),
("ops", "skills-ops"),
("integration", "skills-integration"), ("integration", "skills-integration"),
("biz", "skills-biz"), ("biz", "skills-biz"),
("workflow", "skills-workflow"),
("projects", "skills-projects"),
("personal", "skills-personal"), ("personal", "skills-personal"),
] ]

121
init.sh
View File

@@ -1,32 +1,31 @@
#!/bin/bash #!/bin/bash
# ai-proj-helper 初始化脚本 # ai-proj-helper MCP 初始化脚本
# 配置 MCP 服务器 + 生成 marketplace.json # 为用户配置 ai-proj MCP 连接
set -e set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
MCP_CONFIG="$HOME/.claude/.mcp.json" MCP_CONFIG="$HOME/.claude/.mcp.json"
MCP_BRIDGE_DIR="$HOME/coding/qiudl/new-ai-proj/mcp-task-bridge" MCP_BRIDGE_DIR="$SCRIPT_DIR/mcp-task-bridge"
CONFIG_FILE="$SCRIPT_DIR/claude-config.yaml" CONFIG_FILE="$SCRIPT_DIR/claude-config.yaml"
API_BASE="https://ai.pipexerp.com/api/v1"
SSE_URL="${API_BASE}/mcp/sse"
# Default values # Default values
MODE="" MODE=""
ENV=""
TOKEN="" TOKEN=""
# ── Parse command line arguments ────────────────────────────────────── # ── Parse command line arguments ──────────────────────────────────────
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case $1 in case $1 in
--mode) MODE="$2"; shift 2 ;; --mode) MODE="$2"; shift 2 ;;
--env) ENV="$2"; shift 2 ;;
--token) TOKEN="$2"; shift 2 ;; --token) TOKEN="$2"; shift 2 ;;
-h|--help) -h|--help)
echo "Usage: ./init.sh [--mode stdio|sse] [--env dev|staging|prod] [--token PAT_TOKEN]" echo "Usage: ./init.sh [--mode sse|stdio] [--token MCP_API_KEY]"
echo "" echo ""
echo "Options:" echo "Options:"
echo " --mode MCP connection mode: stdio (local) or sse (remote)" echo " --mode MCP connection mode: sse (remote, recommended) or stdio (local)"
echo " --env Environment: dev, staging, or prod" echo " --token MCP API Key (aiproj_pk_xxx)"
echo " --token Personal Access Token for ai-proj API"
echo "" echo ""
echo "Without arguments, runs in interactive mode." echo "Without arguments, runs in interactive mode."
exit 0 exit 0
@@ -50,75 +49,71 @@ read_config_value() {
echo "$default" echo "$default"
} }
CONFIG_MODE=$(read_config_value "mode" "stdio") CONFIG_MODE=$(read_config_value "mode" "sse")
CONFIG_ENV=$(read_config_value "env" "prod")
# ── Interactive mode selection ──────────────────────────────────────── # ── Interactive mode selection ────────────────────────────────────────
if [ -z "$MODE" ]; then if [ -z "$MODE" ]; then
echo "┌─────────────────────────────────────┐" echo "┌─────────────────────────────────────┐"
echo "│ ai-proj-helper 初始化 │" echo "│ ai-proj MCP 初始化 │"
echo "└─────────────────────────────────────┘" echo "└─────────────────────────────────────┘"
echo "" echo ""
echo "MCP 连接模式:" echo "MCP 连接模式:"
echo " 1) stdio - 本地进程 (需要 mcp-task-bridge)" echo " 1) sse - 远程 SSE 连接 (推荐,零依赖)"
echo " 2) sse - 远程 SSE 连接" echo " 2) stdio - 本地进程 (需要 Node.js + mcp-task-bridge)"
echo "" echo ""
read -p "选择模式 [1/2] (default: $([ "$CONFIG_MODE" = "sse" ] && echo "2" || echo "1")): " mode_choice read -p "选择模式 [1/2] (default: $([ "$CONFIG_MODE" = "stdio" ] && echo "2" || echo "1")): " mode_choice
case "$mode_choice" in case "$mode_choice" in
2|sse) MODE="sse" ;; 2|stdio) MODE="stdio" ;;
*) MODE="stdio" ;; *) MODE="sse" ;;
esac esac
fi fi
# ── Interactive environment selection ─────────────────────────────────
if [ -z "$ENV" ]; then
echo ""
echo "环境:"
echo " 1) dev - http://localhost:8080"
echo " 2) staging - https://ai-staging.pipexerp.com"
echo " 3) prod - https://ai.pipexerp.com"
echo ""
default_num=3
[ "$CONFIG_ENV" = "dev" ] && default_num=1
[ "$CONFIG_ENV" = "staging" ] && default_num=2
read -p "选择环境 [1/2/3] (default: $default_num): " env_choice
case "$env_choice" in
1|dev) ENV="dev" ;;
2|staging) ENV="staging" ;;
*) ENV="prod" ;;
esac
fi
# ── Resolve API base URL ─────────────────────────────────────────────
case "$ENV" in
dev) API_BASE="http://localhost:8080/api/v1" ;;
staging) API_BASE="https://ai-staging.pipexerp.com/api/v1" ;;
prod) API_BASE="https://ai.pipexerp.com/api/v1" ;;
esac
# ── Token input ─────────────────────────────────────────────────────── # ── Token input ───────────────────────────────────────────────────────
if [ -z "$TOKEN" ]; then if [ -z "$TOKEN" ]; then
echo "" echo ""
echo "请输入 AI-Proj Personal Access Token (PAT):" echo "请输入 MCP API Key:"
echo " 获取方式: 登录 AI-Proj → 设置 → API Tokens → 创建" echo " 格式: aiproj_pk_xxxxxxxx"
echo " 获取: 登录 AI-Proj → 设置 → MCP API Keys → 创建"
echo "" echo ""
read -sp "Token: " TOKEN read -sp "API Key: " TOKEN
echo "" echo ""
fi fi
if [ -z "$TOKEN" ]; then if [ -z "$TOKEN" ]; then
echo "❌ Token 不能为空" echo "❌ API Key 不能为空"
exit 1 exit 1
fi fi
echo "" echo ""
echo "配置信息:" echo "配置信息:"
echo " 模式: $MODE" echo " 模式: $MODE"
echo " 环境: $ENV ($API_BASE)" if [ "$MODE" = "sse" ]; then
echo " SSE: $SSE_URL"
else
echo " API: $API_BASE"
fi
echo "" echo ""
# ── SSE mode ─────────────────────────────────────────────────────────
if [ "$MODE" = "sse" ]; then
mkdir -p "$(dirname "$MCP_CONFIG")"
cat > "$MCP_CONFIG" << EOF
{
"mcpServers": {
"ai-proj": {
"type": "sse",
"url": "$SSE_URL",
"headers": {
"X-API-Key": "$TOKEN"
}
}
}
}
EOF
echo "✅ 已生成 $MCP_CONFIG (SSE 模式)"
# ── stdio mode: ensure mcp-task-bridge ──────────────────────────────── # ── stdio mode: ensure mcp-task-bridge ────────────────────────────────
if [ "$MODE" = "stdio" ]; then elif [ "$MODE" = "stdio" ]; then
if [ ! -d "$MCP_BRIDGE_DIR" ]; then if [ ! -d "$MCP_BRIDGE_DIR" ]; then
echo "📦 mcp-task-bridge 未找到,正在克隆..." echo "📦 mcp-task-bridge 未找到,正在克隆..."
git clone https://gitea.pipexerp.com/pipexerp/mcp-task-bridge.git "$MCP_BRIDGE_DIR" git clone https://gitea.pipexerp.com/pipexerp/mcp-task-bridge.git "$MCP_BRIDGE_DIR"
@@ -134,7 +129,6 @@ if [ "$MODE" = "stdio" ]; then
BRIDGE_ENTRY="$MCP_BRIDGE_DIR/dist/index.js" BRIDGE_ENTRY="$MCP_BRIDGE_DIR/dist/index.js"
# Generate .mcp.json for stdio mode
mkdir -p "$(dirname "$MCP_CONFIG")" mkdir -p "$(dirname "$MCP_CONFIG")"
cat > "$MCP_CONFIG" << EOF cat > "$MCP_CONFIG" << EOF
{ {
@@ -153,37 +147,12 @@ if [ "$MODE" = "stdio" ]; then
} }
EOF EOF
echo "✅ 已生成 $MCP_CONFIG (stdio 模式)" echo "✅ 已生成 $MCP_CONFIG (stdio 模式)"
elif [ "$MODE" = "sse" ]; then
# Generate .mcp.json for SSE mode
SSE_URL="${API_BASE%/api/v1}/mcp/sse"
mkdir -p "$(dirname "$MCP_CONFIG")"
cat > "$MCP_CONFIG" << EOF
{
"mcpServers": {
"ai-proj": {
"type": "sse",
"url": "$SSE_URL",
"headers": {
"Authorization": "Bearer $TOKEN"
}
}
}
}
EOF
echo "✅ 已生成 $MCP_CONFIG (SSE 模式)"
fi fi
# ── Generate marketplace.json ─────────────────────────────────────────
echo ""
echo "🔄 生成 marketplace.json..."
cd "$SCRIPT_DIR"
python3 generate-marketplace.py
echo "" echo ""
echo "┌─────────────────────────────────────┐" echo "┌─────────────────────────────────────┐"
echo "│ ✅ 初始化完成! │" echo "│ ✅ 初始化完成! │"
echo "└─────────────────────────────────────┘" echo "└─────────────────────────────────────┘"
echo "" echo ""
echo "下次启动 Claude Code 即可使用 MCP 工具。" echo "下次启动 Claude Code 即可使用 MCP 工具。"
echo "如需更新技能配置,编辑 claude-config.yaml 后重新运行 ./init.sh" echo "如需更改模式,编辑 claude-config.yaml 后重新运行 ./init.sh"

View File

@@ -0,0 +1,8 @@
{
"name": "publish-plugin",
"description": "发布 ai-proj-helper 技能市场更新并通知飞书群。当用户提到发布、publish、更新技能市场时自动激活。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,169 @@
---
name: publish
description: 发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。
user_invocable: true
---
# publish - 技能市场发布与通知
发布 ai-proj-helper 的技能变更,重新生成 marketplace.json提交推送到 Gitea并通过飞书 Webhook 通知团队。
## 命令
**`/publish [消息]`** — 发布当前变更并通知飞书
## 流程
```
1. 检查工作目录状态 (git status)
2. 运行 generate-marketplace.py 重新生成 marketplace.json
3. 生成变更摘要(新增/更新/删除了哪些技能)
4. git add + commit + push
5. 发送飞书卡片通知
```
## 详细步骤
### Step 1: 检查工作目录
```bash
cd <ai-proj-helper-root>
git status
```
确认当前在正确的仓库中。如果没有任何变更(包括 marketplace.json提示用户无需发布。
### Step 2: 重新生成 marketplace.json
```bash
cd <ai-proj-helper-root>
python3 generate-marketplace.py
```
输出会显示扫描到的各分类技能数量。
### Step 3: 生成变更摘要
对比 `git diff` 结果,提取变更内容:
- **新增技能**:新出现的 `*-plugin/` 目录
- **更新技能**:已有技能的 SKILL.md 或 plugin.json 变更
- **删除技能**:被移除的 `*-plugin/` 目录
- **配置变更**claude-config.yaml、init.sh 等基础文件变更
摘要格式:
```
新增: feishu-bitable-plugin, doubao-voice-plugin
更新: req-plugin (SKILL.md)
删除: old-plugin
配置: init.sh 默认改为 SSE 模式
```
### Step 4: Git 提交并推送
```bash
cd <ai-proj-helper-root>
git add -A
git commit -m "chore(marketplace): <变更摘要>"
git push origin main
```
Commit message 示例:
- `chore(marketplace): add feishu-bitable-plugin, update req-plugin`
- `chore(marketplace): update init.sh to SSE default`
### Step 5: 飞书通知
**Webhook 地址**:从环境变量 `FEISHU_DEPLOY_WEBHOOK` 读取,配置在 `~/.config/devops/credentials.env`
如果环境变量未设置AskUserQuestion 询问用户提供 webhook URL并建议添加到 credentials.env。
**卡片格式**(必须用 legacy format不用 schema 2.0
```bash
# 先 source 凭据
source ~/.config/devops/credentials.env
# 构建卡片 JSON必须写文件不能直接传中文 JSON
cat > /tmp/publish_notify.json << 'CARD_EOF'
{
"msg_type": "interactive",
"card": {
"header": {
"title": {"tag": "plain_text", "content": "AI 技能市场更新"},
"template": "green"
},
"elements": [
{
"tag": "div",
"text": {"tag": "lark_md", "content": "CHANGE_SUMMARY_HERE"}
},
{
"tag": "div",
"text": {"tag": "lark_md", "content": "**提交**: COMMIT_HASH_HERE"}
},
{
"tag": "action",
"actions": [{
"tag": "button",
"text": {"tag": "plain_text", "content": "查看仓库"},
"type": "primary",
"url": "https://gitea.pipexerp.com/pipexerp/ai-proj-helper"
}]
}
]
}
}
CARD_EOF
# 替换占位符后发送
curl -s -X POST "$FEISHU_DEPLOY_WEBHOOK" \
-H "Content-Type: application/json" \
-d @/tmp/publish_notify.json
```
**重要**
- 必须用 legacy card format无 schema 字段),否则返回 ErrCode 11246
- 中文内容必须先写文件再 `curl -d @file`,直接传会出现 "blank argument" 错误
- `template` 颜色:`green`=成功,`red`=失败,`blue`=信息
### 自定义消息
用户可以在 `/publish` 后附加自定义消息,会追加到卡片内容中:
```
/publish 新增飞书多维表格技能,支持批量数据导入
```
卡片内容将包含:
```
**更新说明**: 新增飞书多维表格技能,支持批量数据导入
**变更**: 新增 feishu-bitable-plugin
**提交**: abc1234
```
## 环境配置
`~/.config/devops/credentials.env` 中添加:
```bash
# 飞书部署通知 Webhook
FEISHU_DEPLOY_WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_WEBHOOK_KEY"
```
## 错误处理
| 场景 | 处理 |
|------|------|
| 无变更可提交 | 提示用户,跳过后续步骤 |
| generate-marketplace.py 失败 | 显示错误,中止发布 |
| git push 失败 | 显示错误,建议手动解决冲突 |
| FEISHU_DEPLOY_WEBHOOK 未配置 | AskUserQuestion 询问 webhook URL |
| 飞书通知发送失败 | 显示 curl 返回值,提示但不阻断(代码已推送成功) |
## 注意事项
- 此技能操作的仓库路径由 marketplace 插件根目录决定
- 发布前确认 `generate-marketplace.py` 输出无异常
- 飞书通知是 best-effort失败不影响代码发布

View File

@@ -1,8 +0,0 @@
{
"name": "agent-swarm-plugin",
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

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

View File

@@ -1,8 +0,0 @@
{
"name": "dev-plugin",
"description": "Plugin for dev",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,314 +0,0 @@
---
name: dev
description: 软件开发技能组入口。整合架构设计(dev-arch)、编码实现(dev-coding)、测试(dev-test)三个子技能提供完整的软件开发工作流。支持全栈开发Go、Vue、React、iOS、Android、小程序等。
---
# 软件开发 Skill (dev)
## 概述
dev 是一个技能组入口,整合了软件开发的三个核心阶段:
| 子技能 | 用途 | 触发词 |
|--------|------|--------|
| **dev-arch** | 架构设计、技术选型、系统设计 | 架构、设计、技术方案 |
| **dev-coding** | 编码实现、功能开发、代码审查 | 编码、开发、实现 |
| **dev-test** | 单元测试、集成测试、E2E测试 | 测试、test、覆盖率 |
---
## 开发工作流
```
需求分析 → 架构设计 → 编码实现 → 测试验证 → 部署上线
↓ ↓ ↓
dev-arch dev-coding dev-test
```
### 典型流程
1. **架构设计** (dev-arch)
- 需求分析
- 技术选型
- 系统设计文档
- 架构评审
2. **编码实现** (dev-coding)
- 任务分解
- 功能开发
- 代码审查
- 文档记录
3. **测试验证** (dev-test)
- 单元测试
- 集成测试
- E2E 测试
- 覆盖率分析
---
## 支持的项目类型
### 当前项目生态
| 项目 | 类型 | 技术栈 |
|------|------|--------|
| **TWMS** | 仓储物流 | Go + Vue 3 + MySQL |
| **AI-Proj** | 项目管理 | Go + React + PostgreSQL + iOS + Android |
| **DICIAI** | 进销存SaaS | Go + Vue 3 + MySQL + Android PDA |
### 技术栈矩阵
| 端 | 语言/框架 | 工具 |
|-----|----------|------|
| **后端** | Go (Gin + GORM) | MySQL/PostgreSQL, Redis, Docker |
| **Web前端** | Vue 3 / React 18 | TypeScript, Vite/CRA, Ant Design |
| **iOS** | Swift + SwiftUI | Xcode, XCTest |
| **Android** | Kotlin + Compose | Gradle, Hilt, Room |
| **PDA** | Android 原生 | 扫码枪集成, 离线存储 |
| **MCP** | TypeScript | Node.js, MCP SDK |
---
## ai-proj 任务管理集成
所有开发工作都通过 ai-proj CLI 进行任务管理:
### 快速开始
```bash
# 1. 查看待办任务
ai-proj task list --status in_progress,todo
# 2. 启动任务
ai-proj task start --id <taskId>
# 3. 完成任务
ai-proj task complete --id <taskId>
# 4. 记录文档
ai-proj task append-doc --id <taskId> --content "实现说明"
```
### 任务分解
```bash
# 创建主任务
ai-proj task create --title "功能名称"
# 创建子任务
ai-proj task create --title "架构设计" --parent-id <parentId>
ai-proj task create --title "功能开发" --parent-id <parentId>
ai-proj task create --title "测试验证" --parent-id <parentId>
```
---
## 常用命令速查
### Go 后端
```bash
# 构建
make build
# 运行
./_output/main --config ./configs/config.yaml
# 测试
make test
make cover
```
### Vue 前端
```bash
# 开发
npm run dev
# 构建
npm run build:prod
# 检查
npm run lint:eslint
```
### React 前端
```bash
# 开发
npm start
# 构建
npm run build
# 测试
npm test
npm run test:e2e
```
### iOS
```bash
# 构建
xcodebuild -scheme ProjectName -configuration Debug
# 测试
xcodebuild test -scheme ProjectName
```
### Android
```bash
# 构建
./gradlew assembleDebug
./gradlew assembleRelease
# 测试
./gradlew test
./gradlew connectedAndroidTest
```
---
## Git 工作流
### 提交规范
| 类型 | 说明 |
|------|------|
| feat | 新功能 |
| fix | Bug 修复 |
| docs | 文档 |
| refactor | 重构 |
| test | 测试 |
| chore | 杂项 |
### 分支策略
```bash
# 功能开发
git checkout -b feature/功能名称
# 提交
git commit -m "feat: 功能描述"
# 推送
git push origin feature/功能名称
# 合并
git checkout main
git merge feature/功能名称
```
### 双电脑同步 (au-dev / cn-dev)
```bash
# 离开时
git add -A
git commit -m "WIP: sync from $(hostname)"
git push origin $(git branch --show-current)
# 到达时
git fetch origin
git pull origin $(git branch --show-current)
```
---
## Docker 部署
### 标准配置
```yaml
services:
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- db
- redis
frontend:
build: ./frontend
ports:
- "80:80"
db:
image: mysql:8.0
# 或 postgres:15
redis:
image: redis:alpine
```
### 常用端口
| 服务 | 端口 |
|------|------|
| Backend | 8080 / 9099 |
| Frontend | 80 / 3000 |
| MySQL | 3306 |
| PostgreSQL | 5432 |
| Redis | 6379 |
---
## 子技能详情
### dev-arch (架构设计)
用于系统设计阶段:
- 需求分析
- 技术选型
- 架构设计文档
- API 设计
- 数据库设计
- 架构评审
### dev-coding (编码实现)
用于开发实现阶段:
- Go 后端开发
- Vue/React 前端开发
- iOS/Android 移动开发
- PDA 应用开发
- MCP 桥接开发
- 代码审查
### dev-test (测试)
用于测试验证阶段:
- 单元测试
- 集成测试
- E2E 测试
- UI 测试
- 覆盖率分析
---
## 最佳实践
1. **任务驱动** - 使用 ai-proj 管理所有开发任务
2. **设计先行** - 复杂功能先设计后编码
3. **分层清晰** - Controller → Service → Repository
4. **小步提交** - 频繁提交,每次做一件事
5. **测试覆盖** - 核心逻辑必须有测试
6. **文档同步** - 代码变更同步更新文档
7. **代码审查** - 重要变更必须审查
---
## 何时使用哪个子技能
| 场景 | 推荐技能 |
|------|----------|
| 新功能设计 | dev-arch |
| 技术方案评审 | dev-arch |
| 功能开发实现 | dev-coding |
| Bug 修复 | dev-coding |
| 编写测试 | dev-test |
| 测试覆盖率提升 | dev-test |
| 代码审查 | dev-coding |
| 性能优化 | dev-arch + dev-coding |

View File

@@ -1,8 +0,0 @@
{
"name": "finishing-a-development-branch-plugin",
"description": "Plugin for finishing-a-development-branch",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

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

View File

@@ -1,8 +0,0 @@
{
"name": "frontend-design-plugin",
"description": "Plugin for frontend-design",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

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

View File

@@ -1,8 +0,0 @@
{
"name": "gitea-plugin",
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,211 +0,0 @@
#!/bin/bash
# gitea-runs — Gitea Actions CLI helper
# Usage:
# gitea-runs List recent runs
# gitea-runs list [limit] List recent runs (default 10)
# gitea-runs view <run_number> View run details & jobs
# gitea-runs open [run_number] Open run in browser
# gitea-runs workflows List workflows
# gitea-runs dispatch <wf> [ref] Trigger a workflow dispatch
# gitea-runs help Show this help
set -e
# Config from tea CLI
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/Library/Application Support}/tea/config.yml"
if [ ! -f "$TEA_CONFIG" ]; then
TEA_CONFIG="$HOME/.config/tea/config.yml"
fi
# Parse tea config (nested under logins)
GITEA_URL=$(grep 'url:' "$TEA_CONFIG" | head -1 | awk '{print $NF}')
GITEA_TOKEN=$(grep 'token:' "$TEA_CONFIG" | head -1 | awk '{print $NF}')
# Detect repo from git remote
REPO=$(git remote get-url origin 2>/dev/null | sed 's|.*gitea.pipexerp.com[:/]*||;s|\.git$||;s|^10022/||')
if [ -z "$REPO" ]; then
echo "Error: not in a git repo or remote not configured"
exit 1
fi
API="$GITEA_URL/api/v1"
AUTH="Authorization: token $GITEA_TOKEN"
GREEN='\033[0;32m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m'
cmd_dispatch() {
local workflow="${1:-}"
local ref="${2:-main}"
if [ -z "$workflow" ]; then
echo "Usage: gitea-runs dispatch <workflow> [ref]"
echo ""
echo "Available workflows:"
curl -s -H "$AUTH" "$API/repos/$REPO/actions/workflows" 2>/dev/null \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for w in data.get('workflows', []):
print(f\" {w['id']:30s} {w['name']}\")
" 2>/dev/null
return
fi
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
-H "$AUTH" \
-H "Content-Type: application/json" \
-X POST "$API/repos/$REPO/actions/workflows/$workflow/dispatches" \
-d "{\"ref\":\"$ref\"}" 2>/dev/null)
if [ "$http_code" = "204" ]; then
echo -e "${GREEN}✓${NC} Dispatched workflow: $workflow (ref: $ref)"
echo " View: $GITEA_URL/$REPO/actions"
else
echo -e "${RED}✗${NC} Failed to dispatch (HTTP $http_code)"
fi
}
cmd_workflows() {
echo -e "${CYAN}Workflows for $REPO${NC}"
echo ""
curl -s -H "$AUTH" "$API/repos/$REPO/actions/workflows" 2>/dev/null \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for w in data.get('workflows', []):
state = '✓' if w['state'] == 'active' else '✗'
print(f\" {state} {w['id']:30s} {w['name']}\")
" 2>/dev/null
}
cmd_list() {
local limit="${1:-10}"
echo -e "${CYAN}Recent runs for $REPO${NC}"
echo ""
curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs?limit=$limit" 2>/dev/null \
| python3 -c "
import json, sys
limit = $limit
data = json.load(sys.stdin)
for r in data.get('workflow_runs', [])[:limit]:
status = r.get('status', '?')
num = r.get('run_number', 0)
title = r.get('display_title', '')[:60]
wf = r.get('path', '')
wf = wf.split('@')[0] if '@' in wf else wf
icon = {'success':'\u2713','completed':'\u2713','failure':'\u2717','cancelled':'\u2717','in_progress':'\u27f3','running':'\u27f3','queued':'\u25cc','waiting':'\u25cc'}.get(status, '?')
color = {'success':'\033[0;32m','completed':'\033[0;32m','failure':'\033[0;31m','cancelled':'\033[0;31m','in_progress':'\033[0;33m','running':'\033[0;33m'}.get(status, '\033[0;37m')
print(f\"{color}{icon}\033[0m #{num:<4} {status:<12} {wf:<20} {title}\")
" 2>/dev/null
}
cmd_view() {
local run_number="${1:-}"
if [ -z "$run_number" ]; then
echo "Usage: gitea-runs view <run_number>"
return 1
fi
# Find run by run_number (API uses internal id, html uses run_number)
local run_data
run_data=$(curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs?limit=50" 2>/dev/null \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('workflow_runs', []):
if r['run_number'] == $run_number:
print(json.dumps(r))
break
" 2>/dev/null)
if [ -z "$run_data" ]; then
echo -e "${RED}✗${NC} Run #$run_number not found"
return 1
fi
local run_id
run_id=$(echo "$run_data" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
# Print run info
echo "$run_data" | python3 -c "
import json, sys
r = json.load(sys.stdin)
status = r.get('status', '?')
icon = {'success':'\u2713','failure':'\u2717','in_progress':'\u27f3','queued':'\u25cc'}.get(status, '?')
color = {'success':'\033[0;32m','failure':'\033[0;31m','in_progress':'\033[0;33m'}.get(status, '\033[0;37m')
print(f\"{color}{icon} Run #{r.get('run_number',0)} \u2014 {status}\033[0m\")
print(f\" Title: {r.get('display_title','')}\")
print(f\" Event: {r.get('event','')}\")
print(f\" Branch: {r.get('head_branch','')}\")
print(f\" Commit: {r.get('head_sha','')[:8]}\")
print(f\" Actor: {r.get('actor',{}).get('login','')}\")
wf = r.get('path', '')
wf = wf.split('@')[0] if '@' in wf else wf
print(f\" Workflow: {wf}\")
" 2>/dev/null
# Print jobs
echo ""
echo -e "${CYAN}Jobs:${NC}"
curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs/$run_id/jobs" 2>/dev/null \
| python3 -c "
import json, sys
from datetime import datetime
data = json.load(sys.stdin)
for j in data.get('jobs', []):
status = j.get('status', '?')
icon = {'success':'\u2713','failure':'\u2717','in_progress':'\u27f3','queued':'\u25cc','waiting':'\u25cc'}.get(status, '?')
color = {'success':'\033[0;32m','failure':'\033[0;31m','in_progress':'\033[0;33m'}.get(status, '\033[0;37m')
runner = j.get('runner_name', '-')
started = j.get('started_at', '')[:19].replace('T', ' ')
completed = j.get('completed_at', '')[:19].replace('T', ' ')
duration = ''
if completed and not completed.startswith('1970'):
try:
d = datetime.fromisoformat(completed) - datetime.fromisoformat(started)
duration = f' ({int(d.total_seconds())}s)'
except: pass
print(f\" {color}{icon}\033[0m {j.get('name',''):<30} {status:<12} runner: {runner}{duration}\")
" 2>/dev/null
}
cmd_open() {
local run_id="${1:-}"
local url="$GITEA_URL/$REPO/actions"
if [ -n "$run_id" ]; then
url="$url/runs/$run_id"
fi
echo "Opening: $url"
open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null || echo "$url"
}
cmd_help() {
echo "gitea-runs — Gitea Actions CLI helper"
echo ""
echo "Usage:"
echo " gitea-runs List recent runs"
echo " gitea-runs list [limit] List recent runs (default 10)"
echo " gitea-runs view <run_number> View run details & jobs"
echo " gitea-runs open [run_number] Open run in browser"
echo " gitea-runs workflows List workflows"
echo " gitea-runs dispatch <wf> [ref] Trigger a workflow dispatch"
echo " gitea-runs help Show this help"
echo ""
echo "Repo: $REPO"
echo "Gitea: $GITEA_URL"
}
# Main
case "${1:-}" in
list|ls) shift; cmd_list "$@" ;;
view|v) shift; cmd_view "$@" ;;
dispatch) shift; cmd_dispatch "$@" ;;
workflows|wf) cmd_workflows ;;
open|o) shift; cmd_open "$@" ;;
help|--help|-h) cmd_help ;;
"") cmd_list ;;
*) cmd_view "$1" ;;
esac

View File

@@ -1,281 +0,0 @@
---
name: gitea
description: Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。当用户提到 Gitea、Actions、Runner、CI/CD workflow、PR 检查相关任务时自动激活。
---
# Gitea Skill
Gitea 代码托管平台管理,覆盖 Actions CI/CD、Runner、PR、仓库配置。
## 服务器信息
| 服务 | 地址 | SSH |
|------|------|-----|
| Gitea Web | https://gitea.pipexerp.com | — |
| Gitea SSH | gitea.pipexerp.com:10022 | `ssh -i ~/.ssh/id_ed25519 git@gitea.pipexerp.com -p 10022` |
| Gitea 服务器 | 123.56.89.187 | `ssh -i ~/.ssh/tools.pem root@123.56.89.187` |
| Runner 服务器 | 101.200.136.200 (Jenkins 服务器) | `ssh -i ~/.ssh/tools.pem root@101.200.136.200` |
## API 访问
```bash
# Gitea API Token (仓库级)
GITEA_TOKEN="483a2b65219625ee382eb6d023cda39238c32e24"
# 通用请求格式
curl -s "https://gitea.pipexerp.com/api/v1/repos/pipexerp/<repo>/..." \
-H "Authorization: token $GITEA_TOKEN"
```
### 常用 API
| 操作 | 方法 | 端点 |
|------|------|------|
| 创建 PR | POST | `/repos/{owner}/{repo}/pulls` |
| 更新 PR | PATCH | `/repos/{owner}/{repo}/pulls/{id}` |
| 列出 Runs | GET | `/repos/{owner}/{repo}/actions/runs` |
| Run 详情 | GET | `/repos/{owner}/{repo}/actions/runs/{id}` |
| Job 详情 | GET | `/repos/{owner}/{repo}/actions/runs/{id}/jobs` |
| 手动触发 Workflow | POST | `/repos/{owner}/{repo}/actions/workflows/{file}/dispatches` body: `{"ref":"main"}` |
| 获取 Runner Token | POST | `/repos/{owner}/{repo}/actions/runners/registration-token` |
| 添加 Secret | PUT | `/repos/{owner}/{repo}/actions/secrets/{name}` body: `{"data":"value"}` |
| 删除 Run仅已完成| DELETE | `/repos/{owner}/{repo}/actions/runs/{id}` |
**注意**: Gitea 1.25 **不支持**通过 API cancel 正在排队/运行的 run。
## 仓库
| 仓库 | 地址 | 主分支 |
|------|------|--------|
| coolbuy-paas | pipexerp/coolbuy-paas | main |
| dotfiles | huangjun/dotfiles | main |
| claude-marketplace | huangjun/claude-marketplace | main |
## Actions Runners
### 主 Runner (lint/test/e2e)
| 项目 | 值 |
|------|-----|
| 名称 | jenkins-runner |
| 配置 | `/opt/act_runner/config.yaml` |
| Capacity | 3 |
| Labels | `ubuntu-latest`, `ubuntu-22.04`, `ubuntu-20.04` |
| 进程 | `/usr/local/bin/act_runner daemon --config /opt/act_runner/config.yaml` |
### Deploy Runner (staging 部署专用)
| 项目 | 值 |
|------|-----|
| 名称 | deploy-runner |
| 配置 | `/opt/act_runner_deploy/config.yaml` |
| Capacity | 1 |
| Labels | `deploy:host` |
| PID | `/opt/act_runner_deploy/runner.pid` |
| 日志 | `/opt/act_runner_deploy/runner.log` |
| 启动 | `cd /opt/act_runner_deploy && nohup act_runner daemon --config config.yaml > runner.log 2>&1 &` |
### 注册新 Runner
```bash
# 1. 获取 registration token
curl -s -X POST "https://gitea.pipexerp.com/api/v1/repos/pipexerp/coolbuy-paas/actions/runners/registration-token" \
-H "Authorization: token $GITEA_TOKEN"
# 2. SSH 到 runner 服务器
ssh -i ~/.ssh/tools.pem root@101.200.136.200
# 3. 创建目录和配置
mkdir -p /opt/act_runner_<name>
cat > /opt/act_runner_<name>/config.yaml << 'EOF'
log:
level: info
runner:
file: .runner
capacity: 1
timeout: 30m
labels:
- "<label>:host" # host 模式用系统 shell
# 或 "<label>:docker://image" # docker 模式
cache:
enabled: false
EOF
# 4. 注册
cd /opt/act_runner_<name>
act_runner register --instance https://gitea.pipexerp.com \
--token <TOKEN> --name <NAME> --labels '<LABEL>:host' \
--config config.yaml --no-interactive
# 5. 启动
nohup act_runner daemon --config config.yaml > runner.log 2>&1 &
echo $! > runner.pid
```
### Runner 运维
```bash
# 检查 runner 状态
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "ps aux | grep act_runner | grep -v grep"
# 查看 deploy runner 日志
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "tail -20 /opt/act_runner_deploy/runner.log"
# 重启 deploy runner
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "
kill \$(cat /opt/act_runner_deploy/runner.pid) 2>/dev/null
cd /opt/act_runner_deploy
nohup act_runner daemon --config config.yaml > runner.log 2>&1 &
echo \$! > runner.pid
"
```
## Workflows (coolbuy-paas)
| Workflow | 触发 | Runner | paths-ignore | 用途 |
|----------|------|--------|-------------|------|
| 🚀 deploy-staging.yml | push → main | `deploy` | md, docs, .gitea, scripts, *_test.go | 触发 Jenkins 部署到 staging |
| 🔍 lint.yml | PR → main | `ubuntu-latest` | md, docs, .gitea, scripts | Go lint + ESLint auto-fix |
| 🧪 unit-test.yml | PR → main | `ubuntu-latest` | md, docs, .gitea, scripts | 4 个 Go 服务单元测试 |
| 🎭 e2e-tests.yml | schedule 12h | `ubuntu-latest` | — | Playwright E2E仅定时 |
| 📋 notify-aiproj.yml | PR merged | `ubuntu-latest` | — | 同步需求状态到 ai-proj |
| 📦 build.yaml | 手动 | `ubuntu-latest` | — | Docker 构建推 Hub |
### Workflow 编写规范
```yaml
# 1. 名称加 emoji 前缀
name: "🚀 Deploy Staging"
# 2. 非代码变更加 paths-ignore
on:
push:
branches: [main]
paths-ignore:
- '*.md'
- 'docs/**'
- '.gitea/**'
- 'scripts/**'
# 3. 加 concurrency 防重复
concurrency:
group: deploy-staging
cancel-in-progress: true
# 4. 仅定时的 workflow 加 event 守卫
jobs:
e2e:
if: github.event_name == 'schedule'
# 5. auto-fix 提交加 [skip ci]
git commit -m "style: auto-fix [skip ci]"
```
### Checkout 模式(容器内)
Gitea Actions 不支持 `actions/checkout`,用原生 git
```yaml
- name: Checkout
env:
TOKEN: ${{ github.token }}
run: |
git config --global --add safe.directory "$(pwd)"
git init
git remote add origin "https://oauth2:${TOKEN}@gitea.pipexerp.com/${{ github.repository }}.git"
git fetch origin "${{ github.event.pull_request.head.ref }}"
git checkout -b pr-branch "origin/${{ github.event.pull_request.head.ref }}"
git config user.name "CI Bot"
git config user.email "ci@pipexerp.com"
```
## Secrets 管理
### 当前 Secrets (coolbuy-paas 仓库级)
| Secret | 用途 |
|--------|------|
| `JENKINS_USER` | Jenkins API 用户名 |
| `JENKINS_TOKEN` | Jenkins API Token |
| `DOCKER_HUB_TOKEN` | Docker Hub 推送 |
| `AI_PROJ_TOKEN` | ai-proj API 认证 |
### 添加/更新 Secret
```bash
curl -s -X PUT \
"https://gitea.pipexerp.com/api/v1/repos/pipexerp/coolbuy-paas/actions/secrets/<NAME>" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"data": "<VALUE>"}'
```
## CI/CD 完整流程
```
PR → main
├── 🧪 unit-test.yml (Go 服务测试)
├── 🔍 lint.yml (auto-fix 格式)
└── merge 后:
├── 📋 notify-aiproj.yml (需求状态 → testing)
└── 🚀 deploy-staging.yml (Jenkins → staging)
├── ≥5 commits/2h → 立即部署
└── <5 commits → 等3分钟 debounce
定时:
└── 🎭 e2e-tests.yml (每12h Playwright)
手动:
└── 📦 build.yaml (Docker 构建推 Hub)
生产部署:
└── ./scripts/build-and-push.sh prod --deploy (触发 Jenkins)
```
## 本地 CLI 工具
### tea CLI (Gitea 官方命令行)
tea 是 Gitea 官方 CLI 客户端,已配置好认证信息。
```bash
# 配置文件位置
~/Library/Application Support/tea/config.yml
# 或 ~/.config/tea/config.yml
# gitea-runs 脚本从 tea config 读取 url 和 token
```
### gitea-runs (Actions 快捷命令)
位置: `~/.local/bin/gitea-runs`
自动从 git remote 检测仓库,从 tea CLI 配置读取认证信息。
| 命令 | 说明 |
|------|------|
| `gitea-runs` | 列出最近 10 条 run |
| `gitea-runs list [N]` | 列出最近 N 条 run |
| `gitea-runs view <run_number>` | 查看 run 详情和 jobs |
| `gitea-runs open [run_number]` | 在浏览器打开 run 页面 |
| `gitea-runs workflows` | 列出所有 workflow |
| `gitea-runs dispatch <wf> [ref]` | 手动触发 workflow |
```bash
# 示例
gitea-runs # 查看最近 runs
gitea-runs view 303 # 查看 run #303 详情
gitea-runs dispatch deploy-staging.yml main # 手动触发部署
gitea-runs open # 打开 Actions 页面
```
**优先使用 `gitea-runs` 而非 curl API**,更简洁且自动处理认证。
## 常见问题
| 问题 | 原因 | 解决 |
|------|------|------|
| Run 一直 queued | Runner 被占满 | 等其他 job 完成,或加 runner |
| deploy 被 test 阻塞 | 共用 runner | 用 `runs-on: deploy` 专属 runner |
| Workflow 被误触发 | push 新 workflow 文件到 main | 加 `if: github.event_name == 'schedule'` 守卫 |
| auto-fix 无限循环 | 提交触发新 run | 提交信息加 `[skip ci]` |
| API 无法 cancel run | Gitea 1.25 限制 | 网页手动取消,或等完成后 DELETE |
| `date -d` 报错 | 容器 date 不兼容 | 用 host 模式 runner或兼容写法 |

View File

@@ -199,3 +199,50 @@ One paragraph explaining the motivation.
tea pr merge 42 tea pr merge 42
``` ```
## Finishing a Branch
Verify tests pass, then create PR. Use after implementation is complete.
**Core principle:** Verify tests → Create PR → Done.
### Process
1. **Verify Tests** — Run project's test suite before creating PR:
```bash
npm test / cargo test / pytest / go test ./... / mvn test
```
- Tests fail → Stop, show failures, fix first. Cannot proceed.
- Tests pass → Continue to step 2.
2. **Create PR** — Use `/pr create` (checks for existing PR, avoids duplicates). Report PR URL.
3. **Cleanup Worktree** (if applicable):
```bash
git worktree list | grep $(git branch --show-current)
# If in worktree, ask user to confirm removal
git worktree remove <worktree-path>
```
**Never:** Create PR with failing tests. Skip test verification. Force-push without request.
## Plan Execution
Load plan → create branch → execute tasks in batches → report for review between batches.
### Process
1. **Load Plan**: Read plan file, review critically, raise concerns before starting
2. **Setup Branch**: Use `/pr start` or manual `git checkout -b <type>/<name> origin/main`
3. **Execute Batch**: Default 3 tasks per batch, mark in_progress → completed
4. **Report**: Show implementation + verification output. Say: "Ready for feedback."
5. **Continue**: Apply feedback, execute next batch, repeat
6. **Complete**: Use "Finishing a Branch" workflow above
### Stop Conditions
- Hit blocker (missing dependency, test fails, instruction unclear)
- Plan has critical gaps preventing starting
- Verification fails repeatedly
**Ask for clarification rather than guessing.**

View File

@@ -1,8 +0,0 @@
{
"name": "openclaw-ops-plugin",
"description": "Plugin for openclaw-ops",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,797 +0,0 @@
# OpenClaw 运维技能
OpenClaw 容器化部署、运维监控、故障排查完整指南。
## 目录
- [服务器部署](#服务器部署)
- [容器管理](#容器管理)
- [性能优化](#性能优化)
- [故障排查](#故障排查)
- [最佳实践](#最佳实践)
---
## 服务器部署
### 懒猫算力仓 (lazycat)
**服务器信息**
- 主机名haiqing.heiyu.space
- SSH 别名lazycat, lanmao
- 用途OpenClaw 算力服务
- 系统Debian-based Linux
- 容器平台lzc-docker
**OpenClaw 容器信息**
- 容器 ID5f3bf33e090b
- 镜像registry.lazycat.cloud/openclaw:1.1.5
- OpenClaw 版本2026.2.9
- 容器名iamxiaoelzcappopenclaw-openclaw-1
**访问方式**
```bash
# SSH 连接
ssh lazycat
# 进入容器
ssh lazycat "lzc-docker exec -it 5f3bf33e090b bash"
# 启动 OpenClaw TUI
openclaw-tui # 使用本地快捷脚本
```
---
## 容器管理
### 快捷访问脚本
**~/bin/openclaw-tui**
```bash
#!/bin/bash
# OpenClaw TUI 快捷访问脚本(自动启动 Gateway
set -e
echo "🦞 连接到龙虾服务器 (懒猫)..."
echo ""
# 检查并启动 Gateway
echo "检查 OpenClaw Gateway 状态..."
GATEWAY_STATUS=$(ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status" 2>/dev/null | grep "RPC probe" || echo "failed")
if echo "$GATEWAY_STATUS" | grep -q "ok"; then
echo "✅ Gateway 已运行"
else
echo "🔧 启动 Gateway..."
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'nohup openclaw gateway run > /tmp/gateway.log 2>&1 &'" 2>/dev/null
sleep 2
echo "✅ Gateway 已启动"
fi
echo ""
echo "启动 OpenClaw TUI..."
# SSH 到懒猫服务器,然后进入 Docker 容器并启动 OpenClaw TUI
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b bash -c 'openclaw tui'"
```
### 容器操作命令
```bash
# 查看容器状态
ssh lazycat "lzc-docker ps | grep openclaw"
# 查看容器日志
ssh lazycat "lzc-docker logs -f 5f3bf33e090b --tail 100"
# 重启容器
ssh lazycat "lzc-docker restart 5f3bf33e090b"
# 查看容器资源使用
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
# 进入容器 shell
ssh lazycat "lzc-docker exec -it 5f3bf33e090b bash"
```
### Gateway 管理
```bash
# 检查 Gateway 状态
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status"
# 启动 Gateway前台
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway run"
# 启动 Gateway后台
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'nohup openclaw gateway run > /tmp/gateway.log 2>&1 &'"
# 停止 Gateway
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -f 'openclaw-gateway'"
# 查看 Gateway 日志
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -f /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log"
```
---
## 性能优化
### 资源配置
**当前配置**(接近系统上限,确保充足性能):
- 内存限制30GB系统 97%
- 内存+交换32GB
- CPU 限制8.0 核心(系统 100%
- 进程限制10,000 个
```bash
# 查看资源限制配置
ssh lazycat "lzc-docker inspect 5f3bf33e090b --format='
内存限制: {{.HostConfig.Memory}} bytes
内存+交换: {{.HostConfig.MemorySwap}} bytes
CPU配额: {{.HostConfig.CpuQuota}}
CPU周期: {{.HostConfig.CpuPeriod}}
PID限制: {{.HostConfig.PidsLimit}}
'"
# 查看实时资源使用
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
```
**配置说明**
- 懒猫算力仓的主要职责是提供 OpenClaw 服务
- 资源限制设置为接近系统上限,确保有充足资源运行
- 同时提供基本的失控保护机制
### 自动化优化措施
#### 1. 定期自动重启(每周日 03:00
**目的**:清理累积的僵尸进程,释放资源
**查看状态**
```bash
# 查看定时任务状态
ssh lazycat "systemctl status openclaw-restart.timer"
# 查看重启日志
ssh lazycat "tail -50 /var/log/openclaw-restart.log"
# 手动执行重启
ssh lazycat "/root/restart-openclaw.sh"
```
**配置文件**
- Service: `/etc/systemd/system/openclaw-restart.service`
- Timer: `/etc/systemd/system/openclaw-restart.timer`
- 脚本: `/root/restart-openclaw.sh`
**重启脚本** (`/root/restart-openclaw.sh`)
```bash
#!/bin/bash
# OpenClaw 容器定期重启脚本
# 每周日凌晨3点执行
LOG_FILE='/var/log/openclaw-restart.log'
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始重启 OpenClaw 容器" >> $LOG_FILE
# 重启容器
/lzcsys/bin/lzc-docker restart 5f3bf33e090b >> $LOG_FILE 2>&1
# 等待容器启动
sleep 10
# 检查健康状态
STATUS=$(/lzcsys/bin/lzc-docker inspect -f '{{.State.Health.Status}}' 5f3bf33e090b 2>/dev/null || echo 'unknown')
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 重启完成,健康状态: $STATUS" >> $LOG_FILE
# 检查僵尸进程
ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 当前僵尸进程数: $ZOMBIE_COUNT" >> $LOG_FILE
echo "----------------------------------------" >> $LOG_FILE
```
#### 2. 僵尸进程自动监控(每小时检查)
**目的**:监控僵尸进程数量,超过阈值自动重启容器
**查看状态**
```bash
# 查看监控状态
ssh lazycat "systemctl status openclaw-zombie-monitor.timer"
# 查看监控日志
ssh lazycat "tail -50 /var/log/openclaw-zombie-monitor.log"
# 手动检查僵尸进程
ssh lazycat "/root/monitor-openclaw-zombies.sh"
# 直接查看僵尸进程数
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l"
```
**监控参数**
- 检查频率:每小时
- 触发阈值50 个僵尸进程
- 自动操作:重启容器
**监控脚本** (`/root/monitor-openclaw-zombies.sh`)
```bash
#!/bin/bash
# OpenClaw 僵尸进程监控脚本
# 当僵尸进程超过50个时自动重启容器
ZOMBIE_THRESHOLD=50
CONTAINER_ID='5f3bf33e090b'
LOG_FILE='/var/log/openclaw-zombie-monitor.log'
# 检查僵尸进程数量
ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec $CONTAINER_ID ps aux 2>/dev/null | grep -c 'Z' || echo '0')
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 僵尸进程数: $ZOMBIE_COUNT" >> $LOG_FILE
if [ $ZOMBIE_COUNT -gt $ZOMBIE_THRESHOLD ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 僵尸进程超过阈值($ZOMBIE_THRESHOLD),执行自动重启" >> $LOG_FILE
# 重启容器
/lzcsys/bin/lzc-docker restart $CONTAINER_ID >> $LOG_FILE 2>&1
# 等待容器启动
sleep 10
# 再次检查
NEW_ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec $CONTAINER_ID ps aux 2>/dev/null | grep -c 'Z' || echo '0')
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 重启后僵尸进程数: $NEW_ZOMBIE_COUNT" >> $LOG_FILE
echo "----------------------------------------" >> $LOG_FILE
fi
```
#### 3. 全面健康检查
```bash
# 一键健康检查脚本
ssh lazycat "
echo '=== 系统负载 ===' && uptime &&
echo '' && echo '=== 僵尸进程 ===' &&
lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l &&
echo '' && echo '=== 容器资源 ===' &&
lzc-docker stats --no-stream 5f3bf33e090b &&
echo '' && echo '=== Gateway 状态 ===' &&
lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe' &&
echo '' && echo '=== 容器健康 ===' &&
lzc-docker inspect 5f3bf33e090b --format='Status: {{.State.Status}}, Health: {{.State.Health.Status}}'
"
# 查看所有定时任务
ssh lazycat "systemctl list-timers | grep openclaw"
```
---
## 故障排查
### Tower 反复崩溃(已修复 2026-02-16
**现象**
- Tower 日志显示反复崩溃:`[tower] OpenClaw crashed: exit status 1`
- Gateway 启动失败:`gateway already running (pid xxx); lock timeout`
- 僵尸 Gateway 进程堆积,无法回收
- 日志中出现多个僵尸进程:`[openclaw-gatewa] <defunct>`
**典型错误日志**
```
[22:19:39] [tower] OpenClaw crashed: exit status 1
[22:24:52] [tower] OpenClaw crashed: signal: killed
[22:27:33] Gateway failed to start: gateway already running (pid 2005)
[22:27:33] If the gateway is supervised, stop it with: openclaw gateway stop
```
**根本原因**
- Tower 作为容器 PID 1 进程,不是专业的 init 进程
- 缺少子进程回收reaping机制导致僵尸进程未被清理
- 僵尸进程占用锁文件和端口18789阻塞新 Gateway 启动
- 容器 PID 1 是 `/usr/local/bin/tower`,没有僵尸进程回收能力
**诊断命令**
```bash
# 查看 PID 1 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
# 查看僵尸进程详情
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'defunct'"
# 检查端口占用
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
# 查看进程树
ssh lazycat "lzc-docker exec 5f3bf33e090b ps auxf | head -30"
```
**永久解决方案(已实施)**
使用 **tini** 作为容器 PID 1自动回收僵尸进程。
```bash
# 1. 在容器中安装 tini专业 init 进程)
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'apt-get update -qq && apt-get install -y tini'"
# 2. 修改 entrypoint 使用 tini 包装 tower
ssh lazycat "lzc-docker exec 5f3bf33e090b sed -i 's|exec /usr/local/bin/tower|exec /usr/bin/tini -- /usr/local/bin/tower|g' /usr/local/bin/clawdbot-entrypoint.sh"
# 3. 验证修改
ssh lazycat "lzc-docker exec 5f3bf33e090b grep 'exec.*tower' /usr/local/bin/clawdbot-entrypoint.sh"
# 应该看到: exec /usr/bin/tini -- /usr/local/bin/tower ...
# 4. 重启容器使修改生效
ssh lazycat "lzc-docker restart 5f3bf33e090b"
# 5. 验证 tini 已成为 PID 1
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
# 输出应显示: PID 1 -> /usr/bin/tini -- /usr/local/bin/tower ...
# 6. 检查进程树
ssh lazycat "lzc-docker exec 5f3bf33e090b ps auxf | head -15"
```
**修复后的进程架构**
```
PID 1: /usr/bin/tini (专业 init 进程,自动回收僵尸进程)
└─ PID 58: tower
└─ PID 64: openclaw
└─ PID 72: openclaw-gateway
```
**修复效果**
- ✅ Tini 作为 PID 1自动回收所有僵尸进程
- ✅ 僵尸进程数量从 5+ 个降至 1-2 个(健康水平)
- ✅ Tower 稳定运行,不再反复崩溃
- ✅ Gateway 启动正常,无锁文件冲突
- ✅ RPC probe 持续显示 ok
**注意事项**
- ⚠️ 当前修改在运行容器内,**容器重建后需重新应用**
- 💡 建议向镜像维护者(懒猫云)提交 PR在 Dockerfile 中添加 tini
- 📌 每次从镜像重新创建容器时,需要重新执行上述步骤 1-4
**镜像级永久修复**(建议提交给懒猫云):
在 OpenClaw 镜像的 Dockerfile 中添加:
```dockerfile
# 安装 tini
RUN apt-get update && apt-get install -y tini && rm -rf /var/lib/apt/lists/*
# 或使用更轻量的安装方式
ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini /usr/bin/tini
RUN chmod +x /usr/bin/tini
# 在 entrypoint 脚本中使用 tini 包装(已在当前镜像的 entrypoint 中修改)
```
### 僵尸进程过多
**现象**
- 僵尸进程数超过 50 个
- Gateway 响应变慢
- 容器内存占用升高
**诊断**
```bash
# 查看僵尸进程详情
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'Z'"
# 统计僵尸进程数量
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
# 查看僵尸进程父进程
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -eo pid,ppid,stat,comm | grep 'Z'"
```
**解决方案**
```bash
# 方案 1重启容器推荐
ssh lazycat "lzc-docker restart 5f3bf33e090b"
# 方案 2手动清理 Gateway 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-gateway'"
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway run &"
# 验证清理效果
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
```
### Gateway 无响应
**现象**
- `RPC probe: failed` 或超时
- TUI 连接失败:`gateway not connected`
- Dashboard 无法访问
**诊断**
```bash
# 检查 Gateway 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep gateway"
# 检查端口监听
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
# 查看 Gateway 日志
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -100 /tmp/openclaw/openclaw-*.log"
# 测试本地连接
ssh lazycat "lzc-docker exec 5f3bf33e090b curl -I http://127.0.0.1:18789"
```
**解决方案**
```bash
# 1. 杀死所有 Gateway 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-gateway'"
# 2. 启动新的 Gateway
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'openclaw gateway run > /tmp/gateway.log 2>&1 &'"
# 3. 等待启动
sleep 5
# 4. 验证状态
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status"
```
### 多个 OpenClaw TUI 实例运行(已修复 2026-02-16
**现象**
- 每次启动 OpenClaw TUI 前需要 `pkill -9 openclaw`
- 启动失败或端口冲突
- 多个 `openclaw-tui` 进程在后台运行
- 容器资源占用异常高
**诊断**
```bash
# 检查运行中的 OpenClaw 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep openclaw"
# 通常会看到多个 openclaw-tui 实例:
# PID 3041 - openclaw-tui (pts/0)
# PID 6338 - openclaw-tui (pts/1)
# PID 7223 - openclaw-tui (pts/2)
# 检查端口占用
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
```
**根本原因**
- 每次运行 `openclaw tui` 都启动新进程
- 退出 TUI 时进程没有完全清理
- 多个实例同时运行导致资源竞争
**永久解决方案(已实施)**
**1. 创建自动清理脚本**(容器中):
```bash
# 在容器中创建 /usr/local/bin/openclaw-clean
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c \"cat > /usr/local/bin/openclaw-clean << 'EOF'
#!/bin/bash
# OpenClaw 清理并重启脚本
# 清理所有非 Tower 管理的 openclaw 进程
echo '🧹 清理旧的 OpenClaw 进程...'
pkill -9 -f 'openclaw-tui' || true
pkill -9 -f 'openclaw tui' || true
# 等待进程完全退出
sleep 1
# 检查剩余进程
REMAINING=\\\$(ps aux | grep -E 'openclaw' | grep -v 'openclaw-gateway' | grep -v 'tower' | grep -v 'grep' | wc -l)
if [ \\\$REMAINING -gt 0 ]; then
echo '⚠️ 警告:还有 '\\\$REMAINING' 个 openclaw 进程'
else
echo '✅ 清理完成'
fi
# 启动 OpenClaw TUI
echo ''
echo '🦞 启动 OpenClaw TUI...'
exec openclaw tui
EOF
chmod +x /usr/local/bin/openclaw-clean\""
```
**2. 更新本地 openclaw-tui 脚本**
修改 `~/bin/openclaw-tui` 的最后一行:
```bash
# 修改前
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b bash -c 'openclaw tui'"
# 修改后
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b openclaw-clean"
```
**修复效果**
- ✅ 每次启动自动清理旧进程
- ✅ 不再需要手动 `pkill -9 openclaw`
- ✅ 避免多实例导致的资源浪费
- ✅ 一条命令 `openclaw-tui` 搞定所有
**使用方法**
```bash
# 以前(需要手动清理)
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'pkill -9 openclaw && openclaw tui'"
# 现在(自动清理)
openclaw-tui # 一条命令搞定!
```
**手动清理**(如果需要):
```bash
# 清理所有 openclaw-tui 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-tui'"
# 验证清理结果
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep openclaw | grep -v tower | grep -v openclaw-gateway"
```
### 容器内存不足
**现象**
- 容器内存使用率超过 90%
- OOM (Out of Memory) 错误
- 进程被 killed
**诊断**
```bash
# 检查内存使用
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
# 查看内存限制
ssh lazycat "lzc-docker inspect 5f3bf33e090b --format='{{.HostConfig.Memory}}'"
# 查看系统总内存
ssh lazycat "free -h"
```
**解决方案**
```bash
# 调整内存限制(如果当前限制过低)
# 注意:懒猫算力仓已设置为 30GB一般不需要调整
# 如确需调整,使用以下命令
ssh lazycat "lzc-docker update 5f3bf33e090b --memory=30g --memory-swap=32g"
# 重启容器使配置生效
ssh lazycat "lzc-docker restart 5f3bf33e090b"
```
### 自动重启失败
**现象**
- systemd timer 未触发
- 重启脚本执行失败
- 日志显示 `lzc-docker: command not found`
**诊断**
```bash
# 检查 timer 状态
ssh lazycat "systemctl status openclaw-restart.timer"
# 检查 service 状态
ssh lazycat "systemctl status openclaw-restart.service"
# 查看 service 日志
ssh lazycat "journalctl -u openclaw-restart.service -n 50"
# 查看脚本日志
ssh lazycat "tail -50 /var/log/openclaw-restart.log"
# 手动测试脚本
ssh lazycat "bash -x /root/restart-openclaw.sh"
```
**解决方案**
问题通常是脚本中 `lzc-docker` 命令找不到PATH 问题)。
```bash
# 确认 lzc-docker 路径
ssh lazycat "which lzc-docker"
# 输出: /lzcsys/bin/lzc-docker
# 确保脚本使用完整路径
ssh lazycat "grep 'lzc-docker' /root/restart-openclaw.sh"
# 应该看到: /lzcsys/bin/lzc-docker
# 如果使用的是相对路径,需要修改
ssh lazycat "sed -i 's|lzc-docker|/lzcsys/bin/lzc-docker|g' /root/restart-openclaw.sh"
ssh lazycat "sed -i 's|lzc-docker|/lzcsys/bin/lzc-docker|g' /root/monitor-openclaw-zombies.sh"
# 重新加载 systemd 配置
ssh lazycat "systemctl daemon-reload"
# 测试执行
ssh lazycat "/root/restart-openclaw.sh"
```
---
## 最佳实践
### 1. 定期健康检查
建议每天执行一次全面健康检查:
```bash
#!/bin/bash
# OpenClaw 健康检查脚本
echo "🔍 OpenClaw 健康检查 - $(date)"
echo "================================"
# 容器状态
echo -e "\n📦 容器状态:"
ssh lazycat "lzc-docker ps --filter id=5f3bf33e090b --format 'Status: {{.Status}}'"
# PID 1 进程
echo -e "\n🏗 PID 1 进程:"
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
# 僵尸进程数
echo -e "\n👻 僵尸进程:"
ZOMBIE_COUNT=$(ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'")
echo "僵尸进程数: $ZOMBIE_COUNT"
if [ $ZOMBIE_COUNT -gt 10 ]; then
echo "⚠️ 警告:僵尸进程较多,建议重启容器"
fi
# 资源使用
echo -e "\n💾 资源使用:"
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
# Gateway 状态
echo -e "\n🔌 Gateway 状态:"
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
# 系统负载
echo -e "\n📊 系统负载:"
ssh lazycat "uptime"
echo -e "\n================================"
echo "✅ 健康检查完成"
```
### 2. 日志管理
```bash
# 查看最近的错误日志
ssh lazycat "lzc-docker logs 5f3bf33e090b --since 1h 2>&1 | grep -i error"
# 查看 Tower 崩溃日志
ssh lazycat "lzc-docker logs 5f3bf33e090b 2>&1 | grep -i 'crashed\|failed'"
# 查看 OpenClaw 应用日志
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -100 /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log"
# 清理旧日志保留最近7天
ssh lazycat "lzc-docker exec 5f3bf33e090b find /tmp/openclaw -name '*.log' -mtime +7 -delete"
```
### 3. 备份与恢复
```bash
# 备份 OpenClaw 配置
ssh lazycat "lzc-docker exec 5f3bf33e090b tar czf /tmp/openclaw-config-backup-$(date +%Y%m%d).tar.gz -C /home/node/.openclaw ."
# 下载备份到本地
scp lazycat:/tmp/openclaw-config-backup-*.tar.gz ~/backups/
# 恢复配置
scp ~/backups/openclaw-config-backup-*.tar.gz lazycat:/tmp/
ssh lazycat "lzc-docker exec 5f3bf33e090b tar xzf /tmp/openclaw-config-backup-*.tar.gz -C /home/node/.openclaw"
ssh lazycat "lzc-docker restart 5f3bf33e090b"
```
### 4. 监控告警
建议设置以下监控指标:
- **僵尸进程数** > 50触发告警自动重启已实现
- **内存使用率** > 90%:触发告警
- **Gateway 离线时间** > 5分钟触发告警
- **容器重启次数** > 3次/天:触发告警
### 5. 容器重建后的恢复清单
如果容器被重新创建(从镜像),需要重新应用以下修复:
```bash
# 1. 安装 tini
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'apt-get update -qq && apt-get install -y tini'"
# 2. 修改 entrypoint
ssh lazycat "lzc-docker exec 5f3bf33e090b sed -i 's|exec /usr/local/bin/tower|exec /usr/bin/tini -- /usr/local/bin/tower|g' /usr/local/bin/clawdbot-entrypoint.sh"
# 3. 重启容器
ssh lazycat "lzc-docker restart 5f3bf33e090b"
# 4. 验证
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o cmd | grep tini"
```
---
## 附录
### 相关文档
- OpenClaw 官方文档https://docs.openclaw.ai/
- 故障排查指南https://docs.openclaw.ai/troubleshooting
- Tini 项目https://github.com/krallin/tini
### 联系信息
- 懒猫云支持support@lazycat.cloud
- OpenClaw 社区https://community.openclaw.ai/
### 版本历史
- 2026-02-16
- 创建文档,记录 Tower 崩溃修复经验(使用 tini
- 添加多 TUI 实例问题和 openclaw-clean 解决方案
- 2026-02-15实施僵尸进程监控和自动重启
- 2026-02-14调整容器资源限制为接近系统上限
---
## 快速参考
### 常用命令速查
```bash
# 连接 OpenClaw TUI
openclaw-tui
# 查看容器状态
ssh lazycat "lzc-docker ps | grep openclaw"
# 重启容器
ssh lazycat "lzc-docker restart 5f3bf33e090b"
# 查看僵尸进程数
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
# 检查 Gateway 状态
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
# 查看资源使用
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
# 查看定时任务
ssh lazycat "systemctl list-timers | grep openclaw"
# 清理多余的 OpenClaw TUI 进程
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-tui'"
# 启动 OpenClaw自动清理旧进程
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw-clean"
# 全面健康检查
ssh lazycat "echo '=== 容器 ===' && lzc-docker ps | grep openclaw && echo '' && echo '=== 僵尸进程 ===' && lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z' && echo '' && echo '=== Gateway ===' && lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
```
### 故障处理速查
| 问题 | 快速解决 |
|------|----------|
| Tower 反复崩溃 | 参考"Tower 反复崩溃"章节,安装 tini |
| 多个 TUI 实例 | 使用 `openclaw-tui`(自动清理)或手动 `pkill -9 -f openclaw-tui` |
| Gateway 无响应 | `ssh lazycat "lzc-docker restart 5f3bf33e090b"` |
| 僵尸进程过多 | `ssh lazycat "lzc-docker restart 5f3bf33e090b"` |
| 内存不足 | 检查资源限制,重启容器 |
| 自动重启失败 | 检查脚本是否使用完整路径 `/lzcsys/bin/lzc-docker` |

View File

@@ -1,8 +0,0 @@
{
"name": "openclaw-plugin",
"description": "OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,342 +0,0 @@
---
name: openclaw
description: OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.
---
# OpenClaw - Remote AI Compute Orchestration
OpenClaw (龙虾) 是一个分布式 AI 算力调度系统,用于将需求/任务分发到不同机器上的 Claude Code 实例执行。
## 核心概念
### 1. Ticket (工单)
每个需求 (Requirement) 或任务 (Task) 都是一个 Ticket包含:
- **ID**: REQ-YYYYMMDD-XXXX 或 Task ID
- **Description**: 任务描述
- **Context**: 项目路径、技术栈、依赖
- **Priority**: 优先级 (high/medium/low)
- **Target**: 目标计算节点
### 2. Compute Node (算力节点)
运行 Claude Code 的开发机器:
- **Melbourne** (coolbuy-dev): 主开发机,全栈开发
- **Shanghai** (dev-box): 测试环境
- **Beijing** (lazycat): OpenClaw 本身所在的容器
### 3. Dispatcher (调度器)
OpenClaw 核心组件,负责:
- 接收 Ticket
- 选择合适的 Compute Node
- 生成 Claude Code 命令
- 通过 SSH 执行
- 监控进度
- 汇总结果
## 使用方法
### 基本调用
```bash
# 方式 1: 通过需求 ID
/openclaw dispatch REQ-20260216-0001
# 方式 2: 直接指定任务
/openclaw run "实现用户批量导入功能" --node melbourne --project new-ai-proj
# 方式 3: 使用 Swarm 模式
/openclaw swarm REQ-20260216-0001 --node melbourne
```
### 指定计算节点
```bash
# 自动选择 (根据负载和项目位置)
/openclaw dispatch REQ-20260216-0001 --auto
# 指定节点
/openclaw dispatch REQ-20260216-0001 --node melbourne
# 并行执行 (多个节点)
/openclaw dispatch REQ-20260216-0001 --nodes melbourne,shanghai --parallel
```
### 监控执行状态
```bash
# 查看所有运行中的任务
/openclaw status
# 查看特定任务的日志
/openclaw logs REQ-20260216-0001
# 实时追踪任务进度
/openclaw tail REQ-20260216-0001
```
## 工作流程
### 完整示例: 从 Feishu 到执行
**步骤 1: 用户在飞书发起请求**
```
@龙虾 执行 REQ-20260216-0001
```
**步骤 2: Feishu Bot 解析命令**
- 提取需求 ID: REQ-20260216-0001
- 调用 OpenClaw skill
**步骤 3: OpenClaw 查询需求详情**
```bash
# 使用 ai-proj-prod MCP 获取需求信息
mcp__ai-proj-prod__find_requirement(displayId="REQ-20260216-0001")
```
**步骤 4: OpenClaw 生成执行计划**
```json
{
"ticket_id": "REQ-20260216-0001",
"title": "AI Ticket 演示: 验证算力调度系统",
"type": "swarm",
"target_node": "melbourne",
"command": "/swarm start '实现 AI Ticket 从创建到算力调度的完整流程'",
"context": {
"project": "/Users/coolbuy-dev/coding/new-ai-proj",
"requirement_id": "REQ-20260216-0001",
"priority": "high"
}
}
```
**步骤 5: SSH 执行命令**
```bash
ssh coolbuy-dev@melbourne \
"cd /Users/coolbuy-dev/coding/new-ai-proj && \
/opt/homebrew/bin/claude --dangerously-skip-permissions \
-p '/swarm start 实现 AI Ticket 从创建到算力调度的完整流程 \
--context requirement_id=REQ-20260216-0001'"
```
**步骤 6: Claude Code 执行 Swarm 工作流**
- Architect Agent: 分析需求,设计方案
- Coder Agent: 实现代码
- Tester Agent: 编写和运行测试
- Reviewer Agent: 代码审查
- Deployer Agent: 部署到环境
**步骤 7: OpenClaw 监控和汇总**
- 实时获取执行日志
- 解析 Agent 切换和进度
- 检测完成或失败
**步骤 8: 报告结果**
```
【执行完成】REQ-20260216-0001
✅ 状态: 成功
⏱️ 耗时: 25 分钟
📝 修改: 12 个文件
✅ 测试: 32 个用例全部通过
🚀 部署: staging 环境已更新
详情: https://ai-proj.pipexerp.com/requirements/REQ-20260216-0001
```
## 配置文件
### openclaw.yaml
`~/.claude/openclaw/config.yaml` 配置节点信息:
```yaml
nodes:
melbourne:
host: coolbuy-dev-macbook.local
user: coolbuy-dev
ssh_key: ~/.ssh/id_rsa
claude_path: /opt/homebrew/bin/claude
working_dirs:
- /Users/coolbuy-dev/coding/new-ai-proj
- /Users/coolbuy-dev/coding/coolbuy-paas
capabilities:
- go
- vue
- react
- ios
- android
max_concurrent: 3
shanghai:
host: dev-box.pipexerp.com
user: devops
ssh_key: ~/.ssh/id_rsa_ops
claude_path: /usr/local/bin/claude
working_dirs:
- /home/devops/projects
capabilities:
- testing
- deployment
max_concurrent: 2
routing_rules:
# 根据项目路径自动选择节点
- pattern: "*/new-ai-proj/*"
node: melbourne
- pattern: "*/coolbuy-*/*"
node: melbourne
# 根据需求类别路由
- category: testing
node: shanghai
- category: feature
node: melbourne
priority: prefer # 非强制
# 默认节点
default: melbourne
monitoring:
progress_interval: 30s # 每 30 秒检查一次进度
timeout: 2h # 2 小时超时
feishu_notifications: true
feishu_webhook: ${FEISHU_OPENCLAW_WEBHOOK}
```
## 高级功能
### 1. 负载均衡
OpenClaw 自动根据节点负载分配任务:
```bash
# 自动选择最空闲的节点
/openclaw dispatch REQ-20260216-0001 --load-balance
```
### 2. 任务队列
当节点繁忙时,任务进入队列:
```bash
# 查看队列
/openclaw queue
# 输出:
# 队列中的任务:
# 1. [melbourne] REQ-20260216-0002 - 等待中 (前面 1 个任务)
# 2. [shanghai] Task-1234 - 等待中 (前面 0 个任务)
```
### 3. 结果缓存
已执行过的相同任务可以复用结果:
```bash
/openclaw dispatch REQ-20260216-0001 --use-cache
```
### 4. 故障恢复
任务失败时自动重试或切换节点:
```yaml
retry_policy:
max_attempts: 3
backoff: exponential # 1min, 2min, 4min
fallback_node: shanghai # 失败后切换到备用节点
```
## 与其他 Skills 集成
### 与 agent-swarm 集成
```bash
# OpenClaw 调度 Swarm 工作流
/openclaw swarm REQ-20260216-0001 --node melbourne
```
### 与 ai-proj 集成
```bash
# 自动更新需求状态
# pending → in_progress → testing → completed
/openclaw dispatch REQ-20260216-0001 --sync-status
```
### 与 feishu 集成
```bash
# 飞书群接收进度通知
# "【进行中】REQ-20260216-0001 - Coder Agent 正在实现后端 API (35%)"
```
### 与 ops-tools 集成
```bash
# 部署到服务器
/openclaw dispatch REQ-20260216-0001 --deploy staging
```
## 命令速查
| 命令 | 功能 |
|------|------|
| `/openclaw dispatch <req-id>` | 调度需求到节点执行 |
| `/openclaw run "<task>"` | 直接执行任务 |
| `/openclaw swarm <req-id>` | 使用 Swarm 模式执行 |
| `/openclaw status` | 查看所有任务状态 |
| `/openclaw logs <req-id>` | 查看任务日志 |
| `/openclaw tail <req-id>` | 实时追踪任务 |
| `/openclaw queue` | 查看任务队列 |
| `/openclaw nodes` | 列出所有计算节点 |
| `/openclaw cancel <req-id>` | 取消任务 |
## 故障排查
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| SSH 连接失败 | 网络或认证问题 | 检查 `~/.ssh/config` 和密钥权限 |
| Claude 命令未找到 | Claude 未安装或路径错误 | 更新 `openclaw.yaml` 中的 `claude_path` |
| 任务卡住不动 | 超时或节点挂起 | 使用 `/openclaw cancel` 取消并重试 |
| Feishu 通知失败 | Webhook 配置错误 | 检查 `FEISHU_OPENCLAW_WEBHOOK` 环境变量 |
## 安全考虑
1. **SSH 密钥管理**: 使用专用密钥,定期轮换
2. **命令注入防护**: 所有参数都经过严格转义
3. **权限控制**: 限制 Claude Code 的 `--dangerously-skip-permissions` 使用
4. **日志审计**: 所有命令执行都记录在 `~/.claude/openclaw/audit.log`
## 实际应用场景
### 场景 1: 多项目并行开发
```bash
# 同时在不同机器上开发不同项目
/openclaw dispatch REQ-001 --node melbourne --project new-ai-proj &
/openclaw dispatch REQ-002 --node shanghai --project coolbuy-paas &
```
### 场景 2: 测试环境验证
```bash
# 开发在 Melbourne测试在 Shanghai
/openclaw dispatch REQ-003 --node melbourne # 开发
sleep 1h # 等待开发完成
/openclaw dispatch REQ-003 --node shanghai --verify # 测试验证
```
### 场景 3: 紧急 Bug 修复
```bash
# 高优先级任务插队执行
/openclaw dispatch BUG-001 --priority urgent --node melbourne
```
## 未来扩展
- [ ] Web 控制面板: 可视化任务状态和节点负载
- [ ] 分布式追踪: Jaeger/OpenTelemetry 集成
- [ ] 成本统计: 记录每个任务的 token 使用量和费用
- [ ] 智能调度: 基于历史数据预测任务执行时间
- [ ] 多云支持: 支持 AWS/Azure/GCP 上的计算节点
---
**开发者**: AI 项目管理助手
**版本**: 1.0.0
**最后更新**: 2026-02-16

View File

@@ -1,8 +0,0 @@
{
"name": "ops-servers-plugin",
"description": "Plugin for ops-servers",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,262 +0,0 @@
---
name: ops-servers
description: 企业服务器管理。用于云服务器分组管理、系统监控、备份管理、故障排查。当用户提到云服务器、生产环境、腾讯云、阿里云相关任务时自动激活。
---
# 企业服务器管理 Skill
> 家庭网络设备请使用 `ops-home` Skill
---
## 服务器清单
| 别名 | IP | 用户 | SSH 密钥 | 用途 | 配置 | ISP | 账号 |
|------|-----|------|----------|------|------|-----|------|
| prod-pipexerp | 192.144.137.14 | ubuntu | ~/.ssh/officialWebsite.pem | pipexerp 官网 | 2核2G 40G SSD | 腾讯云 | 北京对丝 |
| prod-metaBI | 192.144.174.87 | ubuntu | ~/.ssh/prod_meta.pem | Metabase BI 分析 | - | 腾讯云 | 北京欢乐宿 |
| moltbot | 124.223.196.74 | root | ~/.ssh/moltbot | Moltbot 服务 | - | 腾讯云 | - |
| lazycat | 100.115.52.119 (haiqing.heiyu.space) | root | 密码认证 (zhiyun2026) | AI/计算节点 | - | - | - |
### SSH 快捷连接
```bash
# pipexerp 官网服务器
ssh prod-pipexerp
# Metabase BI 分析服务器
ssh prod-metaBI
# Moltbot 服务器
ssh moltbot
# Lazycat AI 计算节点密码zhiyun2026
ssh root@haiqing.heiyu.space
# 或使用 IP
ssh root@100.115.52.119
```
---
## 服务器分组架构
采用 **环境 + 服务** 混合分组模式:
### 按环境分组
| 环境 | 前缀 | 用途 |
|------|------|------|
| prod | prod- | 生产环境 |
| staging | stg- | 预发布环境 |
| test | test- | 测试环境 |
| dev | dev- | 开发环境 |
### 按服务分组
| 服务组 | 包含服务 | 说明 |
|--------|----------|------|
| web | Nginx, 前端静态资源 | 负载均衡、静态资源 |
| api | Go/Node 后端服务 | 业务 API |
| db | MySQL, PostgreSQL | 数据库 |
| cache | Redis | 缓存服务 |
---
## 常用运维命令
### 系统状态检查
```bash
# 一键查看系统概况
ssh prod-pipexerp "echo '=== 负载 ===' && uptime && echo && echo '=== 内存 ===' && free -h && echo && echo '=== 磁盘 ===' && df -h"
# 查看 CPU 使用最高的进程
ssh prod-pipexerp "ps aux --sort=-%cpu | head -10"
# 查看内存使用最高的进程
ssh prod-pipexerp "ps aux --sort=-%mem | head -10"
```
### Docker 管理
```bash
# 查看运行中的容器
ssh prod-pipexerp "docker ps"
# 查看所有容器
ssh prod-pipexerp "docker ps -a"
# 查看容器日志
ssh prod-pipexerp "docker logs -f <container_name> --tail 100"
# 重启容器
ssh prod-pipexerp "docker restart <container_name>"
# 清理未使用的资源
ssh prod-pipexerp "docker system prune -af"
```
### 网络检查
```bash
# 查看端口监听
ssh prod-pipexerp "sudo netstat -tlnp"
# 检查防火墙状态
ssh prod-pipexerp "sudo ufw status"
# 测试端口连通性
nc -zv 192.144.137.14 80
nc -zv 192.144.137.14 443
```
### 日志查看
```bash
# Nginx 错误日志
ssh prod-pipexerp "sudo tail -f /var/log/nginx/error.log"
# Nginx 访问日志
ssh prod-pipexerp "sudo tail -f /var/log/nginx/access.log"
# 系统日志
ssh prod-pipexerp "sudo tail -f /var/log/syslog"
```
---
## 批量操作
### 对多台服务器执行命令
```bash
# 定义服务器列表
SERVERS="prod-pipexerp"
# 批量检查状态
for host in $SERVERS; do
echo "=== $host ==="
ssh $host "uptime && free -h | head -2 && df -h / | tail -1"
done
```
### 健康检查脚本
```bash
# 检查所有服务器
for host in prod-pipexerp; do
echo "=== $host ==="
ssh $host "
echo '--- 负载 ---' && uptime
echo '--- 内存 ---' && free -h | head -2
echo '--- 磁盘 ---' && df -h / | tail -1
echo '--- Docker ---' && docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null || echo 'N/A'
"
done
```
---
## 备份管理
### 备份策略
| 备份类型 | 频率 | 保留时间 | 存储位置 |
|----------|------|----------|----------|
| 数据库全量 | 每日 02:00 | 7 天 | /backup/mysql/ |
| 配置文件 | 每日 03:00 | 30 天 | /backup/configs/ |
| 上传文件 | 每日 04:00 | 30 天 | /backup/uploads/ |
### 手动备份
```bash
# 备份 Nginx 配置
ssh prod-pipexerp "sudo tar -czf /tmp/nginx-\$(date +%Y%m%d).tar.gz /etc/nginx/"
# 下载备份到本地
scp prod-pipexerp:/tmp/nginx-*.tar.gz ./backups/
```
### 备份清理
```bash
# 清理 7 天前的备份
ssh prod-pipexerp "sudo find /backup/ -name '*.tar.gz' -mtime +7 -delete"
```
---
## 故障排查
### 常见问题
1. **服务无响应**
```bash
ssh prod-pipexerp "sudo systemctl status nginx"
ssh prod-pipexerp "sudo journalctl -u nginx --since '10 minutes ago'"
```
2. **磁盘空间不足**
```bash
ssh prod-pipexerp "df -h && sudo du -sh /* 2>/dev/null | sort -h | tail -10"
# 清理 Docker
ssh prod-pipexerp "docker system prune -af"
# 清理日志
ssh prod-pipexerp "sudo journalctl --vacuum-size=500M"
```
3. **内存不足**
```bash
ssh prod-pipexerp "free -h && ps aux --sort=-%mem | head -10"
```
4. **网站无法访问**
```bash
# 检查 Nginx
ssh prod-pipexerp "sudo systemctl status nginx"
# 检查端口
ssh prod-pipexerp "sudo netstat -tlnp | grep ':80\|:443'"
# 测试本地访问
ssh prod-pipexerp "curl -I http://localhost"
```
5. **SSL 证书问题**
```bash
# 检查证书到期时间
ssh prod-pipexerp "sudo openssl x509 -in /etc/nginx/ssl/cert.pem -noout -dates"
```
---
## 账号管理
### 系统用户
| 用户名 | 用途 | 权限 |
|--------|------|------|
| ubuntu | 默认管理用户 | sudo |
| deploy | 部署用户 | 部署相关 |
### 创建部署用户
```bash
# 创建用户
ssh prod-pipexerp "sudo useradd -m -s /bin/bash deploy"
# 配置 SSH 密钥
ssh prod-pipexerp "sudo mkdir -p /home/deploy/.ssh && sudo chmod 700 /home/deploy/.ssh"
ssh prod-pipexerp "sudo cp ~/.ssh/authorized_keys /home/deploy/.ssh/ && sudo chown -R deploy:deploy /home/deploy/.ssh"
# 配置 sudo 权限(无密码 docker 和 systemctl
ssh prod-pipexerp "echo 'deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/docker *' | sudo tee /etc/sudoers.d/deploy"
```
---
## 安全注意事项
- SSH 密钥文件权限必须是 600: `chmod 600 ~/.ssh/*.pem`
- 使用 `sudo` 执行需要 root 权限的命令
- 敏感操作前先确认服务器和目标
- 生产环境操作需要二次确认
- 定期更新系统和软件包

View File

@@ -1,8 +0,0 @@
{
"name": "ops-tools-plugin",
"description": "Plugin for ops-tools",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,246 +0,0 @@
# AI-Proj 部署指南
**创建时间**: 2026-01-29 11:50:00 CST
**父技能**: ops-tools
## 环境概览
| 环境 | 服务器 | 域名 | 镜像标签 |
|------|--------|------|----------|
| 生产 | tools_ai_proj (152.136.104.251) | https://ai.pipexerp.com | `latest` |
| 测试 | singapore (43.134.28.147) | http://staging.ai.pipexerp.com | `test` |
## 镜像信息
| 服务 | 镜像 |
|------|------|
| 后端 | `saltthing123/ai-proj-backend` |
| 前端 | `saltthing123/ai-proj-frontend` |
## 标准部署流程
### 部署到测试环境
```bash
cd /path/to/new-ai-proj
# 构建后端 test 镜像
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
-t saltthing123/ai-proj-backend:test --push backend/
# 构建前端 test 镜像
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
--build-arg REACT_APP_API_URL=https://staging.ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_API_BASE_URL=https://staging.ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_ENV=staging \
-t saltthing123/ai-proj-frontend:test --push frontend/
# 部署到测试服务器
ssh singapore "cd /opt/ai-project-staging && sudo docker-compose pull && sudo docker-compose up -d"
```
### 部署到生产环境
```bash
cd /path/to/new-ai-proj
# 构建后端 latest 镜像
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
-t saltthing123/ai-proj-backend:latest --push backend/
# 构建前端 latest 镜像
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_ENV=production \
-t saltthing123/ai-proj-frontend:latest --push frontend/
# 部署到生产服务器
ssh tools_ai_proj "cd /opt/ai-project && \
docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml pull && \
docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml up -d"
```
## 新加坡服务器 Build备选方案
本地网络慢时,在新加坡服务器构建:
```bash
# 后端
ssh singapore "cd ~/projects/new-ai-proj && git pull && \
docker build --platform linux/amd64 -f backend/Dockerfile --target production \
-t saltthing123/ai-proj-backend:latest ./backend && \
docker push saltthing123/ai-proj-backend:latest"
# 前端(生产)
ssh singapore "cd ~/projects/new-ai-proj && \
docker build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_ENV=production \
-t saltthing123/ai-proj-frontend:latest ./frontend && \
docker push saltthing123/ai-proj-frontend:latest"
```
## 自动部署Webhook
**状态**: 已启用 (2026-01-16)
```
git push main → Gitea webhook → Jenkins ai-proj → 生产自动部署
```
## 服务管理
```bash
# 查看容器状态
ssh tools_ai_proj "docker ps --format 'table {{.Names}}\t{{.Status}}'"
# 查看日志
ssh tools_ai_proj "docker logs -f ai_backend_prod --tail 100"
# 重启服务
ssh tools_ai_proj "docker restart ai_backend_prod"
# 健康检查
curl -s https://ai.pipexerp.com/api/v1/health | jq .
```
## 测试环境管理
```bash
# 查看状态
ssh singapore "sudo docker-compose -f /opt/ai-project-staging/docker-compose.yml ps"
# 查看日志
ssh singapore "sudo docker logs -f ai_backend_staging --tail 100"
# 健康检查
ssh singapore "curl -s -H 'Host: staging.ai.pipexerp.com' http://127.0.0.1/api/v1/health"
```
## Docker Volumes 配置
**重要**: 数据卷必须标记为 `external: true`
```yaml
volumes:
postgres_prod_data:
external: true
name: ai-project_postgres_prod_data
redis_prod_data:
external: true
name: ai-project_redis_prod_data
```
## 数据库操作
```bash
# 运行迁移
ssh tools_ai_proj "cd /opt/ai-project/backend/migrations && \
for file in \$(ls *.sql | grep -v _down.sql | sort); do \
docker exec -i ai_postgres_prod psql -U ai_prod_user -d ai_project_prod < \"\$file\"; \
done"
# 备份
ssh tools_ai_proj "docker exec ai_postgres_prod pg_dump -U ai_prod_user ai_project_prod > /tmp/backup.sql"
```
## 用户管理
> **重要**: 密码哈希必须使用 bcrypt **cost 12**,这是后端 `utils/password.go` 中的 `DefaultCost` 值。
### 创建用户完整流程
由于 bcrypt 哈希包含 `$` 字符会被 shell 解释,必须使用文件传输方式:
```bash
# 1. 生成密码哈希(在有 Go 环境的机器上执行)
cd /path/to/new-ai-proj/backend
cat > /tmp/genhash.go << 'EOF'
package main
import ("fmt"; "golang.org/x/crypto/bcrypt")
func main() {
hash, _ := bcrypt.GenerateFromPassword([]byte("用户密码"), 12)
fmt.Println(string(hash))
}
EOF
HASH=$(go run /tmp/genhash.go)
echo "Generated hash: $HASH"
# 2. 创建 SQL 文件
cat > /tmp/create_user.sql << EOF
INSERT INTO users (username, email, password_hash, user_type, role, status, created_at, updated_at)
VALUES ('newuser', 'newuser@example.com', '$HASH', 'system', 'admin', 'active', NOW(), NOW());
EOF
# 3. 传输并执行
scp /tmp/create_user.sql tools_ai_proj:/tmp/
ssh tools_ai_proj "docker cp /tmp/create_user.sql ai_postgres_prod:/tmp/ && \
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/create_user.sql"
# 4. 验证
curl -s -X POST "https://ai.pipexerp.com/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"newuser","password":"用户密码"}' | jq '.success'
```
### 用户角色
| user_type | role | 权限 |
|-----------|------|------|
| system | admin | 系统管理员 |
| system | user | 系统用户 |
| tenant | admin | 租户管理员 |
| tenant | user | 租户用户 |
### 重置密码
```bash
# 生成新哈希并更新
cd /path/to/new-ai-proj/backend
HASH=$(go run -e 'package main; import ("fmt";"golang.org/x/crypto/bcrypt"); func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }' 2>/dev/null || cat > /tmp/h.go << 'E'
package main
import ("fmt";"golang.org/x/crypto/bcrypt")
func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }
E
go run /tmp/h.go)
cat > /tmp/reset.sql << EOF
UPDATE users SET password_hash = '$HASH' WHERE username = 'targetuser';
EOF
scp /tmp/reset.sql tools_ai_proj:/tmp/
ssh tools_ai_proj "docker cp /tmp/reset.sql ai_postgres_prod:/tmp/ && \
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/reset.sql"
```
### 常见错误
| 问题 | 原因 | 解决 |
|------|------|------|
| 登录失败 | bcrypt cost 不是 12 | 用 Go 重新生成 cost 12 的哈希 |
| 哈希被截断 | shell 解释了 $ 符号 | 使用文件传输方式 |
### 已创建的系统用户
| 用户名 | 邮箱 | user_type | role | 创建时间 |
|--------|------|-----------|------|----------|
| qiudl | qiudl@zhiyuncai.com | system | admin | - |
| jiaxiang | jiaxiang@joylodging.com | system | admin | 2026-01 |
| haiqing | haiqing@joylodging.com | system | admin | 2026-02 |
> 注意:密码信息不在文档中记录,如需重置请使用上述重置密码流程
## 前端构建注意事项
必须同时设置两个 URL 变量:
- `REACT_APP_API_URL`
- `REACT_APP_API_BASE_URL`
否则会使用 `.env.production` 中的生产 URL。
验证镜像中的 URL
```bash
docker exec <container> sh -c 'grep -oE "https://[a-zA-Z0-9.-]*pipexerp[a-zA-Z0-9./-]*" /usr/share/nginx/html/static/js/main*.js | sort | uniq -c'
```

View File

@@ -1,100 +0,0 @@
# Coolbuy-PaaS 部署指南
**创建时间**: 2026-01-29 11:50:00 CST
**父技能**: ops-tools
## 仓库信息
| 仓库 | 地址 | 说明 |
|------|------|------|
| coolbuy-paas | git@gitea.pipexerp.com:pipexerp/coolbuy-paas.git | 租户业务系统 |
| coolbuy-platform | git@gitea.pipexerp.com:pipexerp/coolbuy-platform.git | 平台管理端 |
| coolbuy-legacy | git@gitea.pipexerp.com:pipexerp/coolbuy-legacy.git | 遗留项目 |
## 镜像信息
| 服务 | 镜像 | Dockerfile |
|------|------|------------|
| Auth | saltthing123/coolbuy-paas-auth | auth-service/Dockerfile |
| Foundation | saltthing123/coolbuy-paas-foundation | foundation-service/Dockerfile |
| ERP | saltthing123/coolbuy-paas-erp | erp-service/Dockerfile |
| Web | saltthing123/coolbuy-paas-web | web/Dockerfile |
## 生产环境
| 项目 | 值 |
|------|-----|
| 服务器 IP | 39.106.88.83 |
| 架构 | AMD64 |
| 部署目录 | /opt/coolbuy-paas |
| Web 端口 | 8888 |
## 部署流程(本地构建 + Jenkins 部署)
### 步骤 1: 本地构建并推送
```bash
cd /path/to/coolbuy-paas
# 构建单个服务AMD64 架构)
docker buildx build --platform linux/amd64 -t saltthing123/coolbuy-paas-web:latest ./web --push
# 构建所有服务
./scripts/build-and-push.sh --push --platform linux/amd64
```
### 步骤 2: 触发 Jenkins 部署
```bash
source ~/.config/devops/credentials.env
# 部署到生产
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "ACTION=deploy-prod&IMAGE_TAG=latest"
# 部署到测试
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "ACTION=deploy-test&IMAGE_TAG=latest"
```
### 一键部署命令
```bash
cd /path/to/coolbuy-paas && \
docker buildx build --platform linux/amd64 -t saltthing123/coolbuy-paas-web:latest ./web --push && \
source ~/.config/devops/credentials.env && \
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "ACTION=deploy-prod&IMAGE_TAG=latest"
```
## 查看构建状态
```bash
source ~/.config/devops/credentials.env
# 构建状态
curl -s "$JENKINS_URL/job/coolbuy-paas/lastBuild/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN" | jq '.result, .building'
# 构建日志
curl -s "$JENKINS_URL/job/coolbuy-paas/lastBuild/consoleText" \
-u "$JENKINS_USER:$JENKINS_TOKEN" | tail -50
```
## 检查镜像架构
```bash
# 本地镜像
docker inspect saltthing123/coolbuy-paas-web:latest | grep Architecture
# DockerHub 镜像
docker manifest inspect saltthing123/coolbuy-paas-web:latest | grep architecture
```
## 重要提醒
- 生产服务器为 AMD64 架构,必须使用 `--platform linux/amd64`
- 禁止在 Jenkins 服务器构建镜像,所有镜像本地构建后推送到 DockerHub

View File

@@ -1,837 +0,0 @@
# 数据库备份与恢复 Skill
**父技能**: ops-tools
**适用范围**: 全局(所有项目数据库)
**创建时间**: 2026-01-15 07:30:00 ACDT
**最后更新**: 2026-02-02
---
## 技能概述
全局数据库备份技能,适用于所有项目的 PostgreSQL 数据库。涵盖迁移前备份、自动备份、数据恢复和灾难恢复策略。
**核心原则**
- ⚠️ **任何数据库迁移操作前必须先备份**
- 保留策略:最近 7 天 + 每月 1 个永久备份
- 存储位置:服务器本地 `/backup/` 目录
---
## 数据库清单
| 数据库 | 服务器 | 容器 | 用途 | 备份路径 |
|--------|--------|------|------|----------|
| ai_project_prod | tools_ai_proj | ai_postgres_prod | AI-Proj 生产 | /backup/ai-project/database/ |
| ai_project_staging | singapore | ai_postgres_staging | AI-Proj 测试 | /backup/ai-project-staging/ |
| coolbuy_prod | coolbuy-dev | postgres | Coolbuy 3.0 | /backup/coolbuy/ |
---
## ⚡ 迁移前快速备份(必读)
> **重要**:执行任何 `UPDATE`、`DELETE`、`ALTER`、数据迁移等操作前,**必须先执行备份**。
### 一键备份命令
```bash
# AI-Proj 生产数据库 - 迁移前备份
ssh tools_ai_proj 'REASON="pre_migration_$(date +%Y%m%d_%H%M%S)" && \
docker exec ai_postgres_prod pg_dump -U ai_prod_user -Fc ai_project_prod \
> /backup/ai-project/database/ai_project_${REASON}.dump && \
echo "✓ 备份完成: /backup/ai-project/database/ai_project_${REASON}.dump"'
# AI-Proj 测试数据库 - 迁移前备份
ssh singapore 'REASON="pre_migration_$(date +%Y%m%d_%H%M%S)" && \
sudo docker exec ai_postgres_staging pg_dump -U ai_staging_user -Fc ai_project_staging \
> /backup/ai-project-staging/ai_project_staging_${REASON}.dump && \
echo "✓ 备份完成"'
```
### 带原因的备份(推荐)
```bash
# 指定备份原因,方便追溯
ssh tools_ai_proj 'REASON="migrate_project_165_to_167" && \
docker exec ai_postgres_prod pg_dump -U ai_prod_user -Fc ai_project_prod \
> /backup/ai-project/database/ai_project_$(date +%Y%m%d_%H%M%S)_${REASON}.dump && \
ls -lh /backup/ai-project/database/ | tail -3'
```
### 备份后验证
```bash
# 验证备份文件
ssh tools_ai_proj 'ls -lh /backup/ai-project/database/ | tail -5'
# 检查备份文件大小(应该 > 10MB
ssh tools_ai_proj 'stat --printf="%s bytes\n" /backup/ai-project/database/ai_project_*.dump | tail -1'
```
---
## 快速恢复命令
### 从最新备份恢复
```bash
# 1. 找到最新备份
ssh tools_ai_proj 'ls -lt /backup/ai-project/database/*.dump | head -3'
# 2. 恢复(使用 pg_restore
ssh tools_ai_proj 'BACKUP_FILE="/backup/ai-project/database/ai_project_XXXXXXXX.dump" && \
docker stop ai_backend_prod && \
docker exec ai_postgres_prod pg_restore -U ai_prod_user -d ai_project_prod --clean --if-exists -Fc "$BACKUP_FILE" && \
docker start ai_backend_prod && \
echo "✓ 恢复完成"'
# 3. 验证
curl -s https://ai.pipexerp.com/api/v1/health | jq .
```
### 恢复到特定时间点
```bash
# 列出所有备份,找到目标时间点
ssh tools_ai_proj 'ls -lht /backup/ai-project/database/*.dump'
# 恢复指定备份
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_restore \
-U ai_prod_user -d ai_project_prod --clean --if-exists -Fc \
/backup/ai-project/database/ai_project_20260202_180000_migrate_project_165_to_167.dump'
```
---
## 保留策略
### 策略说明
| 类型 | 保留时间 | 清理规则 |
|------|----------|----------|
| 每日备份 | 7 天 | 超过 7 天自动删除 |
| 月度备份 | 永久 | 每月 1 号的备份永久保留 |
| 迁移前备份 | 30 天 | 带 `pre_migration` 标记的保留 30 天 |
### 自动清理脚本
```bash
# /opt/scripts/cleanup-backups.sh
#!/bin/bash
BACKUP_DIR="/backup/ai-project/database"
# 删除超过 7 天的每日备份(保留月度备份)
find "$BACKUP_DIR" -name "*.dump" -mtime +7 ! -name "*_01_*" -delete
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 ! -name "*_01_*" -delete
# 删除超过 30 天的迁移前备份
find "$BACKUP_DIR" -name "*pre_migration*" -mtime +30 -delete
echo "$(date): Cleanup completed" >> /var/log/backup-cleanup.log
```
### Cron 配置
```cron
# 每天凌晨 3 点清理旧备份
0 3 * * * /opt/scripts/cleanup-backups.sh
```
---
## 快速参考
| 操作 | 命令 |
|------|------|
| 手动执行备份 | `ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"` |
| 查看本地备份 | `ssh tools_ai_proj "ls -lh /backup/ai-project/database/"` |
| 查看备份日志 | `ssh tools_ai_proj "tail -f /var/log/ai-project-backup.log"` |
| 触发 OSS 同步 | `ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"` |
| 列出 OSS 备份 | `ssh tools_ai_proj "ossutil ls oss://fnos2026/ai-project/backups/ --config-file ~/.ossutilconfig"` |
| 下载最新备份 | `ssh tools_ai_proj "ossutil cp oss://fnos2026/ai-project/backups/latest.sql.gz /tmp/ --config-file ~/.ossutilconfig"` |
| 验证备份完整性 | `ssh tools_ai_proj "gzip -t /backup/ai-project/database/latest.sql.gz"` |
---
## 备份架构
### 双层备份策略
```
┌─────────────────────────────────────────────────────────┐
│ AI-Proj 生产服务器 │
│ (tools_ai_proj: 152.136.104.251) │
├─────────────────────────────────────────────────────────┤
│ │
│ PostgreSQL 数据库 (ai_postgres_prod) │
│ │ │
│ │ 每天 02:00 (Cron) │
│ ▼ │
│ 本地备份 (/backup/ai-project/database/) │
│ │ - gzip 压缩 │
│ │ - 30 天保留 │
│ │ - 完整性验证 │
│ │ - 符号链接 (latest.sql.gz) │
│ │ │
│ │ 每天 02:30 (Cron) │
│ ▼ │
│ OSS 同步 (backup-to-oss.sh) │
│ │ │
└────────────┼─────────────────────────────────────────────┘
│ 互联网 (623 KB/s)
┌─────────────────────────────────────────────────────────┐
│ 阿里云对象存储 (OSS) │
│ 北京区域 │
├─────────────────────────────────────────────────────────┤
│ Bucket: fnos2026 │
│ 路径: /ai-project/backups/ │
│ │
│ ├── YYYYMMDD/ │
│ │ └── ai_project_YYYYMMDD_HHMMSS.sql.gz │
│ └── latest.sql.gz (最新备份) │
│ │
│ ✅ 异地容灾 (99.9% 可用性) │
│ ✅ 30 天自动清理 │
│ ✅ 成本: ~¥0.25/月 │
└─────────────────────────────────────────────────────────┘
```
### 备份时间表
| 时间 | 操作 | 脚本 | 日志文件 |
|------|------|------|----------|
| 02:00 | 本地数据库备份 | `/opt/ai-project/deploy/scripts/backup-database.sh` | `/var/log/ai-project-backup.log` |
| 02:30 | OSS 异地同步 | `/opt/ai-project/deploy/scripts/backup-to-oss.sh` | `/var/log/ai-project-oss-sync.log` |
---
## 自动备份配置
### 本地备份
**脚本位置**: `/opt/ai-project/deploy/scripts/backup-database.sh`
**功能特性**:
- ✅ PostgreSQL pg_dump 完整备份
- ✅ gzip 压缩
- ✅ 按日期目录组织
- ✅ 30 天自动清理
- ✅ 备份完整性验证
- ✅ 符号链接指向最新备份
**Cron 配置**:
```cron
0 2 * * * /opt/ai-project/deploy/scripts/backup-database.sh >> /var/log/ai-project-backup.log 2>&1
```
**手动执行**:
```bash
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"
```
**查看日志**:
```bash
ssh tools_ai_proj "tail -f /var/log/ai-project-backup.log"
```
**备份目录结构**:
```
/backup/ai-project/database/
├── 20260115/
│ ├── ai_project_20260115_020001.sql.gz (13M)
│ └── ai_project_20260115_120000.sql.gz (13M)
├── 20260116/
│ └── ai_project_20260116_020001.sql.gz (13M)
└── latest.sql.gz -> 20260116/ai_project_20260116_020001.sql.gz
```
---
## 阿里云 OSS 异地备份
**配置时间**: 2026-01-15 01:12:00 CST
**首次同步**: 2026-01-15 02:30:01 CST
### OSS 配置信息
| 配置项 | 值 |
|--------|-----|
| Endpoint | oss-cn-beijing.aliyuncs.com |
| Bucket | fnos2026 |
| 存储路径 | oss://fnos2026/ai-project/backups/ |
| 保留策略 | 30 天自动清理 |
| 预计成本 | ~¥0.25/月 |
### 凭据配置
**存储位置**: `~/.config/devops/credentials.env` (权限 600)
```bash
OSS_ENDPOINT="oss-cn-beijing.aliyuncs.com"
OSS_BUCKET="fnos2026"
OSS_ACCESS_KEY_ID="LTAI5tEARCztp3Bj3FUYd9rh"
OSS_ACCESS_KEY_SECRET="RSvwURFo2cgF1krSgeriyrAUIqQyGE"
```
**加载凭据**:
```bash
source ~/.config/devops/credentials.env
```
### ossutil 工具
**版本**: v1.7.15
**安装位置**: `/usr/local/bin/ossutil`
**安装时间**: 2026-01-15 00:45:00 CST
**安装步骤**:
```bash
wget https://gosspublic.alicdn.com/ossutil/1.7.15/ossutil64
sudo mv ossutil64 /usr/local/bin/ossutil
sudo chmod +x /usr/local/bin/ossutil
```
**配置**:
```bash
source ~/.config/devops/credentials.env
ossutil config -e ${OSS_ENDPOINT} \
-i ${OSS_ACCESS_KEY_ID} \
-k ${OSS_ACCESS_KEY_SECRET} \
-L CH \
--config-file ~/.ossutilconfig
```
**测试连接**:
```bash
ossutil ls oss://${OSS_BUCKET}/
```
### 自动同步脚本
**脚本位置**: `/opt/ai-project/deploy/scripts/backup-to-oss.sh`
**功能特性**:
- ✅ 同步当天备份目录到 OSS
- ✅ 上传 latest.sql.gz
- ✅ 自动清理 30 天前的旧备份
- ✅ 备份统计报告
- ✅ 彩色日志输出
**Cron 配置**:
```cron
30 2 * * * /opt/ai-project/deploy/scripts/backup-to-oss.sh >> /var/log/ai-project-oss-sync.log 2>&1
```
**手动执行**:
```bash
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"
```
**查看日志**:
```bash
ssh tools_ai_proj "tail -f /var/log/ai-project-oss-sync.log"
```
### 常用 OSS 操作
```bash
# 加载凭据
source ~/.config/devops/credentials.env
# 列出所有备份文件
ssh tools_ai_proj "ossutil ls oss://${OSS_BUCKET}/ai-project/backups/ -r --config-file ~/.ossutilconfig"
# 查看备份统计
ssh tools_ai_proj "ossutil du oss://${OSS_BUCKET}/ai-project/backups/ --config-file ~/.ossutilconfig"
# 下载特定日期的备份
ssh tools_ai_proj "ossutil cp oss://${OSS_BUCKET}/ai-project/backups/20260115/ai_project_20260115_*.sql.gz /tmp/ --config-file ~/.ossutilconfig"
# 下载最新备份
ssh tools_ai_proj "ossutil cp oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz /tmp/ --config-file ~/.ossutilconfig"
# 查看备份文件详情
ssh tools_ai_proj "ossutil stat oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
# 手动清理特定日期的备份
ssh tools_ai_proj "ossutil rm oss://${OSS_BUCKET}/ai-project/backups/20260101/ -r -f --config-file ~/.ossutilconfig"
```
### 备份验证
```bash
# 验证最新备份是否上传成功
ssh tools_ai_proj "ossutil stat oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
# 下载并测试备份完整性
ssh tools_ai_proj "
ossutil cp oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz /tmp/test_restore.sql.gz --config-file ~/.ossutilconfig
gzip -t /tmp/test_restore.sql.gz && echo '✓ 备份文件完整' || echo '✗ 备份文件损坏'
rm /tmp/test_restore.sql.gz
"
```
---
## 手动备份
### 完整备份
```bash
# 连接到生产服务器
ssh tools_ai_proj
# 导出数据库
docker exec ai_postgres_prod pg_dump -U ai_prod_user ai_project_prod \
--no-owner --no-acl --clean --if-exists \
> /tmp/ai_project_backup_$(date +%Y%m%d_%H%M%S).sql
# 压缩备份
gzip /tmp/ai_project_backup_*.sql
# 验证备份完整性
gzip -t /tmp/ai_project_backup_*.sql.gz
```
### 下载到本地
**直接下载** (如果网络良好):
```bash
scp tools_ai_proj:/tmp/ai_project_backup_*.sql.gz /tmp/
```
**通过跳板机优化传输** (高延迟环境):
```bash
# 使用新加坡跳板机中转(澳洲 → 新加坡 → 腾讯云)
scp tools_ai_proj:/tmp/ai_project_backup_*.sql.gz singapore:/tmp/
scp singapore:/tmp/ai_project_backup_*.sql.gz /tmp/
# 清理跳板机临时文件
ssh singapore "rm /tmp/ai_project_backup_*.sql.gz"
```
---
## 数据库恢复
### 场景 1: 从 OSS 备份恢复(推荐)
```bash
# 1. 从 OSS 下载最新备份
ssh tools_ai_proj "
source ~/.config/devops/credentials.env
ossutil cp oss://fnos2026/ai-project/backups/latest.sql.gz /tmp/restore.sql.gz --config-file ~/.ossutilconfig -f
"
# 2. 验证文件完整性
ssh tools_ai_proj "gzip -t /tmp/restore.sql.gz"
# 3. 停止后端服务
ssh tools_ai_proj "docker stop ai_backend_prod"
# 4. 恢复数据库
ssh tools_ai_proj "
gunzip -c /tmp/restore.sql.gz | \
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
"
# 5. 启动后端服务
ssh tools_ai_proj "docker start ai_backend_prod"
# 6. 验证服务
curl -s https://ai.pipexerp.com/api/v1/health | jq .
# 7. 清理临时文件
ssh tools_ai_proj "rm /tmp/restore.sql.gz"
```
### 场景 2: 从本地备份恢复
```bash
ssh tools_ai_proj
# 停止后端服务
docker stop ai_backend_prod
# 恢复数据库
gunzip -c /backup/ai-project/database/latest.sql.gz | \
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
# 启动后端服务
docker start ai_backend_prod
```
### 场景 3: 从本地开发环境恢复到生产(完整重建)
```bash
# 1. 本地导出
pg_dump -U donglinlai ai_project_local \
--no-owner --no-acl --clean --if-exists \
--exclude-table=audit_logs \
> /tmp/ai_project_clean.sql
# 2. 压缩
gzip /tmp/ai_project_clean.sql
# 3. 通过新加坡跳板机传输(优化高延迟)
scp /tmp/ai_project_clean.sql.gz singapore:/tmp/
ssh singapore "scp /tmp/ai_project_clean.sql.gz tools_ai_proj:/tmp/"
# 4. 生产环境恢复
ssh tools_ai_proj
# 停止后端服务
docker stop ai_backend_prod
# 完全重建数据库(避免依赖冲突)
docker exec ai_postgres_prod psql -U ai_prod_user postgres \
-c 'DROP DATABASE IF EXISTS ai_project_prod;'
docker exec ai_postgres_prod psql -U ai_prod_user postgres \
-c 'CREATE DATABASE ai_project_prod OWNER ai_prod_user;'
# 恢复数据
gunzip -c /tmp/ai_project_clean.sql.gz | \
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
# 创建可能缺失的表
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod << 'EOF'
CREATE TABLE IF NOT EXISTS audit_logs (
id SERIAL PRIMARY KEY,
user_id INTEGER,
action VARCHAR(100),
resource_type VARCHAR(100),
resource_id VARCHAR(100),
details TEXT,
ip_address VARCHAR(50),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
EOF
# 运行数据库迁移(如果有)
cd /opt/ai-project/backend/migrations
for file in $(ls *.sql | grep -v _down.sql | sort); do
echo "Running migration: $file"
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod < "$file"
done
# 启动后端服务
docker start ai_backend_prod
# 清理临时文件
rm /tmp/ai_project_clean.sql.gz
```
---
## 最佳实践
### Docker Volumes 安全配置
**关键规则**: 所有生产数据卷必须配置为 `external: true`
**正确配置** (`deploy/tencent-cloud/docker-compose.dockerhub.yml`):
```yaml
volumes:
postgres_prod_data:
external: true
name: ai-project_postgres_prod_data
redis_prod_data:
external: true
name: ai-project_redis_prod_data
```
**危险配置** (会被 `docker compose down` 删除):
```yaml
volumes:
postgres_prod_data:
redis_prod_data:
```
**验证**:
```bash
ssh tools_ai_proj "docker volume ls | grep ai-project"
# 应该看到:
# ai-project_postgres_prod_data
# ai-project_redis_prod_data
```
### 备份策略
1. **每日自动备份** - 使用 cron 定时任务
2. **双层备份** - 本地 + 阿里云 OSS
3. **定期验证** - 每周测试备份恢复流程
4. **保留策略** - 30 天自动清理
### pg_dump 最佳参数
```bash
# 跨服务器迁移
pg_dump --no-owner --no-acl --clean --if-exists --exclude-table=<problem_table>
# 参数说明:
# --no-owner 不恢复对象所有者(避免用户名冲突)
# --no-acl 不恢复访问权限(避免权限问题)
# --clean 包含 DROP 语句(完全替换)
# --if-exists DROP 前检查存在(避免错误)
# --exclude-table 排除问题表(如有 JSON 格式问题的表)
```
### 数据恢复检查清单
在执行恢复前,务必检查以下项目:
- [ ] 确认备份文件完整性gzip -t 验证)
- [ ] 停止相关应用服务(避免数据不一致)
- [ ] 完全重建数据库DROP + CREATE避免依赖冲突
- [ ] 恢复后创建缺失的表(如被排除的表)
- [ ] 运行数据库迁移(确保表结构最新)
- [ ] 验证数据完整性(检查关键表行数)
- [ ] 测试应用功能(登录、关键业务流程)
- [ ] 清理临时文件备份文件、SQL 文件)
### 网络传输优化
**场景**: 跨地域高延迟环境(如澳洲 → 腾讯云)
**问题**: 直连延迟 370ms+,大文件传输极慢
**方案**: 使用地理位置中间的跳板机
```bash
# 直连(慢): 澳洲 → 腾讯云 (370ms+)
scp file.gz tools_ai_proj:/tmp/
# 优化(快): 澳洲 → 新加坡 → 腾讯云
scp file.gz singapore:/tmp/
ssh singapore "scp /tmp/file.gz tools_ai_proj:/tmp/"
```
**新加坡跳板机信息**:
- 别名: singapore
- IP: 43.134.28.147
- 用户: ubuntu
- SSH Key: ~/.ssh/singpore.pem
---
## 监控与告警
### 每周检查清单
**建议执行频率**: 每周一次
```bash
# 1. 检查本地备份
ssh tools_ai_proj "ls -lh /backup/ai-project/database/$(date +%Y%m%d)/"
# 2. 检查 OSS 备份
ssh tools_ai_proj "ossutil stat oss://fnos2026/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
# 3. 检查 cron 日志
ssh tools_ai_proj "tail -20 /var/log/ai-project-backup.log"
ssh tools_ai_proj "tail -20 /var/log/ai-project-oss-sync.log"
# 4. 验证备份大小(应该在 10-20M 范围)
ssh tools_ai_proj "du -sh /backup/ai-project/database/$(date +%Y%m%d)/"
# 5. 测试备份完整性
ssh tools_ai_proj "
gzip -t /backup/ai-project/database/latest.sql.gz && \
echo '✓ 本地备份完整' || echo '✗ 本地备份损坏'
"
```
### 备份失败排查
如果备份或同步失败:
1. **检查磁盘空间**:
```bash
ssh tools_ai_proj "df -h"
```
2. **检查 PostgreSQL 容器状态**:
```bash
ssh tools_ai_proj "docker ps | grep postgres"
```
3. **检查 ossutil 配置**:
```bash
ssh tools_ai_proj "cat ~/.ossutilconfig"
```
4. **测试 OSS 连接**:
```bash
ssh tools_ai_proj "ossutil ls oss://fnos2026/ --config-file ~/.ossutilconfig"
```
5. **手动运行脚本查看详细错误**:
```bash
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"
```
---
## 成本估算
**基于当前数据量** (13MB/天):
| 项目 | 计算 | 月成本 |
|------|------|--------|
| OSS 存储 | 13MB × 30天 = 390MB × ¥0.12/GB | ¥0.05 |
| OSS 流量 | 13MB × 30天 = 390MB × ¥0.50/GB | ¥0.20 |
| **总计** | | **¥0.25** |
---
## 故障案例
### 2026-01-15: 生产数据库丢失事件
**事件时间**: 2026-01-15 00:00:00 - 00:46:00 CST
**事件**: Jenkins 部署时 `docker compose down` 删除了非 external volumes
**影响**: 生产数据库完全清空,所有用户无法登录
**恢复过程**:
1. 从本地开发环境导出完整数据41 用户、54 项目、4,722 任务)
2. 使用新加坡跳板机优化传输(解决 370ms+ 延迟)
3. 完全重建数据库避免依赖冲突
4. 重置所有管理员密码
**恢复完成时间**: 2026-01-15 00:46:00 CST
**预防措施**:
1. ✅ 所有数据卷标记为 `external: true` (完成时间: 2026-01-15 00:46:00)
2. ✅ Jenkinsfile 添加自动数据库迁移 (完成时间: 2026-01-15 00:46:00)
3. ✅ 临时禁用 webhook 自动部署 (完成时间: 2026-01-15 00:46:00)
4. ✅ 配置自动备份策略(本地 + OSS 双层备份)(完成时间: 2026-01-15 02:30:46)
**详细记录**: 见思源笔记 `devops/运维记录/2026-01-15 AI-Proj生产数据库恢复记录`
---
## 用户管理相关
数据库用户管理(创建用户、重置密码)请参考:
- **ops-tools/SKILL.md** - "AI-Proj 用户管理" 章节
- **ai-proj-deploy.md** - "用户管理" 章节
**关键注意事项**
- 密码哈希使用 bcrypt **cost 12**(后端 `utils/password.go` 的 `DefaultCost`
- 由于 `$` 字符问题SQL 必须通过文件传输方式执行
---
## 相关资源
- **父技能**: ops-tools/skill.md
- **备份脚本**: `/opt/ai-project/deploy/scripts/backup-database.sh`
- **OSS 同步脚本**: `/opt/ai-project/deploy/scripts/backup-to-oss.sh`
- **凭据文件**: `~/.config/devops/credentials.env`
- **SiYuan 笔记**: `devops/运维记录/2026-01-15 AI-Proj生产数据库恢复记录`
---
---
## 数据库迁移标准流程
> **强制要求**:任何数据库迁移操作必须遵循以下流程。
### 迁移检查清单
```
┌─────────────────────────────────────────────────────────────┐
│ 数据库迁移标准流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 迁移前备份 ⬅️ 必须 │
│ ssh tools_ai_proj 'docker exec ai_postgres_prod \ │
│ pg_dump -U ai_prod_user -Fc ai_project_prod \ │
│ > /backup/ai-project/database/pre_migration.dump' │
│ │
│ 2. 验证备份文件 │
│ ssh tools_ai_proj 'ls -lh /backup/.../pre_migration.dump'│
│ │
│ 3. 记录迁移前状态 │
│ SELECT COUNT(*) FROM <table>; │
│ │
│ 4. 执行迁移(使用事务) │
│ BEGIN; ... COMMIT; │
│ │
│ 5. 验证迁移结果 │
│ SELECT COUNT(*) FROM <table>; │
│ │
│ 6. 如有问题,恢复备份 │
│ pg_restore -Fc pre_migration.dump │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 迁移 SQL 模板
```sql
-- ============================================
-- 迁移脚本模板
-- 执行前请先备份!
-- ============================================
BEGIN;
-- 迁移前统计
\echo '=== 迁移前统计 ==='
SELECT 'table_name' as info, COUNT(*) as count FROM table_name WHERE condition;
-- 执行迁移
\echo '=== 执行迁移 ==='
UPDATE table_name SET column = new_value WHERE condition;
-- 迁移后统计
\echo '=== 迁移后统计 ==='
SELECT 'table_name' as info, COUNT(*) as count FROM table_name WHERE condition;
-- 确认无误后提交
COMMIT;
\echo '=== 迁移完成 ==='
```
### 迁移失败回滚
```bash
# 1. 停止后端服务
ssh tools_ai_proj 'docker stop ai_backend_prod'
# 2. 恢复备份
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_restore \
-U ai_prod_user -d ai_project_prod --clean --if-exists -Fc \
/backup/ai-project/database/ai_project_XXXXXXXX_pre_migration.dump'
# 3. 启动后端服务
ssh tools_ai_proj 'docker start ai_backend_prod'
# 4. 验证服务
curl -s https://ai.pipexerp.com/api/v1/health | jq .
```
---
## 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 2.0 | 2026-02-02 | 升级为全局技能新增迁移前备份流程、多数据库支持、7天+月度保留策略、快速恢复命令 |
| 1.0 | 2026-01-15 | 初始版本AI-Proj 备份与 OSS 同步 |
---
**文档创建时间**: 2026-01-15 07:30:00 ACDT
**最后更新时间**: 2026-02-02
**文档状态**: ✅ 正常运行

View File

@@ -1,41 +0,0 @@
#!/bin/bash
# 部署状态检查脚本
# 用法: ./deploy-check.sh [ai-proj|pipeXerp]
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
JOB_NAME="${1:-ai-proj}"
echo "======================================"
echo "Jenkins Job: $JOB_NAME"
echo "======================================"
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << EOF
echo "--- 最近 5 次构建 ---"
ls -lt /var/lib/jenkins/jobs/$JOB_NAME/builds/ 2>/dev/null | head -6
echo ""
echo "--- 最近成功构建 ---"
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild ]; then
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild)
echo "Build #\$BUILD_NUM"
if [ -f "/var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log" ]; then
echo "构建时间: \$(stat -c %y /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || stat -f %Sm /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log)"
fi
else
echo "无成功构建记录"
fi
echo ""
echo "--- 最近失败构建 ---"
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild ]; then
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild)
echo "Build #\$BUILD_NUM"
echo "错误日志(最后 20 行):"
tail -20 /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || echo "无法读取日志"
else
echo "无失败构建记录"
fi
EOF

View File

@@ -1,97 +0,0 @@
#!/bin/bash
# Gitea PR 操作脚本
# 用法:
# ./gitea-pr.sh list # 列出 PR
# ./gitea-pr.sh create <title> <head> # 创建 PR
# ./gitea-pr.sh merge <pr-number> # 合并 PR
set -e
# 加载凭据
source ~/.config/devops/credentials.env
REPO="Tools/new-ai-proj"
ACTION="${1:-list}"
case "$ACTION" in
list)
echo "=== 当前 Pull Requests ==="
curl -s "$GITEA_URL/api/v1/repos/$REPO/pulls?state=open" \
-H "Authorization: token $GITEA_TOKEN" | \
python3 -c "
import sys, json
prs = json.load(sys.stdin)
if not prs:
print('没有开放的 PR')
else:
for pr in prs:
print(f\"#{pr['number']} [{pr['state']}] {pr['title']}\")
print(f\" {pr['head']['ref']} -> {pr['base']['ref']}\")
print(f\" 作者: {pr['user']['login']}\")
print()
"
;;
create)
TITLE="$2"
HEAD="$3"
BASE="${4:-main}"
if [ -z "$TITLE" ] || [ -z "$HEAD" ]; then
echo "用法: $0 create <title> <head-branch> [base-branch]"
exit 1
fi
echo "创建 PR: $TITLE"
echo "分支: $HEAD -> $BASE"
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\":\"$TITLE\",\"head\":\"$HEAD\",\"base\":\"$BASE\"}" | \
python3 -c "
import sys, json
pr = json.load(sys.stdin)
if 'number' in pr:
print(f\"PR 创建成功! #{pr['number']}\")
print(f\"URL: {pr['html_url']}\")
else:
print(f\"创建失败: {pr.get('message', '未知错误')}\")
"
;;
merge)
PR_NUM="$2"
if [ -z "$PR_NUM" ]; then
echo "用法: $0 merge <pr-number>"
exit 1
fi
echo "合并 PR #$PR_NUM..."
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM/merge" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Do":"merge"}' | \
python3 -c "
import sys, json
try:
result = json.load(sys.stdin)
if result:
print(f\"结果: {result}\")
else:
print('PR 合并成功!')
except:
print('PR 合并成功!')
"
;;
*)
echo "用法: $0 {list|create|merge}"
echo " list - 列出所有开放的 PR"
echo " create <title> <head> - 创建新 PR"
echo " merge <pr-number> - 合并 PR"
exit 1
;;
esac

View File

@@ -1,84 +0,0 @@
#!/bin/bash
# 服务器健康检查脚本
# 用法: ./health-check.sh [aliyun|website|all]
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
WEBSITE_SERVER="root@192.144.137.14"
WEBSITE_KEY="~/.ssh/officialWebsite.pem"
check_tools_server() {
echo "======================================"
echo "Tools 服务器 (101.200.136.200)"
echo "======================================"
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << 'EOF'
echo "--- 系统负载 ---"
uptime
echo ""
echo "--- 内存使用 ---"
free -h
echo ""
echo "--- 磁盘使用 ---"
df -h | grep -E '^/dev|Filesystem'
echo ""
echo "--- Docker 容器 ---"
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
echo ""
echo "--- 系统服务 ---"
echo -n "Jenkins: "; systemctl is-active jenkins
echo -n "Nginx: "; systemctl is-active nginx
echo -n "Docker: "; systemctl is-active docker
echo ""
echo "--- 端口检查 ---"
netstat -tlnp 2>/dev/null | grep -E ':3000|:8080|:10022|:5000' | awk '{print $4, $7}'
EOF
}
check_website_server() {
echo "======================================"
echo "Website 服务器 (192.144.137.14)"
echo "======================================"
ssh -i $WEBSITE_KEY -o ConnectTimeout=5 $WEBSITE_SERVER << 'EOF'
echo "--- 系统负载 ---"
uptime
echo ""
echo "--- 内存使用 ---"
free -h
echo ""
echo "--- 磁盘使用 ---"
df -h | grep -E '^/dev|Filesystem'
echo ""
echo "--- Nginx 状态 ---"
systemctl is-active nginx || echo "nginx not running"
EOF
}
case "${1:-all}" in
aliyun|tools)
check_tools_server
;;
website)
check_website_server
;;
all)
check_tools_server
echo ""
check_website_server
;;
*)
echo "用法: $0 [aliyun|website|all]"
exit 1
;;
esac

View File

@@ -1,76 +0,0 @@
# 重大事件记录
**创建时间**: 2026-01-29 11:50:00 CST
**父技能**: ops-tools
---
## 2026-01-17: Melbourne 服务器 VNC 配置失误导致系统崩溃
**事件时间**: 2026-01-17 08:49:00 - 09:02:00+ ACDT
**事件**: 执行 `sudo pkill -9 -u coolbuy-dev` 导致 Melbourne 服务器崩溃失联
**后果**:
- macOS 图形系统崩溃
- Tailscale VPN 中断
- SSH 完全无法连接
**根本原因**: macOS 图形系统依赖用户会话,强制终止会导致 WindowServer 崩溃
**教训**:
```bash
# 永远不要在远程 macOS 上执行
sudo pkill -9 -u <username>
sudo killall -9 -u <username>
```
**解决方案**: 需要物理访问恢复
---
## 2026-01-16: AI-Proj Webhook 自动部署重新启用
**事件时间**: 2026-01-16 11:06:01 CST
**事件**: Gitea webhook 重新启用,恢复 main 分支自动部署
**验证结果**:
- Jenkins build #64 自动触发成功
- 数据库数据完整保留664条需求记录验证通过
- External volumes 配置有效
**部署流程**: `开发者 merge PR → Gitea webhook → Jenkins → 生产自动部署`
---
## 2026-01-15: AI-Proj 生产数据库丢失与恢复
**事件时间**: 2026-01-15 00:00:00 - 00:46:00 CST
**事件**: Jenkins 部署时 `docker compose down` 删除了非 external volumes
**影响**: 生产数据库完全清空,所有用户无法登录
**恢复过程**:
1. 从本地开发环境恢复完整数据41 用户、54 项目、4,722 任务)
2. 使用新加坡跳板机优化传输
3. 完全重建数据库
**恢复完成**: 2026-01-15 00:46:00 CST
**预防措施**:
1. 所有数据卷标记为 `external: true`
2. Jenkinsfile 添加自动数据库迁移
3. 配置自动备份策略(本地 + 阿里云 OSS
---
## 事件记录规范
记录重大事件时必须包含:
- **事件时间**: 完整的开始和结束时间
- **事件描述**: 清晰简洁的事件说明
- **影响范围**: 受影响的系统和用户
- **恢复过程**: 详细的恢复步骤
- **预防措施**: 包含完成时间

View File

@@ -1,46 +0,0 @@
#!/bin/bash
# Jenkins 构建触发脚本
# 用法: ./jenkins-build.sh [job-name] [env]
# 示例: ./jenkins-build.sh ai-proj staging
set -e
# 加载凭据
source ~/.config/devops/credentials.env
JOB_NAME="${1:-ai-proj}"
DEPLOY_ENV="${2:-staging}"
echo "触发 Jenkins 构建..."
echo "Job: $JOB_NAME"
echo "环境: $DEPLOY_ENV"
echo ""
# 触发构建
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
"$JENKINS_URL/job/$JOB_NAME/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "DEPLOY_ENV=$DEPLOY_ENV&SKIP_TESTS=false")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" = "201" ]; then
echo "构建已触发成功!"
echo ""
echo "查看构建状态: $JENKINS_URL/job/$JOB_NAME/"
# 等待 2 秒后获取构建号
sleep 2
BUILD_INFO=$(curl -s "$JENKINS_URL/job/$JOB_NAME/lastBuild/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN" 2>/dev/null)
if [ -n "$BUILD_INFO" ]; then
BUILD_NUM=$(echo "$BUILD_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('number','N/A'))" 2>/dev/null || echo "N/A")
BUILD_STATUS=$(echo "$BUILD_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print('进行中' if d.get('building') else d.get('result','未知'))" 2>/dev/null || echo "未知")
echo "构建号: #$BUILD_NUM"
echo "状态: $BUILD_STATUS"
fi
else
echo "构建触发失败! HTTP 状态码: $HTTP_CODE"
exit 1
fi

View File

@@ -1,165 +0,0 @@
# Claude Code MCP 配置指南
**创建时间**: 2026-01-29 11:50:00 CST
**父技能**: ops-tools
## 概述
MCP (Model Context Protocol) 是 Claude Code 与外部服务集成的标准协议。
## 配置文件位置
| 配置文件 | 作用域 | 说明 |
|----------|--------|------|
| `~/.claude/.mcp.json` | 用户级(推荐) | 所有项目共享 |
| `.claude/mcp.json` | 项目级 | 仅当前项目生效 |
## 配置模板stdio 模式)
```json
{
"mcpServers": {
"<服务名称>": {
"type": "stdio",
"command": "node",
"args": ["<服务入口文件路径>"],
"env": {
"API_BASE": "<API基础URL>",
"API_TOKEN": "<PAT令牌>",
"NODE_ENV": "production"
}
}
}
}
```
**参数说明**
| 参数 | 说明 | 示例 |
|------|------|------|
| `type` | 传输类型,固定为 `stdio` | `stdio` |
| `command` | 启动命令 | `node` |
| `args` | 入口文件路径 | `["dist/index.js"]` |
| `env` | 环境变量 | API 地址、PAT 令牌 |
## ai-proj MCP 配置
**配置文件** (`~/.claude/.mcp.json`):
```json
{
"mcpServers": {
"ai-proj": {
"type": "stdio",
"command": "node",
"args": ["/Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099",
"NODE_ENV": "production"
}
}
}
}
```
### 环境变量
| 变量 | 说明 |
|------|------|
| `TASK_API_BASE` | `https://ai.pipexerp.com/api/v1` |
| `TASK_API_TOKEN` | `aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099` |
### 前置条件
```bash
# 编译 mcp-task-bridge
cd /Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge
npm run build
```
### 验证步骤
```bash
# 1. 手动测试服务
cd /Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge
TASK_API_BASE="https://ai.pipexerp.com/api/v1" \
TASK_API_TOKEN="aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" \
node dist/index.js
# 2. 测试 API 连接
curl -s "https://ai.pipexerp.com/api/v1/projects" \
-H "Authorization: Bearer aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" | head -c 200
# 3. Claude Code 重连
/mcp
```
## 开发新 MCP 服务
### 步骤 1: 创建项目
```bash
mkdir my-mcp-service && cd my-mcp-service
npm init -y
npm install @modelcontextprotocol/sdk
```
### 步骤 2: 实现服务
```typescript
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "my-mcp-service",
version: "1.0.0",
}, { capabilities: { tools: {} } });
// 注册和实现工具...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### 步骤 3: 编译和配置
```bash
npm run build
vim ~/.claude/.mcp.json # 添加配置
claude # 重启 Claude Code
```
## 故障排查
### MCP 连接失败
```bash
# 1. 检查配置文件
cat ~/.claude/.mcp.json | jq .
# 2. 检查服务文件
ls -la <服务路径>/dist/index.js
# 3. 手动运行服务
<环境变量> node dist/index.js
```
**常见原因**
- 服务未编译 → `npm run build`
- Token 无效 → 重新生成 PAT
- `/mcp` 无效 → 重启 Claude Code
### 认证失败 (401)
```bash
curl -s "<API_BASE>/auth/me" -H "Authorization: Bearer <TOKEN>"
```
## 相关文件
| 文件 | 说明 |
|------|------|
| `~/.claude/.mcp.json` | MCP 配置 |
| `mcp-task-bridge/dist/index.js` | ai-proj MCP 服务 |

View File

@@ -1,41 +0,0 @@
#!/bin/bash
# 部署状态检查脚本
# 用法: ./deploy-check.sh [ai-proj|pipeXerp]
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
JOB_NAME="${1:-ai-proj}"
echo "======================================"
echo "Jenkins Job: $JOB_NAME"
echo "======================================"
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << EOF
echo "--- 最近 5 次构建 ---"
ls -lt /var/lib/jenkins/jobs/$JOB_NAME/builds/ 2>/dev/null | head -6
echo ""
echo "--- 最近成功构建 ---"
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild ]; then
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild)
echo "Build #\$BUILD_NUM"
if [ -f "/var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log" ]; then
echo "构建时间: \$(stat -c %y /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || stat -f %Sm /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log)"
fi
else
echo "无成功构建记录"
fi
echo ""
echo "--- 最近失败构建 ---"
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild ]; then
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild)
echo "Build #\$BUILD_NUM"
echo "错误日志(最后 20 行):"
tail -20 /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || echo "无法读取日志"
else
echo "无失败构建记录"
fi
EOF

View File

@@ -1,97 +0,0 @@
#!/bin/bash
# Gitea PR 操作脚本
# 用法:
# ./gitea-pr.sh list # 列出 PR
# ./gitea-pr.sh create <title> <head> # 创建 PR
# ./gitea-pr.sh merge <pr-number> # 合并 PR
set -e
# 加载凭据
source ~/.config/devops/credentials.env
REPO="Tools/new-ai-proj"
ACTION="${1:-list}"
case "$ACTION" in
list)
echo "=== 当前 Pull Requests ==="
curl -s "$GITEA_URL/api/v1/repos/$REPO/pulls?state=open" \
-H "Authorization: token $GITEA_TOKEN" | \
python3 -c "
import sys, json
prs = json.load(sys.stdin)
if not prs:
print('没有开放的 PR')
else:
for pr in prs:
print(f\"#{pr['number']} [{pr['state']}] {pr['title']}\")
print(f\" {pr['head']['ref']} -> {pr['base']['ref']}\")
print(f\" 作者: {pr['user']['login']}\")
print()
"
;;
create)
TITLE="$2"
HEAD="$3"
BASE="${4:-main}"
if [ -z "$TITLE" ] || [ -z "$HEAD" ]; then
echo "用法: $0 create <title> <head-branch> [base-branch]"
exit 1
fi
echo "创建 PR: $TITLE"
echo "分支: $HEAD -> $BASE"
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\":\"$TITLE\",\"head\":\"$HEAD\",\"base\":\"$BASE\"}" | \
python3 -c "
import sys, json
pr = json.load(sys.stdin)
if 'number' in pr:
print(f\"PR 创建成功! #{pr['number']}\")
print(f\"URL: {pr['html_url']}\")
else:
print(f\"创建失败: {pr.get('message', '未知错误')}\")
"
;;
merge)
PR_NUM="$2"
if [ -z "$PR_NUM" ]; then
echo "用法: $0 merge <pr-number>"
exit 1
fi
echo "合并 PR #$PR_NUM..."
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM/merge" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Do":"merge"}' | \
python3 -c "
import sys, json
try:
result = json.load(sys.stdin)
if result:
print(f\"结果: {result}\")
else:
print('PR 合并成功!')
except:
print('PR 合并成功!')
"
;;
*)
echo "用法: $0 {list|create|merge}"
echo " list - 列出所有开放的 PR"
echo " create <title> <head> - 创建新 PR"
echo " merge <pr-number> - 合并 PR"
exit 1
;;
esac

View File

@@ -1,84 +0,0 @@
#!/bin/bash
# 服务器健康检查脚本
# 用法: ./health-check.sh [aliyun|website|all]
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
WEBSITE_SERVER="root@192.144.137.14"
WEBSITE_KEY="~/.ssh/officialWebsite.pem"
check_tools_server() {
echo "======================================"
echo "Tools 服务器 (101.200.136.200)"
echo "======================================"
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << 'EOF'
echo "--- 系统负载 ---"
uptime
echo ""
echo "--- 内存使用 ---"
free -h
echo ""
echo "--- 磁盘使用 ---"
df -h | grep -E '^/dev|Filesystem'
echo ""
echo "--- Docker 容器 ---"
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
echo ""
echo "--- 系统服务 ---"
echo -n "Jenkins: "; systemctl is-active jenkins
echo -n "Nginx: "; systemctl is-active nginx
echo -n "Docker: "; systemctl is-active docker
echo ""
echo "--- 端口检查 ---"
netstat -tlnp 2>/dev/null | grep -E ':3000|:8080|:10022|:5000' | awk '{print $4, $7}'
EOF
}
check_website_server() {
echo "======================================"
echo "Website 服务器 (192.144.137.14)"
echo "======================================"
ssh -i $WEBSITE_KEY -o ConnectTimeout=5 $WEBSITE_SERVER << 'EOF'
echo "--- 系统负载 ---"
uptime
echo ""
echo "--- 内存使用 ---"
free -h
echo ""
echo "--- 磁盘使用 ---"
df -h | grep -E '^/dev|Filesystem'
echo ""
echo "--- Nginx 状态 ---"
systemctl is-active nginx || echo "nginx not running"
EOF
}
case "${1:-all}" in
aliyun|tools)
check_tools_server
;;
website)
check_website_server
;;
all)
check_tools_server
echo ""
check_website_server
;;
*)
echo "用法: $0 [aliyun|website|all]"
exit 1
;;
esac

View File

@@ -1,46 +0,0 @@
#!/bin/bash
# Jenkins 构建触发脚本
# 用法: ./jenkins-build.sh [job-name] [env]
# 示例: ./jenkins-build.sh ai-proj staging
set -e
# 加载凭据
source ~/.config/devops/credentials.env
JOB_NAME="${1:-ai-proj}"
DEPLOY_ENV="${2:-staging}"
echo "触发 Jenkins 构建..."
echo "Job: $JOB_NAME"
echo "环境: $DEPLOY_ENV"
echo ""
# 触发构建
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
"$JENKINS_URL/job/$JOB_NAME/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "DEPLOY_ENV=$DEPLOY_ENV&SKIP_TESTS=false")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" = "201" ]; then
echo "构建已触发成功!"
echo ""
echo "查看构建状态: $JENKINS_URL/job/$JOB_NAME/"
# 等待 2 秒后获取构建号
sleep 2
BUILD_INFO=$(curl -s "$JENKINS_URL/job/$JOB_NAME/lastBuild/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN" 2>/dev/null)
if [ -n "$BUILD_INFO" ]; then
BUILD_NUM=$(echo "$BUILD_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('number','N/A'))" 2>/dev/null || echo "N/A")
BUILD_STATUS=$(echo "$BUILD_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print('进行中' if d.get('building') else d.get('result','未知'))" 2>/dev/null || echo "未知")
echo "构建号: #$BUILD_NUM"
echo "状态: $BUILD_STATUS"
fi
else
echo "构建触发失败! HTTP 状态码: $HTTP_CODE"
exit 1
fi

View File

@@ -1,44 +0,0 @@
#!/bin/bash
# 服务重启脚本
# 用法: ./service-restart.sh <service-name>
# 支持: gitea, jenkins, nginx, registry
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
SERVICE_NAME="$1"
if [ -z "$SERVICE_NAME" ]; then
echo "用法: $0 <service-name>"
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
exit 1
fi
echo "正在重启服务: $SERVICE_NAME ..."
case "$SERVICE_NAME" in
gitea)
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart gitea && docker logs --tail 10 gitea"
;;
registry)
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart registry && docker ps | grep registry"
;;
jenkins)
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart jenkins && systemctl status jenkins --no-pager"
;;
nginx)
ssh -i $TOOLS_KEY $TOOLS_SERVER "nginx -t && systemctl restart nginx && systemctl status nginx --no-pager"
;;
docker)
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart docker && docker ps"
;;
*)
echo "不支持的服务: $SERVICE_NAME"
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
exit 1
;;
esac
echo ""
echo "服务 $SERVICE_NAME 重启完成"

View File

@@ -1,44 +0,0 @@
#!/bin/bash
# 服务重启脚本
# 用法: ./service-restart.sh <service-name>
# 支持: gitea, jenkins, nginx, registry
set -e
TOOLS_SERVER="root@101.200.136.200"
TOOLS_KEY="~/.ssh/tools.pem"
SERVICE_NAME="$1"
if [ -z "$SERVICE_NAME" ]; then
echo "用法: $0 <service-name>"
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
exit 1
fi
echo "正在重启服务: $SERVICE_NAME ..."
case "$SERVICE_NAME" in
gitea)
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart gitea && docker logs --tail 10 gitea"
;;
registry)
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart registry && docker ps | grep registry"
;;
jenkins)
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart jenkins && systemctl status jenkins --no-pager"
;;
nginx)
ssh -i $TOOLS_KEY $TOOLS_SERVER "nginx -t && systemctl restart nginx && systemctl status nginx --no-pager"
;;
docker)
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart docker && docker ps"
;;
*)
echo "不支持的服务: $SERVICE_NAME"
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
exit 1
;;
esac
echo ""
echo "服务 $SERVICE_NAME 重启完成"

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
{
"name": "coolbuy-legacy-plugin",
"description": "酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,414 +0,0 @@
---
name: coolbuy-legacy
description: 酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。当用户提到酷采2.0、百丽、李宁、遗留系统测试相关任务时自动激活。
---
# Coolbuy Legacy (酷采2.0) Skill
酷采2.0团购管理系统,服务于百丽、李宁等客户的遗留系统,采用 Vue 2 + Element UI + Java Spring 技术栈。
## 项目信息
| 项目 | 值 |
|------|-----|
| 项目编号 | P264 |
| 项目名称 | 酷采 2.0 |
| AI-Proj 项目ID | 164 |
| 源码路径 | `/Users/donglinlai/workspace/coolbuy-legacy` |
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-legacy.git` |
| 主分支 | main |
| 技术栈 | Vue 2 + Element UI + Java Spring |
---
## 系统访问
### 测试环境
| 项目 | 值 |
|------|-----|
| 测试地址 | http://47.105.185.154:9300/login |
| 管理员账号 | 19090009801 |
| 密码 | 123456 |
| 客户账号 | 17761202551 / 202551 |
| 服务器 | 47.105.185.154 |
### 主要客户
- **百丽集团** - 大型鞋业零售集团
- **李宁体育** - 知名体育用品品牌
---
## 架构概览
```
coolbuy-legacy/
├── cool_lining/module-provider/ # Java 后端服务
│ └── src/main/java/com/jzg/module/
│ ├── action/ # 控制器层
│ │ ├── prd/ # 商品模块控制器
│ │ ├── order/ # 订单模块控制器
│ │ └── customer/ # 客户模块控制器
│ ├── dao/model/ # 数据模型
│ │ ├── prd/ # 商品实体
│ │ ├── order/ # 订单实体
│ │ └── customer/ # 客户实体
│ └── manager/ # 业务逻辑层
│ ├── prd/ # 商品业务逻辑
│ ├── order/ # 订单业务逻辑
│ └── customer/ # 客户业务逻辑
└── ln_admin/ # Vue 2 前端
└── src/views2/module/ # 业务模块页面
├── prd/ # 商品管理页面
├── order/ # 订单管理页面
└── customer/ # 客户管理页面
```
---
## 主要功能模块
### 核心业务模块
1. **推广方案管理**
- 促销活动配置
- 折扣规则设置
- 活动效果统计
2. **销售管理**
- 订单处理流程
- 销售数据统计
- 客户下单管理
3. **草稿单管理**
- 未完成订单保存
- 草稿单编辑
- 批量转正式单
4. **Y码直客**
- 直客订单管理
- Y码生成与核销
- 直客价格体系
5. **库存管理**
- 库存查询
- 库存调拨
- 库存预警
6. **货盘管理**
- 货盘创建
- 货盘分配
- 货盘跟踪
7. **协同仓管理**
- 多仓协同
- 仓库调度
- 发货管理
8. **价格管理**
- 商品定价
- 客户价格体系
- 最低折扣限制
9. **资金管理**
- 账户余额
- 充值记录
- 消费明细
10. **产品管理**
- 商品信息维护
- SPU/SKU管理
- 商品分类
11. **基础功能**
- 客户管理
- 用户权限
- 系统配置
12. **数据看板**
- 销售数据分析
- 库存报表
- 业务概览
13. **公告通知**
- 系统公告
- 消息推送
- 通知管理
14. **起售数量设置**
- 最小起售量
- 批量设置
- 规则配置
---
## 与酷采3.0的对比
### 技术栈差异
| 项目 | 酷采2.0 (Legacy) | 酷采3.0 (PaaS) |
|------|------------------|----------------|
| 前端框架 | Vue 2 | React 18 |
| UI组件库 | Element UI | Ant Design |
| 前端构建 | Webpack | Vite |
| 后端语言 | Java | Go |
| 后端框架 | Spring Boot | Gin + go-zero |
| 数据库 | MySQL | PostgreSQL |
| 架构模式 | 单体应用 | 微服务 |
| 部署方式 | 传统部署 | Docker + K8s |
### 业务差异
| 功能 | 酷采2.0 | 酷采3.0 |
|------|---------|---------|
| 多租户 | ❌ 单租户 | ✅ 多租户 SaaS |
| 客户隔离 | 账号级别 | 企业级别 |
| 定制化 | 客户专属部署 | 配置化租户 |
| 扩展性 | 垂直扩展 | 水平扩展 |
---
## 测试任务管理
### AI-Proj 项目集成
当前项目在 AI-Proj 系统中的ID为 **164**,包含以下测试任务:
#### 客户最低折扣申请限制功能测试
**父任务**: #4725 (in_progress)
**测试用例**:
- ✅ TC001: 按客户类型配置最低折扣 [P0] - #4726
- ✅ TC002: 按特定客户配置最低折扣 [P0] - #4727
- ✅ TC003: 折扣下限输入验证 [P1] - #4728
- ✅ TC004: 阈值导入模板 [P1] - #4729
- ✅ TC005: 折扣低于下限 - 拦截 [P0] - #4730
- ✅ TC006: 折扣等于下限 - 通过 [P0] - #4731
- ✅ TC007: 折扣高于下限 - 通过 [P1] - #4732
- 🔄 TC008: 多商品触发限制 - 罗列提示 [P0] - #4733
- ⏳ TC009: 非一级账号不受限 [P1] - #4734
- ⏳ TC010: 审核修改折扣低于下限 - 拦截 [P0] - #4735
- ⏳ TC011: 审核修改折扣等于下限 - 通过 [P0] - #4736
- ⏳ TC012: 限价标签显示 [P1] - #4737
- ⏳ TC013: 提示文字验证 [P1] - #4738
### 查询任务
```javascript
// 获取酷采2.0项目任务列表
mcp__ai-proj__list_tasks({ projectId: 164 })
// 获取特定任务详情
mcp__ai-proj__get_detailed_task_info({ taskId: 4725 })
// 获取任务文档
mcp__ai-proj__get_task_document({ taskId: 4725 })
```
---
## Chrome DevTools 浏览器自动化
### 启动调试模式
```bash
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-debug
```
### 验证连接
```bash
curl http://127.0.0.1:9222/json/version
```
### 验证码处理规则
**重要**: 当访问需要验证码的系统时:
1. **不要**使用脚本截图方式获取验证码(验证码会快速过期)
2. **直接提醒用户**
- 请在浏览器中输入验证码
- 或请帮我点击登录按钮
3. 用户操作完成后再继续自动化流程
示例提示:
```
浏览器已打开登录页面,验证码需要手动输入。请在 Chrome 浏览器中:
1. 输入验证码
2. 点击登录按钮
完成后告诉我,我将继续后续操作。
```
### 常用 MCP 操作
```javascript
// 列出所有页面
mcp__chrome-devtools__list_pages()
// 选择页面
mcp__chrome-devtools__select_page({ pageId: 1 })
// 导航到URL
mcp__chrome-devtools__navigate_page({
type: "url",
url: "http://47.105.185.154:9300/login"
})
// 截图
mcp__chrome-devtools__take_screenshot({
format: "png",
filePath: "/tmp/screenshot.png"
})
// 获取页面快照
mcp__chrome-devtools__take_snapshot()
// 点击元素
mcp__chrome-devtools__click({ uid: "element_uid" })
// 填写表单
mcp__chrome-devtools__fill({
uid: "input_uid",
value: "text"
})
// 执行JavaScript
mcp__chrome-devtools__evaluate_script({
function: "() => { return document.title; }"
})
```
---
## 常见测试场景
### 1. 客户最低折扣测试
**测试步骤**:
1. 登录管理员账号 (19090009801)
2. 进入价格管理 → 最低折扣配置
3. 配置客户类型或特定客户的最低折扣
4. 使用客户账号 (17761202551) 登录
5. 创建订单,测试折扣限制规则
**验证点**:
- 折扣低于下限时系统拦截
- 折扣等于或高于下限时通过
- 多商品触发时正确罗列提示
- 非一级账号不受限制
### 2. 订单流程测试
**测试步骤**:
1. 客户账号登录
2. 选择商品加入购物车
3. 提交订单
4. 审核订单 (管理员)
5. 发货处理
6. 订单完成
### 3. 库存管理测试
**测试步骤**:
1. 查询库存
2. 创建库存调拨单
3. 审核调拨单
4. 确认入库
5. 验证库存变化
---
## 需求对比测试流程
当酷采3.0实现新功能时需要与酷采2.0进行对比:
### 测试流程
1. **功能分析**
- 在酷采2.0中找到对应功能
- 记录现有实现方式
- 识别差异点
2. **页面对比**
- 截图酷采2.0界面
- 对比UI/UX差异
- 记录交互流程
3. **数据对比**
- 对比数据模型
- 验证业务规则
- 确认边界条件
4. **性能对比**
- 记录响应时间
- 对比并发能力
- 评估用户体验
---
## 问题排查
### 常见问题
1. **登录失败**
- 检查账号密码是否正确
- 验证码是否过期
- 网络连接是否正常
2. **页面加载慢**
- 检查网络状况
- 清除浏览器缓存
- 查看服务器日志
3. **数据不同步**
- 刷新页面
- 检查数据库连接
- 查看后端日志
### 日志查看
```bash
# SSH到测试服务器
ssh root@47.105.185.154
# 查看应用日志
tail -f /path/to/coolbuy/logs/application.log
# 查看错误日志
tail -f /path/to/coolbuy/logs/error.log
```
---
## 相关技能
- `coolbuy-paas` - 酷采3.0 SaaS租户端开发
- `coolbuy-platform` - 酷采3.0平台管理端
- `dev-test` - 软件测试技能
- `req` - 需求管理技能
- `siyuan` - 思源笔记(含酷采相关文档)
---
## 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 1.0.0 | 2026-01-21 | 初始版本创建酷采2.0独立技能 |
---
## 注意事项
⚠️ **重要提醒**:
1. 酷采2.0为遗留系统,主要用于参考和对比测试
2. 新功能开发应在酷采3.0 (coolbuy-paas) 中进行
3. 测试环境数据仅供测试使用,请勿在生产环境操作
4. 百丽、李宁等客户仍在使用此系统,测试时注意不要影响生产数据
5. 发现问题及时记录到 AI-Proj 系统中

View File

@@ -1,8 +0,0 @@
{
"name": "coolbuy-paas-plugin",
"description": "酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发以及酷采2.0系统对比测试。",
"version": "1.3.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,803 +0,0 @@
---
name: coolbuy-paas
description: 酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发以及酷采2.0系统对比测试。当用户提到酷采、coolbuy-paas、商品管理、产品管理、酷采2.0测试相关任务时自动激活。
---
# Coolbuy PaaS Skill
酷采3.0 SaaS 多租户业务系统,采用 Go + React 技术栈。
## 项目信息
| 项目 | 值 |
|------|-----|
| 本地路径 | `/Users/donglinlai/coding/qiudl/coolbuy-paas` |
| 工作区路径 | `/Users/donglinlai/workspace/coolbuy-paas` |
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-paas.git` |
| 主分支 | main |
| 技术栈 | Go (Gin+GORM) + React 18 (Vite+TypeScript+Ant Design) |
---
## 架构概览
```
coolbuy-paas/
├── erp-service/ # Go 后端 - ERP业务服务 (port 7091)
│ ├── api/ # API 定义 (go-zero)
│ ├── internal/
│ │ ├── product/ # 商品模块
│ │ ├── order/ # 订单模块
│ │ └── inventory/ # 库存模块
│ └── configs/
├── foundation-service/ # 基础服务 (port 7090)
├── auth-service/ # 认证服务 (port 7089)
├── ai-service/ # AI 服务 (port 7092) - AI Chat, Tool Calling
│ ├── api/
│ │ └── etc/ # 配置文件 (多环境)
│ └── services/
│ ├── chat_service.go # 对话服务
│ └── ai_ticket_reporter.go # AI 工单上报
├── gateway/ # API 网关
├── web/ # React 前端 - 租户端 (port 4000)
│ ├── src/
│ │ ├── services/ # API 服务
│ │ │ ├── aiChatApi.ts
│ │ │ └── chatSessionService.ts
│ │ └── components/AIChat/ # AI 聊天组件
│ └── .env.* # 环境配置
└── web-mall/ # React 前端 - 独立商城 (port 5174)
├── src/
│ ├── pages/ # 首页/分类/商品/购物车/结算/个人中心
│ ├── api/ # API 层(共享 erp-service
│ ├── auth/ # 认证(共享 auth-service JWT
│ ├── store/ # Zustand 状态管理
│ └── layouts/ # 商城布局(顶部导航,非侧边栏)
├── nginx.conf # 生产 Nginx 配置
└── Dockerfile # 多阶段构建
```
---
## 多环境配置
### 运行环境
| 环境 | 前端配置 | 后端配置 | 说明 |
|------|---------|---------|------|
| development | `.env.development` | `ai-api.yaml` | 本地开发 |
| staging | `.env.staging` | `ai-api.staging.yaml` | 预发布环境 |
| production | `.env.production` | `ai-api.production.yaml` | 生产环境 |
### 核心环境变量
| 变量 | 说明 | 开发环境示例 |
|------|------|------------|
| `VITE_AUTH_SERVICE_URL` | 认证服务 | `http://127.0.0.1:7089` |
| `VITE_FOUNDATION_SERVICE_URL` | 基础服务 | `http://127.0.0.1:7090` |
| `VITE_BUSINESS_SERVICE_URL` | ERP服务 | `http://127.0.0.1:7091` |
| `VITE_AI_SERVICE_URL` | AI服务 | `http://127.0.0.1:7092` |
| `VITE_AI_PROJ_URL` | ai-proj服务 | `http://127.0.0.1:8080` |
### Vite 代理配置 (vite.config.ts)
```typescript
proxy: {
'/api/v1/auth': { target: VITE_AUTH_SERVICE_URL },
'/api/v1/ai': { target: VITE_AI_SERVICE_URL }, // AI Chat
'/api/v1/chat': { target: VITE_AI_PROJ_URL }, // Chat Sessions
'/api/v1': { target: VITE_BUSINESS_SERVICE_URL }, // 默认路由
}
```
---
## AI 服务集成
### AI Chat 功能
| 端点 | 服务 | 说明 |
|------|------|------|
| `/api/v1/ai/chat/stream` | ai-service (7092) | 流式对话 |
| `/api/v1/ai/tools` | ai-service (7092) | 获取可用工具 |
| `/api/v1/chat/sessions` | ai-proj (8080) | 会话管理 |
| `/api/v1/ai-tickets` | ai-proj (8080) | AI 工单 |
### AI Chat 代码路径(重要)
**前端实际调用链**
```
useChat.ts
→ import * as aiChatService from '@/services/aiChatApi' ← 实际使用的文件!
→ aiChatApi.sendChatMessageStream()
→ aiChatApi.sendStreamingChatRequest() ← 用 fetch() 直接发 SSE 请求
```
**注意**`@/services/aiChatService.ts` 是遗留文件,**未被使用**。修改 AI Chat 前端逻辑时必须修改 `aiChatApi.ts`
**流式请求绕过 axios**`aiChatApi.ts` 使用原生 `fetch()` 发送 SSE 请求,不经过 `request.ts` 的 axios 拦截器。因此 `Authorization``X-Tenant-ID` 等 header 需要在 `fetch()` 中手动添加。
### AI Chat 认证链路
```
前端登录 → auth-service 返回 JWT (含 tenant_id, username, roles)
→ localStorage 存储 user_info + token
→ AI Chat 发送请求时:
1. getToken() 获取 JWT
2. getTenantIdFromContext() 获取 tenant_id
3. fetch() 携带 Authorization + X-Tenant-ID header
→ ai-service auth middleware 解析 JWT claims
→ Go context 注入 user_id, username, tenant_id, tenant_code, roles
→ buildUserIdentityContext(ctx) 提取并追加到 system prompt
→ AI 能回答"我的租户ID是什么"等问题
```
**关键文件**
| 文件 | 作用 |
|------|------|
| `web/src/services/aiChatApi.ts` | 前端 AI Chat API实际使用 |
| `web/src/hooks/useChat.ts` | Chat 状态管理 Hook |
| `ai-service/api/internal/middleware/auth_middleware.go` | JWT 解析,注入 context |
| `ai-service/services/chat_service.go` | 对话服务system prompt 注入 |
| `ai-service/services/context_builder.go` | 用户上下文构建 |
**JWT 密钥一致性**auth-service 和 ai-service 的 `JWT.AccessSecret` 必须一致,否则 ai-service 无法验证 token开发环境有 flexible parse 兜底)。
### AI 工单上报
ai-service 的错误会自动上报到 ai-proj 的 AI 工单系统:
```yaml
# ai-service/api/etc/ai-api.yaml
AITicketReporter:
Enabled: true
AiProjURL: "http://localhost:8080"
```
错误类型自动分类:
- `api_error` - API 调用错误
- `missing_tool` - 工具调用错误
- `timeout` - 超时错误
- `permission_denied` - 权限错误
---
## 酷采2.0 测试环境 (Legacy)
用于参考和对比酷采3.0开发。
### 访问信息
| 项目 | 值 |
|------|-----|
| 测试地址 | http://47.105.185.154:9300/login |
| 管理员账号 | 19090009801 |
| 密码 | 123456 |
| 客户账号 | 17761202551 / 202551 |
| 技术栈 | Vue 2 + Element UI + Java Spring |
### 主要功能模块
- 推广方案、销售管理、草稿单管理
- Y码直客、库存管理、货盘管理
- 协同仓、价格管理、资金管理
- 基础功能、数据看板、公告通知
- 起售数量设置、**产品管理**
### 源码位置
```
~/workspace/coolbuy-legacy/
├── cool_lining/module-provider/ # Java 后端
│ └── src/main/java/com/jzg/module/
│ ├── action/prd/ # 商品控制器
│ ├── dao/model/prd/ # 商品实体
│ └── manager/prd/ # 商品业务逻辑
└── ln_admin/ # Vue 前端
└── src/views2/module/prd/ # 商品管理页面
```
---
## Chrome DevTools 浏览器自动化
用于系统测试、截图、UI验证。
### 启动 Chrome 调试模式
```bash
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-debug
```
### 验证连接
```bash
curl http://127.0.0.1:9222/json/version
```
### 验证码处理规则
**重要**: 当访问需要验证码的系统时:
1. **不要**使用脚本截图方式获取验证码(验证码会快速过期)
2. **直接提醒用户**
- 请在浏览器中输入验证码
- 或请帮我点击登录按钮
3. 用户操作完成后再继续自动化流程
示例提示:
```
浏览器已打开登录页面,验证码需要手动输入。请在 Chrome 浏览器中:
1. 输入验证码
2. 点击登录按钮
完成后告诉我,我将继续后续操作。
```
### 常用 CDP 操作
```javascript
// 截图
Page.captureScreenshot({ format: 'png' })
// 导航
Page.navigate({ url: 'http://...' })
// 执行 JS
Runtime.evaluate({ expression: '...' })
// 点击元素
Runtime.evaluate({
expression: `document.querySelector('button').click()`
})
```
---
## 酷采3.0 PRD 参考
PRD 文档存储在 ai-proj 任务系统:
| 模块 | 任务ID | 文档名称 |
|------|--------|----------|
| 商品管理 | #4754 | 酷采3.0商品管理模块 |
| 商品基本信息 | #4770 | 商品基本信息管理模块PRD |
获取 PRD 文档:
```
mcp__ai-proj__get_task_document(taskId: 4770)
```
---
## 本地开发
### 启动服务
```bash
# ERP 服务 (port 7091)
cd erp-service && go run api/main.go -f configs/config.local.yaml
# AI 服务 (port 7092)
cd ai-service && go run api/ai.go -f api/etc/ai-api.yaml
# 租户端前端 (port 4000)
cd web && npm run dev
# 独立商城前端 (port 5174)
cd web-mall && npm run dev
```
### 依赖服务
| 服务 | 端口 | 说明 |
|------|------|------|
| PostgreSQL | 5432 | 本地数据库 |
| Redis | 6379 | 缓存 |
| ai-proj | 8080 | AI 项目管理(可选,用于 Chat Sessions |
### 本地数据库
| 项目 | 值 |
|------|-----|
| 类型 | PostgreSQL |
| Database | paas_foundation |
| User | coolbuy-dev |
| Password | (空) |
### 远程数据库(生产参考)
| 项目 | 值 |
|------|-----|
| Host | 192.144.137.14 |
| Database | coolbuy_paas |
| User | platform |
| Password | Zhiyuncai2025~ |
### 数据库管理工具 - TablePlus
**推荐工具**: TablePlus - macOS 原生数据库 GUI 客户端,支持 PostgreSQL/MySQL/Redis 等。
#### 安装 TablePlus
```bash
# 使用 Homebrew 安装
brew install --cask tableplus
# 启动 TablePlus
open -a TablePlus
```
#### 自动配置数据库连接
TablePlus 的连接配置存储在 `~/Library/Application Support/com.tinyapp.TablePlus/Data/Connections.plist`
**快速配置脚本**(已包含本地和远程连接):
```bash
# 1. 关闭 TablePlus如果正在运行
killall TablePlus 2>/dev/null || true
# 2. 备份现有配置
cp ~/Library/Application\ Support/com.tinyapp.TablePlus/Data/Connections.plist \
~/Library/Application\ Support/com.tinyapp.TablePlus/Data/Connections.plist.backup
# 3. 编辑配置文件添加连接(参考下方 plist 格式)
# 4. 重启 TablePlus
open -a TablePlus
```
**连接配置示例**plist 格式):
```xml
<!-- 本地开发环境连接 -->
<dict>
<key>ConnectionName</key>
<string>Coolbuy PaaS - Local (开发环境)</string>
<key>DatabaseHost</key>
<string>localhost</string>
<key>DatabasePort</key>
<string>5432</string>
<key>DatabaseName</key>
<string>paas_foundation</string>
<key>DatabaseUser</key>
<string>coolbuy-dev</string>
<key>DatabasePasswordMode</key>
<integer>0</integer>
<key>Driver</key>
<string>PostgreSQL</string>
<key>Enviroment</key>
<string>local</string>
<key>statusColor</key>
<string>#3B82F6</string> <!-- 蓝色标识开发环境 -->
</dict>
```
#### 手动配置步骤
如果自动配置失败,可以手动在 TablePlus GUI 中添加:
1. 打开 TablePlus → 点击 "Create a new connection"
2. 选择 PostgreSQL
3. 填写连接信息:
**本地连接**
- Name: `Coolbuy PaaS - Local (开发环境)`
- Host: `localhost`
- Port: `5432`
- Database: `paas_foundation`
- User: `coolbuy-dev`
- Password: (留空)
- Color: 蓝色
**生产连接**
- Name: `Coolbuy PaaS - Production (生产环境)`
- Host: `192.144.137.14`
- Port: `5432`
- Database: `coolbuy_paas`
- User: `platform`
- Password: `Zhiyuncai2025~`
- Color: 红色(警示)
- **重要**:勾选 "Read-only mode" 防止误操作
#### 验证连接
连接成功后运行以下 SQL 验证:
```sql
-- 检查数据库版本
SELECT version();
-- 查看所有表
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;
-- 查看库存预占记录
SELECT * FROM biz_inventory_reservations
ORDER BY created_at DESC
LIMIT 10;
-- 查看活跃租户
SELECT id, name, code, status
FROM fnd_tenants
WHERE status = 1 AND deleted_at IS NULL;
```
#### TablePlus 常用快捷键
| 快捷键 | 功能 |
|--------|------|
| `Cmd + N` | 新建连接 |
| `Cmd + T` | 新建 Tab |
| `Cmd + K` | 连接列表 |
| `Cmd + R` | 刷新 |
| `Cmd + /` | 注释/取消注释 SQL |
| `Cmd + Enter` | 执行 SQL |
| `Cmd + Shift + E` | 导出数据 |
#### 安全提示
⚠️ **生产数据库操作注意事项**
1. **必须**启用 "Read-only mode"(连接设置中)
2. **避免**直接执行 UPDATE/DELETE 操作
3. **建议**使用事务测试:`BEGIN; ... ROLLBACK;`
4. **慎用**批量操作
5. **定期**备份重要数据
---
## 独立商城 (web-mall)
独立 B2B 商城前端,与租户端 `web/` 并行运行,共享后端 API。
### 定位对比
| 维度 | 租户端 (web/) | 独立商城 (web-mall/) |
|------|--------------|---------------------|
| 定位 | 内部采购经理 | 终端采购用户 |
| 布局 | ERP 侧边栏 | 商城顶部导航 |
| 选品 | 表单弹窗选择 | 浏览分类/搜索+加购 |
| 下单 | ERP 表单模式 | 购物车→结算 |
### 页面结构
| 页面 | 路径 | 说明 |
|------|------|------|
| 首页 | `/` | 推荐商品、分类入口 |
| 商品列表 | `/products` | 搜索、筛选、排序 |
| 商品详情 | `/products/:id` | SKU 选择、加入购物车 |
| 购物车 | `/cart` | 购物车管理 |
| 结算 | `/checkout` | 提交订单 |
| 个人中心 | `/user` | 订单列表、订单详情 |
### Vite 代理配置 (web-mall/vite.config.ts)
```typescript
proxy: {
'/api/v1/auth': { target: 'http://localhost:7089' }, // auth-service
'/api': { target: 'http://localhost:7091' }, // erp-service
}
```
### Docker 部署
| 环境 | 端口 | 镜像 |
|------|------|------|
| 开发 | 5174 (Vite) | 本地 `npm run dev` |
| 生产 | 8889:80 | `saltthing123/coolbuy-paas-web-mall` |
### 需求来源
REQ-20260214-0001采购单双模式PRD 任务 #5874
---
## 商品模块开发
### 前端页面结构
```
web/src/pages/Product/
├── ProductList/ # 商品列表页
│ ├── index.tsx
│ ├── columns.tsx # 表格列配置
│ └── searchFields.ts # 搜索表单配置
├── ProductForm/ # 商品表单页(新增/编辑)
│ ├── index.tsx
│ ├── BasicInfo.tsx # 基本信息
│ ├── ImageUpload.tsx # 图片上传
│ └── PriceInfo.tsx # 价格信息
└── ProductDetail/ # 商品详情弹窗
└── index.tsx
```
### 后端模块结构
```
erp-service/internal/product/
├── model/
│ ├── spu.go # SPU 模型
│ └── sku.go # SKU 模型
├── biz/
│ ├── spu.go # SPU 业务逻辑
│ └── sku.go # SKU 业务逻辑
├── store/
│ ├── spu.go # SPU 数据访问
│ └── sku.go # SKU 数据访问
└── handler/
└── spu_handler.go # HTTP 处理器
```
### API 端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/v1/products | 商品列表 |
| GET | /api/v1/products/:id | 商品详情 |
| POST | /api/v1/products | 创建商品 |
| PUT | /api/v1/products/:id | 更新商品 |
| DELETE | /api/v1/products/:id | 删除商品 |
| PATCH | /api/v1/products/:id/status | 上架/下架 |
---
## 研发经验与开发策略
> 本章总结了酷采 3.0 开发过程中积累的研发方法论,指导 Claude Code 高效完成业务模块开发。
### 系统定位
酷采 3.0 是酷采 2.0 的**重构升级版本**,不是 1:1 复刻。核心策略:**用 2.0 的业务逻辑 + 3.0 的代码模式**。
### 两代系统架构对比
| 维度 | 酷采 2.0 (coolbuy-legacy) | 酷采 3.0 (coolbuy-paas) |
|------|--------------------------|------------------------|
| 后端 | Java Spring Boot 单体 | Go 微服务 (5 个独立服务) |
| 前端 | Vue 2 + Element UI | React 18 + Ant Design 5 + Vite |
| 数据库 | MySQL + MyBatis | PostgreSQL + GORM |
| 认证 | Shiro | JWT + Redis 黑名单 |
| 多租户 | company_id 字段 | 原生 SaaS tenant 隔离 |
| 权限 | 多表关联 RBAC | 权限引擎 + 数据权限 |
### 业务模块完成度
| 业务模块 | 2.0 页面 | 3.0 后端 | 3.0 前端 | 优先级 |
|----------|---------|---------|---------|--------|
| 系统管理 (用户/角色/权限/组织) | 9 页 | 95% | 95% | - 已完成 |
| 商品管理 (SPU/SKU/分类/品牌) | 18 页 | 90% | 85% | P1 补齐 |
| 订单管理 (销售/采购/退货/审批) | 22 页 | 85% | 70% | **P0** |
| 仓储管理 (入库/出库/库存/物流) | 6 页 | 70% | 50% | P0 |
| 客户管理 (等级/销售员/供应商) | 17 页 | 60% | 50% | P0 |
| 财务结算 (账户/流水/结算单) | 3 页 | 40% | 30% | P1 |
| 报备授权 (项目/渠道/审核) | 20+ 页 | 20% | 10% | P2 评估 |
| 分销网络 (3.0 新增) | 无 | 75% | 75% | P1 |
| 购物车 & 商城 (web-mall) | 无 | 80% | 80% | P1 |
### 三层工作流 (需求 → 代码)
```
第一层: 需求 → PRD (/req-prd skill)
输入: 2.0 对应页面 + 业务规则描述
输出: PRD 文档 + 原型 HTML (dev-plans/prototypes/)
工具: /req create → /req doc
第二层: PRD → 开发计划 (/req-dev skill)
输入: PRD + 当前 3.0 代码库分析
输出: 文件级开发任务拆分
工具: /req doc → ai-proj tasks
第三层: 任务 → 代码 (/dev-coding skill)
输入: 开发计划 + 参考模块代码
输出: 可运行的前后端代码
工具: Claude Code 直接编码
```
### 模块复制模式 (核心开发方法)
每个新业务模块参照已有成熟模块的代码模式生成:
```
参考模块 (User) 目标模块 (Order)
──────────────────── ────────────────────
api/types.ts (追加接口) → OrderQueryParams, Order, OrderItem...
api/order.ts (新建) → getOrderList, getOrderById, createOrder...
pages/OrderList.tsx → 统计卡片 + 搜索表单 + 工具栏 + 表格
pages/OrderDetail.tsx → 头部信息 + 多 Tab (基本信息/明细/日志)
pages/OrderForm.tsx → Modal 表单 (新增/编辑)
router/tenantRoutes.tsx → 追加路由注册
```
**关键约定**(必须遵循):
- API 字段使用 `snake_case` (如 `order_status`, `created_at`)
- 响应数据解包:`res.data?.data || res.data`(双层嵌套兼容)
- 分页参数:`{ current, pageSize }` → 后端映射为 `{ page, page_size }`
- 时间格式化:`dayjs(v).format('YYYY-MM-DD HH:mm:ss')`
- 枚举渲染:`<Tag color={colorMap[value]}>{labelMap[value]}</Tag>`
- 表格滚动:`scroll={{ x: 列宽总和 }}`
- 权限控制:`<Permission permission="module:resource:action">` 包裹按钮
### 单模块开发 SOP
| 步骤 | 产出 | 预估时间 |
|------|------|---------|
| 1. 类型定义 | `types.ts` 追加接口/枚举 | 10 min |
| 2. API 层 | `api/xxx.ts` (CRUD + 业务接口) | 10 min |
| 3. 列表页 | `XxxList.tsx` (搜索+表格+工具栏+统计) | 20 min |
| 4. 详情页 | `XxxDetail.tsx` (多 Tab 信息展示) | 20 min |
| 5. 表单页 | `XxxForm.tsx` (新增/编辑 Modal) | 15 min |
| 6. 路由注册 | `tenantRoutes.tsx` 追加 lazy import | 5 min |
| 7. 联调修复 | 对接实际 API 后的字段/格式调整 | 30 min |
**单模块总计约 2 小时**,相比纯手写 2-3 天。
### 参考 2.0 代码的方法
开发新模块时Claude 应按以下顺序获取业务知识:
```bash
# 1. 读 2.0 前端路由 → 了解页面结构和导航
~/workspace/coolbuy-paas/coolbuy-legacy/ln_admin/src/router/<module>_routers.js
# 2. 读 2.0 前端页面 → 了解字段、搜索条件、操作按钮
~/workspace/coolbuy-paas/coolbuy-legacy/ln_admin/src/views/module/<module>/
# 3. 读 2.0 后端 Manager → 了解业务规则和校验逻辑
~/workspace/coolbuy-paas/coolbuy-legacy/cool_belle/module-provider/src/main/java/com/jzg/module/manager/<module>/
# 4. 读 2.0 数据模型 → 了解表结构和字段
~/workspace/coolbuy-paas/coolbuy-legacy/cool_belle/module-provider/src/main/java/com/jzg/module/dao/model/<module>/
# 5. 读 3.0 已有参考模块 → 了解代码模式
~/coding/qiudl/coolbuy-paas/web/src/modules/foundation/pages/User/
~/coding/qiudl/coolbuy-paas/erp-service/internal/<module>/
```
### 联调经验总结
以下是已验证的联调常见问题和修复模式:
| 问题 | 原因 | 修复模式 |
|------|------|---------|
| 表格空数据 | API 响应格式 `{list,total}` vs `data[]` | `const d = res.data?.data \|\| res.data; setList(d?.list \|\| d)` |
| 按钮不显示 | Permission 组件依赖 `hasPermission()` | 确保 `isSuperAdmin()` 包含 `admin` 角色 |
| 时间显示原始 ISO | 缺少 dayjs 格式化 | 统一用 `formatTime()` helper |
| 统计接口 404 | 后端未部署 | `catch {}` 静默处理,不弹错误 |
| "加载更多"覆盖数据 | setState 替换而非追加 | 加 `append` 参数:`prev => append ? [...prev, ...newList] : newList` |
| TreeSelect undefined | 组织树数据映射缺字段 | 确保 `convertTreeData` 映射 `title/value/key` |
| TS 类型不匹配 | API 返回结构与类型定义不一致 | 用 `: any` 断言,后续补齐类型 |
| antd deprecated | v5.26 废弃 API | `bordered={false}``variant="borderless"` |
### 分阶段推进计划
**Phase 1 — 核心交易闭环** (决定系统可用性)
- 订单管理:后端 handler 已有 507 行,前端 20 页面待联调
- 客户管理:基础 CRUD + 客户等级 + 销售员体系
- 仓储管理:入库/出库/库存查询
**Phase 2 — 商品完善 + 财务**
- 商品模块补齐:组合方案、现货加标、生效时间管理
- 财务结算:账户管理、流水查询、结算单
**Phase 3 — 运营支撑**
- 报备/授权模块评估后选择性迁移2.0 有 20+ 页面)
- 报表/数据分析
- 小程序/H5 商城增强
### 2.0 订单模块业务知识 (已梳理)
#### 订单状态机
```
创建 → 待支付(01) → 已支付(02) → 已发货(03) → 已收货(04) → 已完成(10)
↘ 已取消(05) ↘ 已退款(08)
待审核(06) 已关闭(07)
待出库(11)
```
#### 支付方式
| 代码 | 方式 | 业务规则 |
|------|------|---------|
| 01 | 预存款 | 扣减预付账户余额,记 BizFundLog |
| 02 | 授信 | 扣减信用额度,需审核 |
| 11 | 银行转账 | 自动生成付款单(MallPay)+收款单(MallReceive) |
| 13 | 货到付款 | 无需预付 |
#### 退款类型
| 类型 | 说明 | 校验规则 |
|------|------|---------|
| 整单退(01) | 全额退款 | 同一用户/订单只能有一个待处理退款 |
| 按数量退(02) | 部分数量退 | 检查可退数量 |
| 按物品退(03) | 指定商品退 | 逐项检查 |
| 退运费(04) | 仅退运费 | 运费大于 0 |
#### 用户角色与操作权限
| userType | 身份 | 可执行操作 |
|----------|------|-----------|
| 01 | 平台管理员 | 直接取消、审核、改价、所有操作 |
| 02 | 供应商 | 申请退款、查看、发货 |
| 03 | 客户 | 申请退款、查看、收货确认 |
| 04 | 前端用户 | 下单、查看、基础操作 |
### 3.0 订单模块现状 (已梳理)
#### 后端 API (erp-service)
```
GET /api/v1/orders # 列表 (支持 OrderNo/Status/Date/Amount 筛选)
GET /api/v1/orders/:id # 详情 (含 items)
POST /api/v1/orders # 创建 (含采购权限/区域/MOQ 校验)
PUT /api/v1/orders/:id # 更新 (仅草稿)
DELETE /api/v1/orders/:id # 删除 (仅草稿)
POST /api/v1/orders/:id/submit-approval # 提交审批
POST /api/v1/orders/:id/approve # 审批通过/拒绝
POST /api/v1/orders/:id/confirm-payment # 确认付款
POST /api/v1/orders/:id/ship # 发货
POST /api/v1/orders/:id/confirm-delivery # 确认收货
POST /api/v1/orders/:id/complete # 完成
POST /api/v1/orders/:id/cancel # 取消
POST /api/v1/orders/:id/refund # 退款
GET /api/v1/orders/:id/status-logs # 状态变更日志
GET /api/v1/orders/:id/approval-history # 审批历史
GET /api/v1/orders/statistics/* # 统计 (6 个子接口)
```
#### 3.0 订单状态 (14 态,比 2.0 更细)
```
Draft(10) → PendingApproval(20) → Approved(29) → PendingPayment(30) → Paid(39)
→ PendingShipment(40) → PartialShipped(45) → Shipped(49)
→ PartialDelivered(55) → Delivered(59) → Completed(90)
→ Rejected(92) / Cancelled(95) / Refunded(97)
```
#### 前端已有页面 (20 个)
```
/order/sales - SalesOrderList
/order/sales/add - SalesOrderForm
/order/business - BusinessOrderList
/order/purchase - PurchaseOrderList
/order/purchase/add - PurchaseOrderForm
/order/purchase/:id - PurchaseOrderDetail
/order/pending-approval - PendingApprovalList
/order/return - ReturnOrderList
/order/return/create - CreateReturnOrder
/order/return/:id - ReturnOrderDetail
/order/statistics - PurchaseOrderStatistics
/checkout - CheckoutPage
```
---
## 相关技能
- `coolbuy-platform` - 平台管理端开发
- `coolbuy-legacy` - 酷采 2.0 测试与参考
- `dev-coding` - 软件编码开发
- `dev-arch` - 软件架构设计
- `dev-test` - 软件测试
- `req-prd` - 产品需求文档编写
- `req-dev` - 需求开发计划编写
- `siyuan` - 思源笔记(含酷采相关文档)
---
## 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 1.4.0 | 2026-02-25 | 新增研发经验与开发策略章节:两代系统对比、模块完成度、三层工作流、模块复制模式、联调经验、订单模块业务梳理 |
| 1.3.0 | 2026-02-14 | 新增数据库管理工具章节TablePlus 安装配置、自动配置脚本、连接验证、安全提示 |
| 1.2.0 | 2026-02-14 | 新增 web-mall 独立商城模块(架构、页面、代理、部署端口) |
| 1.1.0 | 2026-02-13 | 新增 AI Chat 代码路径、认证链路、关键文件说明;记录 aiChatApi vs aiChatService 陷阱 |
| 1.0.0 | 2026-01-10 | 初始版本添加酷采2.0测试环境和浏览器自动化指南 |

View File

@@ -1,8 +0,0 @@
{
"name": "coolbuy-platform-plugin",
"description": "Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。",
"version": "1.0.9",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,338 +0,0 @@
---
name: coolbuy-platform
description: Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。当用户提到 coolbuy-platform、平台端、租户管理后台相关任务时自动激活。
---
# Coolbuy Platform Skill
Coolbuy SaaS 平台管理端,用于管理所有租户、功能授权、计费、运营分析等。
## 项目信息
| 项目 | 值 |
|------|-----|
| 本地路径 | `/Users/donglinlai/coding/qiudl/coolbuy-platform` |
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-platform.git` |
| 主分支 | main |
---
## 架构概览
```
coolbuy-platform/
├── service/ # Go 后端 (Gin + GORM)
│ ├── cmd/ # 入口 main.go
│ ├── internal/admin/ # 核心业务
│ │ ├── api/ # HTTP handlers
│ │ ├── biz/ # 业务逻辑
│ │ ├── store/ # 数据访问
│ │ ├── model/ # 领域模型
│ │ └── middleware/ # 中间件
│ └── configs/ # 配置文件
└── web/ # React 前端 (Vite + TypeScript)
├── src/
│ ├── api/ # API 客户端
│ ├── components/ # 组件
│ ├── pages/ # 页面
│ ├── stores/ # Zustand 状态
│ └── locales/ # i18n 翻译
└── dist/
```
---
## 部署环境
### 生产服务器
| 服务 | 地址 | 端口 | 容器名 |
|------|------|------|--------|
| 前端 | http://platform.pipexerp.com | 4999 | coolbuy-platform-web |
| 后端 | http://39.105.150.219 | 7090 | coolbuy-platform-service |
| Auth | http://39.105.150.219 | 7089 | coolbuy-auth-service |
### 服务器信息
| 项目 | 值 |
|------|-----|
| IP | 39.105.150.219 |
| 用户 | root |
| SSH 密钥 | ~/.ssh/coolbuy3.pem |
| 操作系统 | Ubuntu 24.04 |
### 数据库
| 项目 | 值 |
|------|-----|
| 类型 | PostgreSQL 16 |
| Host | 172.18.0.1 (Docker 网关) |
| Port | 5432 |
| Database | paas_platform |
| User | platform |
| Password | Coolbuy2025~ |
### Docker Registry
| 项目 | 值 |
|------|-----|
| Registry | Docker Hub |
| 账号 | saltthing123 |
| 前端镜像 | saltthing123/coolbuy-platform-web |
| 后端镜像 | saltthing123/coolbuy-platform-service |
| Auth镜像 | saltthing123/coolbuy-auth-service |
---
## 快速部署命令
### 部署前端
```bash
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
# 1. 构建
npx vite build
# 2. 打包 Docker 镜像
~/.orbstack/bin/docker build --platform linux/amd64 \
-t saltthing123/coolbuy-platform-web:<version> \
-t saltthing123/coolbuy-platform-web:latest .
# 3. 推送镜像
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-web:<version>
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-web:latest
# 4. 部署到服务器
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "
docker pull saltthing123/coolbuy-platform-web:<version> && \
docker stop coolbuy-platform-web && \
docker rm coolbuy-platform-web && \
docker run -d --name coolbuy-platform-web \
--restart unless-stopped \
-p 4999:80 \
saltthing123/coolbuy-platform-web:<version>
"
```
### 部署后端
```bash
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/service
# 1. 构建二进制
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o coolbuy-platform-service cmd/main.go
# 2. 打包 Docker 镜像
~/.orbstack/bin/docker build --platform linux/amd64 \
-t saltthing123/coolbuy-platform-service:<version> \
-t saltthing123/coolbuy-platform-service:latest .
# 3. 推送镜像
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-service:<version>
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-service:latest
# 4. 部署到服务器
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "
docker pull saltthing123/coolbuy-platform-service:<version> && \
docker stop coolbuy-platform-service && \
docker rm coolbuy-platform-service && \
docker run -d --name coolbuy-platform-service \
--restart unless-stopped \
-p 7090:7090 \
-v /data/coolbuy-platform/logs:/app/logs \
-v /data/coolbuy-platform/storage:/app/storage \
-v /data/coolbuy-platform/configs:/app/configs:ro \
-e TZ=Asia/Shanghai \
saltthing123/coolbuy-platform-service:<version> \
--config configs/config.prod.yaml
"
```
---
## 本地开发
### 启动后端
```bash
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/service
go run cmd/main.go -config configs/config-dev.yaml
```
### 启动前端
```bash
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
npm run dev
```
### 构建测试
```bash
# 后端测试
cd service && go test -v ./...
# 前端测试
cd web && npm run test
```
---
## 翻译管理
### 翻译文件位置
- 简体中文: `web/src/locales/zh-CN.ts`
- 繁体中文: `web/src/locales/zh-TW.ts`
### 检查翻译缺失
```bash
# 查找组件中使用的翻译 key
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
grep -r "t(['\"]" src/components/ src/pages/ | grep -oE "t\(['\"][^'\"]+['\"]" | sort | uniq
```
### 翻译 key 命名规范
| 模块 | 前缀 | 示例 |
|------|------|------|
| 租户管理 | tenant.* | tenant.form.nameRequired |
| 用户管理 | user.* | user.createSuccess |
| 角色管理 | role.* | role.permissionAssigned |
| 菜单管理 | menu.* | menu.iconRequired |
| 通知中心 | notification.* | notification.markAllRead |
---
## API 端点
### 认证 (Auth Service - 7089)
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/v1/auth/login | 登录 |
| POST | /api/v1/auth/logout | 登出 |
| POST | /api/v1/auth/refresh | 刷新 Token |
### 平台管理 (Platform Service - 7090)
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/v1/admin/tenants | 租户列表 |
| POST | /api/v1/admin/tenants | 创建租户 |
| GET | /api/v1/admin/users | 用户列表 |
| GET | /api/v1/admin/roles | 角色列表 |
| GET | /api/v1/admin/menus | 菜单列表 |
| GET | /api/v1/admin/dashboard/overview | 仪表盘概览 |
### 健康检查
| 路径 | 说明 |
|------|------|
| /health | 基础健康检查 |
| /health/detailed | 详细状态 |
| /readiness | K8s 就绪探针 |
| /liveness | K8s 存活探针 |
---
## 数据库迁移
### 自动迁移
配置 `migration.auto: true` 时,服务启动自动运行迁移。
### 手动迁移
```bash
psql -h 172.18.0.1 -U platform -d paas_platform \
-f service/configs/migrations/001_create_platform_admin_tables.sql
```
---
## 常见问题
### 1. 翻译 key 不显示
组件使用的 key 与 locale 定义不匹配。检查:
- 组件使用 `t('tenant.domainConfig.*')` 但 locale 定义为 `tenant.domain.*`
- 需要添加别名命名空间
### 2. SSE 连接错误
通过 Cloudflare Tunnel 访问时 SSE 长连接会中断,属于已知问题,会自动重连。
### 3. Docker 构建失败
确保使用 OrbStack 的 docker`~/.orbstack/bin/docker`
### 4. 数据库连接失败
Docker 网关 IP 是 `172.18.0.1`,不是默认的 `172.17.0.1`
---
## 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 1.0.9 | 2026-01-05 | 修复租户管理全部翻译缺失 |
| 1.0.8 | 2026-01-04 | 修复租户列表翻译 |
| 1.0.7 | 2026-01-04 | 修复租户表单翻译 |
| 1.0.0 | 2026-01-03 | 初始版本 |
---
## SSH 快捷命令
```bash
# 连接服务器
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219
# 查看容器状态
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker ps | grep coolbuy"
# 查看后端日志
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker logs -f coolbuy-platform-service --tail 100"
# 查看前端日志
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker logs -f coolbuy-platform-web --tail 100"
# 健康检查
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "curl -s http://localhost:7090/health"
```
---
## 创建租户
```bash
# 通过 API 创建租户
curl -X POST http://39.105.150.219:7090/api/v1/admin/tenants \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "租户名称",
"code": "tenant_code",
"contact": "联系人",
"phone": "13800138000",
"email": "contact@example.com",
"user_limit": 50,
"storage_limit": 10,
"schema_type": "shared",
"admin_username": "tenantadmin",
"admin_real_name": "管理员姓名",
"status": "normal"
}'
```
---
## 相关技能
- `ops-tools` - DevOps 运维工具,包含 Jenkins/Gitea 管理
- `dev-coding` - 软件编码开发
- `coolbuy-paas` - 租户端系统(待创建)

View File

@@ -1,8 +0,0 @@
{
"name": "enjoysa-deploy-plugin",
"description": "EnjoySA 项目部署到新加坡服务器",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,113 +0,0 @@
# EnjoySA 部署技能
## 触发条件
当用户提到以下内容时自动激活:
- enjoysa 部署
- 部署到新加坡
- deploy enjoysa
---
## 项目信息
| 项目 | 值 |
|------|-----|
| 本地路径 | `/Users/donglinlai/coding/qiudl/enjoysa` |
| Git 仓库 | `https://gitea.pipexerp.com/qiudl/enjoysa.git` |
| 主分支 | main |
---
## 服务器信息
| 项目 | 值 |
|------|-----|
| 服务器 | singapore (43.134.28.147) |
| 用户 | ubuntu |
| SSH 密钥 | ~/.ssh/singpore.pem |
| 部署路径 | /opt/enjoysa |
| 访问地址 | http://43.134.28.147:6066 |
| Web 服务 | Nginx (端口 6066) |
---
## 快速部署
执行部署脚本:
```bash
./scripts/deploy.sh
```
---
## 手动部署步骤
### 1. 构建
```bash
cd web && npm run build
```
### 2. 上传
```bash
scp -r web/dist/* singapore:/opt/enjoysa/
```
### 3. 验证
```bash
ssh singapore "curl -s -o /dev/null -w '%{http_code}' http://localhost:6066/"
```
---
## 常用运维命令
```bash
# 查看 Nginx 状态
ssh singapore "sudo systemctl status nginx"
# 重载 Nginx 配置
ssh singapore "sudo nginx -t && sudo systemctl reload nginx"
# 查看部署目录
ssh singapore "ls -la /opt/enjoysa/"
# 查看 Nginx 访问日志
ssh singapore "sudo tail -f /var/log/nginx/access.log"
# 查看错误日志
ssh singapore "sudo tail -f /var/log/nginx/error.log"
```
---
## Nginx 配置
配置文件: `/etc/nginx/sites-available/enjoysa`
```nginx
server {
listen 6066;
listen [::]:6066;
server_name _;
root /opt/enjoysa;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
```
---
## 注意事项
1. 腾讯云安全组需开放 6066 端口
2. SPA 应用使用 `try_files` 支持前端路由
3. 静态资源设置长期缓存

View File

@@ -1,8 +0,0 @@
{
"name": "enjoysa-plugin",
"description": "Plugin for enjoysa",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,210 +0,0 @@
---
name: enjoysa
description: EnjoySA 畅游南澳旅游平台开发。用于前端页面开发、组件开发、i18n国际化。当用户提到 enjoysa、畅游南澳、旅游平台、供应商后台相关任务时自动激活。
---
# EnjoySA 开发技能
畅游南澳旅游平台,面向 C 端游客和 B 端供应商的在线旅游服务系统。
## 项目信息
| 项目 | 值 |
|------|-----|
| 本地路径 | `/Users/donglinlai/coding/qiudl/enjoysa` |
| Git 仓库 | `https://gitea.pipexerp.com/qiudl/enjoysa.git` |
| 主分支 | main |
| 技术栈 | Vite + React 18 + TypeScript + CSS Modules |
| 部署服务器 | singapore (43.134.28.147:6066) |
| 访问地址 | http://43.134.28.147:6066 |
---
## 架构概览
```
enjoysa/
├── web/ # React 前端
│ ├── src/
│ │ ├── components/ # 通用组件
│ │ │ ├── Common/ # Header, Footer, LanguageSwitcher
│ │ │ ├── Auth/ # LoginForm, RegisterForm
│ │ │ └── Supplier/ # SupplierLoginForm, SupplierRegisterForm
│ │ ├── pages/ # 页面组件
│ │ │ ├── LoginPage/ # C端用户登录
│ │ │ ├── SupplierLoginPage/# B端供应商登录
│ │ │ ├── AdminLoginPage/ # 平台管理员登录
│ │ │ ├── TermsPage/ # 服务条款
│ │ │ ├── PrivacyPage/ # 隐私政策
│ │ │ └── Supplier/ # 供应商后台模块
│ │ ├── i18n/ # 国际化
│ │ │ └── locales/ # 翻译文件
│ │ │ ├── zh-CN.json
│ │ │ └── en-US.json
│ │ └── types/ # 类型定义
│ ├── scripts/ # 部署脚本
│ └── dist/ # 构建产物
├── backend/ # Go 后端 (规划中)
└── docs/ # 文档
```
---
## 页面路由
### C 端 (游客)
| 路由 | 页面 | 说明 |
|------|------|------|
| `/` | HomePage | 首页 |
| `/login` | LoginPage | 用户登录/注册 |
| `/terms` | TermsPage | 服务条款 |
| `/privacy` | PrivacyPage | 隐私政策 |
### B 端 (供应商)
| 路由 | 页面 | 说明 |
|------|------|------|
| `/supplier/login` | SupplierLoginPage | 供应商登录 |
| `/supplier/register` | SupplierRegisterPage | 供应商入驻申请 |
| `/supplier` | SupplierDashboard | 供应商仪表盘 |
| `/supplier/products` | SupplierProducts | 产品管理 |
| `/supplier/orders` | SupplierOrders | 订单处理 |
| `/supplier/finance` | SupplierFinance | 财务结算 |
### 管理端
| 路由 | 页面 | 说明 |
|------|------|------|
| `/admin/login` | AdminLoginPage | 管理员登录 |
---
## i18n 国际化
### 翻译文件位置
```
web/src/i18n/locales/
├── zh-CN.json # 简体中文
└── en-US.json # 英文
```
### 命名空间规范
| 命名空间 | 用途 | 示例 |
|---------|------|------|
| `brand.*` | 品牌信息 | brand.name, brand.tagline |
| `auth.*` | 登录注册 | auth.loginTitle, auth.emailPlaceholder |
| `terms.*` | 服务条款 | terms.title, terms.sections.* |
| `privacy.*` | 隐私政策 | privacy.title, privacy.sections.* |
| `supplier.*` | 供应商模块 | supplier.login.*, supplier.dashboard.* |
| `admin.*` | 管理员模块 | admin.login.*, admin.dashboard.* |
| `common.*` | 通用文本 | common.submit, common.cancel |
| `footer.*` | 页脚 | footer.supplierEntry, footer.copyright |
### 添加新翻译步骤
1.`zh-CN.json``en-US.json` 中同时添加新 key
2. 使用 `useTranslation()` hook 获取 `t` 函数
3. 使用 `t('namespace.key')` 获取翻译文本
```tsx
import { useTranslation } from 'react-i18next';
const MyComponent = () => {
const { t } = useTranslation();
return <h1>{t('brand.name')}</h1>;
};
```
### 注意事项
- **禁止硬编码中文/英文**,所有用户可见文本必须使用 i18n
- 长文本内容(如条款、政策)使用 `\n` 分段
- JSON 中避免使用中文引号 `""` `''`,使用 `「」` 或英文引号
---
## 组件规范
### Common 组件
| 组件 | 用途 | 文件 |
|------|------|------|
| Header | 顶部导航栏 | `components/Common/Header/` |
| Footer | 页脚(含供应商入口) | `components/Common/Footer/` |
| LanguageSwitcher | 语言切换器 | `components/Common/LanguageSwitcher/` |
### Auth 组件
| 组件 | 用途 | 文件 |
|------|------|------|
| LoginForm | C端登录表单 | `components/Auth/LoginForm/` |
| RegisterForm | C端注册表单 | `components/Auth/RegisterForm/` |
### Supplier 组件
| 组件 | 用途 | 文件 |
|------|------|------|
| SupplierLoginForm | 供应商登录表单 | `components/Supplier/SupplierLoginForm/` |
| SupplierRegisterForm | 供应商入驻申请表单 | `components/Supplier/SupplierRegisterForm/` |
---
## 本地开发
### 启动前端
```bash
cd /Users/donglinlai/coding/qiudl/enjoysa/web
npm install
npm run dev
```
### 构建
```bash
npm run build
```
### 部署
```bash
./scripts/deploy.sh
```
或手动部署:
```bash
scp -r web/dist/* singapore:/opt/enjoysa/
```
---
## 供应商类型
系统支持以下供应商类型:
| 类型 | 说明 |
|------|------|
| travel_agency | 旅行社 |
| hotel | 酒店 |
| attraction | 景区 |
| restaurant | 餐厅 |
| car_rental | 租车公司 |
---
## 相关技能
- `enjoysa-deploy` - 部署到新加坡服务器
- `frontend-design` - 前端界面设计
- `dev-coding` - 软件编码开发
---
## 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 1.0.0 | 2026-01-31 | 初始版本包含项目结构、页面路由、i18n规范 |

View File

@@ -1,8 +0,0 @@
{
"name": "executing-plans-plugin",
"description": "Plugin for executing-plans",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

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

View File

@@ -1,8 +0,0 @@
{
"name": "req-commands-plugin",
"description": "需求命令详细参考。含撰写命令new/draft/edit/check/split/history/compare和流程命令submit/review/phase/next/deploy/done。",
"version": "2.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,436 +0,0 @@
---
name: req-commands
description: 需求命令详细参考。当需要查看 /req 命令的详细用法、参数、示例时使用。
---
# req 命令参考
## 基础命令
### `/req` 或 `/req list`
列出所有需求,按状态分组显示。
### `/req new [标题]`
创建新需求。
- 参数:`--priority=high|medium|low``--project=<name>``--category=feature|bug|improvement`
- 创建后提示使用 `req-prd` 技能编写 PRD
### `/req status [REQ-ID]`
查看需求详情、进度、关联任务。
## 阶段管理命令
### `/req phase [REQ-ID]`
查看需求当前开发阶段和任务状态。
**执行逻辑**
1. `get_requirement(id)` → 获取 `delivery_stage`
2. `get_requirement_tasks(id)` → 获取所有关联任务
3. 按 linkRole 分组展示,标注当前阶段任务完成度
**输出示例**
```
REQ-20260218-0013 | 阶段: dev (开发)
────────────────────────────────────
✅ analysis (评审)
✅ #6035 【评审】PRD: 需求全生命周期阶段化管理
✅ #6040 【评审】技术设计: 数据模型
▶ dev (开发) ← 当前阶段
🔄 #6042 【开发-后端】实现阶段管理 API [in_progress]
⬜ #6043 【开发-前端】阶段可视化组件 [todo]
⬜ review (代码评审)
(无任务)
⬜ testing (测试)
(无任务)
```
### `/req next [REQ-ID]`
检测当前阶段完成度,推进到下一阶段。
**执行逻辑**
1. 获取当前 `delivery_stage` 和该阶段所有任务
2. 检查任务完成度:
- 全部完成 → 提示「当前阶段已完成,是否推进到 {下一阶段}?」
- **部分未完成 → 显示未完成任务列表 + AskUserQuestion**
- 选项 A: "强制推进(需说明原因)"
- 选项 B: "返回完成任务"
- 用户选 A → 输入跳过原因 → `advance_delivery_stage(force=true)`
- 记录到需求历史: `POST /requirements/{id}/history`comment 包含跳过原因
- **⚠️ 禁止 AI 自动使用 force=true必须经过 AskUserQuestion 确认**
3. **智能跳阶段检测**(推进前):
- `get_requirement_tasks(id)` → 收集所有 linkRole
- 如果目标阶段与当前 linkRole 不匹配,主动建议跳过:
-`implementation` → 推进到 review/testing 时提示「该需求无代码任务,建议跳过此阶段」
-`code_review` → 推进到 review 时提示跳过
-`test` → 推进到 testing 时提示跳过
- 通过 AskUserQuestion 确认:「跳过」或「仍然创建任务」
4. 用户确认推进后:
- 更新 `delivery_stage` 到下一阶段
- **自动创建**目标阶段的建议任务(`create_stage_task` 批量创建,无需询问)
- 展示已创建任务列表:「✅ 已创建: #XXXX 【代码评审】CR: {需求标题}。如需撤销请说明」
- ⚠️ 仅当用户主动要求撤销时才删除已创建任务
**阶段顺序**
```
analysis → design → dev → review → testing → [待部署池] → released
↑ /req deploy 批量推进
```
**linkRole 到阶段的映射**
| linkRole | 所属阶段 |
|----------|----------|
| prd | analysis |
| design | design |
| implementation | dev |
| code_review | review |
| test | testing |
| deploy (staging) | staging |
| deploy (prod) | released |
## 会话恢复命令
### `/req resume [REQ-ID]`
从上次中断的位置恢复工作。**会话被截断后的首选命令**。
**执行逻辑**
1. 若无 REQ-ID → `list_requirements(status=approved)` 找到最近活跃的需求
2. `get_requirement(id)` → 获取需求基本信息和 `delivery_stage`
3. `get_requirement_tasks(id)` → 获取所有关联任务及状态
4. 汇总展示恢复上下文
**输出格式**
```
📋 恢复工作上下文
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
需求: REQ-20260218-0016 | 需求全生命周期 AI 开发管理优化
状态: approved | 阶段: dev (开发)
📊 任务进度: 2/4 完成
✅ #6051 【开发-后端】实现 advance_delivery_stage MCP 工具
✅ #6052 【开发-后端】实现 create_stage_task 组合 MCP 工具
🔄 #6053 【开发-Skill】req-commands 阶段 checklist 模板化 [in_progress]
⬜ #6054 【开发-Skill】会话断点恢复机制 [todo]
▶ 建议操作:
1. 继续任务 #6053当前 in_progress
2. 执行 /req next 推进阶段
3. 执行 /req phase 查看完整阶段视图
```
**自动行为**
- 如果有 `in_progress` 任务,提示继续该任务
- 如果当前阶段所有任务已完成,提示执行 `/req next`
- 如果需求已 `archived`,告知用户无需操作
## 评审命令
### `/req review [REQ-ID]`
提交评审。**前置条件**:必须有 PRD 文档。
**评审等待机制(强制)**
1. `submit_requirement(id)` → status 变为 pending
2. 展示 PRD 要点摘要:
```
PRD 评审摘要
─────────────────────
标题: {需求标题}
核心方案: {1-2句总结}
验收标准: {N}项
改动范围: {文件列表}
```
3. **AskUserQuestion**: "请确认 PRD 是否通过评审"
- "通过评审" → `approve_requirement(id)`
- "需要修改" → 回到编辑流程
4. **⚠️ 禁止 AI 自动审批**,必须等待用户明确选择
### `/req review pass [REQ-ID]`
评审通过。支持多人审批。参数:`--comment="审批意见"`
### `/req review reject [REQ-ID] [原因]`
评审驳回。必须提供驳回原因。
### `/req review status [REQ-ID]`
查看审批进度(多人审批时)。
## 开发命令
### `/req dev [REQ-ID]`
启动开发,自动选择优先级最高的 todo 任务并开始计时。
- 参数:`--task=<task-id>` 指定任务
- 优先启动 `implementation` 角色任务
- **自动设置** `delivery_stage = dev`(如尚未设置)
### `/req cr [REQ-ID]`
代码评审。**前置条件**:开发任务完成。
- 显示 Git diff 摘要
- 生成代码评审检查清单
- **自动设置** `delivery_stage = review`
### `/req test [REQ-ID]`
启动测试。**前置条件**:代码评审通过。
- 参数:`--skip-cr --reason="原因"` 跳过代码评审
- **自动设置** `delivery_stage = testing`
- **⭐ 遵循 `req-test-gate` v2 技能的 5 道门禁**
**执行逻辑5-Gate 流程,详见 `req-test-gate` 技能)**
1. **Gate 1 前置条件**CR 已通过 + 开发任务全部完成(不可跳过)
2. **Gate 2 测试执行**推断需求类型code/skill/ops分阶段验证
- **code 类型四阶段**
- **2A 静态验证**:编译 + 单元测试 + 条件前端/iOS 测试
- **2B 集成验证**API 端点 + DB 约束 + 错误处理
- **2C 冒烟测试**Staging 环境健康检查 + 核心流程(已部署时)
- **2D 原型符合性**:对比原型 HTML 的结构/字段/交互/状态(有原型时)
- **skill**: 关键词一致性 + 规则无歧义 + 边界情况(至少 3 项)
- **ops**: 部署命令可执行 + 健康检查
3. **Gate 3 质量验证**:派遣 test-validator 子代理审查测试质量
- code 类型:总是触发 | skill 类型≥5 测试项时触发 | ops 类型:不触发
- Critical 缺陷必须修复Important 缺陷需 AskUserQuestion 确认
4. **Gate 4 文档持久化(不可跳过)**`create-and-attach` 将完整测试报告写入测试任务文档
- 文档模板见 `req-test-gate` 技能的「最小必填模板」(含 2A-2D 阶段标记)
- 必须包含:前置条件结果 + 测试执行表格 + 质量验证摘要 + 通过/失败结论
- 无此文档 → `/req deploy` 前置检查会警告
5. **Gate 5 回归贡献code 类型)**:检查是否有 linkRole=regression 任务和用例文档
- v2.0 过渡期为警告级别,不阻塞
- 提醒补充回归测试用例到回归池
### `/req deploy [--project <name>] [--env <environment>]`
**项目级批量部署**。收集所有待部署需求,一次构建部署。
- **这是项目级动作**,不是单需求操作
- `--project` 默认为当前项目,`--env` 默认为 `staging`
- 参数:`--platform=web|ios|android`
- **⭐ 遵循 `req-test-gate` v2 的 Deploy Gates (DG1-DG6)**
**执行逻辑**
1. **前置检查(强制)**
- 对每个待部署需求,检查 testing 阶段任务是否有文档附件(`has_task_document`
- ✅ 有文档 → 继续
- ⚠️ 无文档 → AskUserQuestion「测试任务 #XXXX 无测试记录文档,确认继续部署?」
2. **收集待部署需求**
- `delivery_stage = testing` 且所有 test 任务 completed
- 有 implementation 任务(排除纯运维/文档需求)
3. **展示待部署列表** → `AskUserQuestion` 确认部署范围
4. **创建部署批次任务**
- 标题:`【部署】{project} {date} ({N} requirements)`
- 对每个选中需求:`link_tasks_to_requirement(role=deploy)`
5. **Deploy Gates (DG1-DG6)**(详见 `req-test-gate/deploy-gates.md`
- **DG1 迁移检查(不可跳过)**:对比 migrations/ vs 数据库,有新 migration 先备份再执行
- **DG2 Staging 部署**:构建镜像 + 部署到 singapore
- **DG3 冒烟测试**:健康检查 + 登录 + 新 API 验证
- **DG4 影响域回归**:根据 module-deps.json 运行对应回归套件(无套件时跳过)
- **DG5 性能基线(推荐)**:关键 API 响应时间检查
- **DG6 生产部署(不可跳过)**:部署 + 健康检查,失败立即回滚
6. **部署后强制检查点**
- ✅ **部署文档创建**(必须):`create-and-attach` 到部署任务,包含 Deploy Gates 结果表格
- ☑️ **截图验证**(可选):有 chrome-dev MCP → 执行截图;无 → 记录跳过
7. **部署成功后**
- 所有关联需求 `advance_delivery_stage → released`
- `complete_task(部署任务)`
**单需求兼容**:当仅 1 个需求待部署时,流程自动退化为单需求部署。
### `/req done [REQ-ID]`
完成归档。参数:`--force` 强制归档。
**类型化归档门禁(强制)**
1. `get_requirement_tasks(id)` → 获取所有关联任务
2. **推断需求类型**(从 linkRole 集合判断):
- **code**: 有 `implementation` 角色任务 → 代码需求
- **skill**: 无 `implementation`,有 `prd`/`code_review`/`test` → Skill/文档需求
- **ops**: 仅 `deploy` 角色任务 → 运维需求
3. **按类型执行检查清单**
| 检查项 | code | skill | ops |
|--------|------|-------|-----|
| delivery_stage = released | ✅ | - | - |
| delivery_stage >= testing | - | ✅ | - |
| deploy 任务已完成 | ✅ | - | ✅ |
| 部署文档存在 | ✅ | - | - |
| 所有关联任务已完成 | ✅ | ✅ | ✅ |
4. **检查结果处理**
- 全部通过 → 展示检查清单 + AskUserQuestion "确认归档?"
- 有缺失 → 显示缺失项 + AskUserQuestion "是否强制归档?"
- 用户确认 → 进入步骤 5
5. **Git 提交(强制)**
- `git add` 本需求相关变更文件
- `git commit -m "feat(skill): REQ-XXXX 需求标题"`(或 `fix`/`refactor` 等合适的 type
- `git push origin <current-branch>`
- ⚠️ 提交前确认无敏感文件(.env、credentials 等)
6. `archive_requirement(id)`
7. 归档后生成生命周期总结,触发同步
### `/req regression [--module <name>] [--mode <mode>]`
**运行回归测试**。系统级持续质量活动。
- `--module` 指定模块okr/task/auth/...),不指定则按影响域推断
- `--mode` 执行模式:`impact`(影响域)| `critical`(关键路径)| `full`(全量)
- 默认模式:`impact`(根据最近变更推断影响域)
**执行逻辑**(详见 `req-test-gate/regression.md`
1. **确定范围**
- 指定 module → 直接运行该模块回归套件
- 未指定 → `git diff --name-only` 获取变更 → 查 `module-deps.json` → 推断影响域
2. **运行回归套件**
- 执行 `regression-suite/suites/` 下对应脚本
- 记录每个用例的 PASS/FAIL 状态
3. **回归判定**
- 对比上次运行结果
- 上次 PASS + 本次 FAIL → 标记为「回归」
4. **结果处理**
- 全部通过 → 展示通过率
- 有回归 → AskUserQuestion「是否为回归项创建 bug 需求?」
- 有新失败 → 展示失败列表,建议排查
5. **报告输出**
```
回归测试结果 - {module/all}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
模式: {impact/critical/full}
套件: {N} 个 | 用例: {M} 个
✅ 通过: {P} | ❌ 失败: {F} | 🔴 回归: {R}
```
**当前状态**:回归套件待初始化,首次运行会提示建立基线。
## 辅助命令
### `/req link [REQ-ID] --task-id [TASK-ID]`
关联任务到需求。
### `/req decompose [REQ-ID]`
分解需求为任务。**创建时自动加阶段前缀**。
### `/req generate-tasks [REQ-ID]`
根据 PRD 自动生成开发任务。**所有任务带【开发】前缀**。
### `/req priority [REQ-ID] [low|medium|high]`
设置需求优先级。
### `/req stats [REQ-ID|--all]`
查看需求统计信息。
## 阶段任务 Checklist 模板
当 `/req next` 推进到新阶段时,根据目标阶段自动建议创建的任务。使用 `create_stage_task` 组合工具一步完成(创建+关联+可选启动)。
### analysis评审
```
☐ 【评审】PRD: {需求标题} (linkRole: prd)
☐ 【评审】技术设计: {需求标题} (linkRole: design) [可选]
```
### design设计
```
☐ 【设计】技术方案: {需求标题} (linkRole: design)
☐ 【设计】数据模型设计 (linkRole: design) [可选]
```
### dev开发
```
☐ 【开发-后端】{需求标题} (linkRole: implementation)
☐ 【开发-前端】{需求标题} (linkRole: implementation) [可选]
☐ 【开发-MCP】{需求标题} (linkRole: implementation) [可选]
```
### review代码评审
```
☐ 【代码评审】{需求标题} (linkRole: code_review)
```
### testing测试
```
☐ 【测试】单元测试: {需求标题} (linkRole: test)
☐ 【测试】集成测试: {需求标题} (linkRole: test) [可选]
```
**按需求类型的最低测试标准**
| 需求类型 | 最低测试要求 |
|----------|-------------|
| **code** | `go test` 或前端测试通过 + API 验证 + 截图验证 |
| **skill** | 关键词跨文件一致性 + 规则无歧义验证 + 边界情况检查(至少 3 项) |
| **ops** | 部署命令可执行 + 健康检查通过 |
**skill 类型测试 checklist**(最低 3 项):
```
☐ 关键词一致性grep 验证核心概念在所有相关 skill 文件中对齐
☐ 规则无歧义:每条规则的触发条件和执行动作明确,无二义性
☐ 边界情况:至少验证 1 个边界场景(如混合类型需求的分类)
☐ 交叉引用:文件间的引用(如"见 xxx 技能")指向正确 [可选]
```
### 部署(项目级,由 `/req deploy` 触发)
部署不再按单需求创建任务,而是通过 `/req deploy` 批量收集待部署需求:
```
testing 完成的需求 → 进入「待部署池」
/req deploy → 创建批次任务:【部署】{project} {date} ({N} requirements)
关联到所有选中需求 (linkRole: deploy)
部署成功后批量推进 → released
```
### `/req next` 执行流程(更新版)
1. `get_requirement(id)` → 获取 `delivery_stage`
2. `get_requirement_tasks(id)` → 获取关联任务,收集 linkRole 集合
3. **智能跳阶段检测**:检查目标阶段是否与 linkRole 匹配
- 不匹配 → AskUserQuestion「建议跳过 {阶段},是否同意?」
- 用户同意跳过 → 递归检测下一阶段
- 用户拒绝 → 继续推进到该阶段
4. **门禁检查**`advance_delivery_stage(id, nextStage)` 自动检查
- 通过 → 进入步骤 4.5
- 未通过 → 显示阻塞任务AskUserQuestion 确认 force禁止自动 force
4.5. **⭐ 内容门禁检查(防空转)**:对关键阶段的已完成任务验证文档附件
- **适用阶段**: reviewCR 报告、testing测试结果、staging部署文档
- **检查逻辑**
```
对当前阶段的每个 completed 任务:
has_task_document(taskId) → 有文档?
✅ 有 → get_task_document(taskId) → 检查质量:
- review: ≥500字符 + 含 file:line 代码引用 + 含结论章节
- testing: 含测试项表格 + 含通过/失败结论 + ≥200字符
(详见 req-test-gate 技能 Gate 4 文档质量门禁)
- staging: 含健康检查结果 + 含镜像/commit 信息
❌ 无 → 阻止推进,提示「任务 #XXXX 缺少 {类型} 文档」
```
- **未通过处理**AskUserQuestion「内容门禁未通过选择操作」
- 选项 A: "补充文档后重试"
- 选项 B: "强制跳过(记录原因)" → 记录跳过原因到需求历史
- **⚠️ 禁止 AI 自动跳过**,必须经过 AskUserQuestion
5. **自动创建阶段任务**`create_stage_task` 批量创建目标阶段建议任务
- 展示已创建列表:「✅ 已创建: #XXXX {任务名}。如需撤销请说明」
- 用户主动要求撤销时才删除
## MCP 工具映射
| 命令 | MCP 工具 |
|------|----------|
| `/req` | `list_requirements` |
| `/req new` | `create_requirement` |
| `/req phase` | `get_requirement` + `get_requirement_tasks` |
| `/req next` | `advance_delivery_stage` (门禁检查+推进) + `create_stage_task` (创建任务) |
| `/req resume` | `get_requirement` + `get_requirement_tasks` (断点恢复) |
| `/req dev` | `get_requirement` + `get_requirement_tasks` + `start_task_with_timer` |
| `/req cr` | `get_requirement_tasks` + Git diff |
| `/req test` | `req-test-gate` v2 5-Gate 流程: 前置检查 → 类型化测试(2A-2D) → test-validator 子代理 → `create-and-attach` 持久化 → 回归贡献检查 |
| `/req deploy` | 前置检查 + Deploy Gates(DG1-DG6): 迁移→staging→冒烟→回归→性能→生产 + 部署文档 |
| `/req regression` | `git diff` 影响域推断 + 运行回归套件 + 回归判定 + 可选创建 bug 需求 |
| `/req done` | 类型推断 + 检查清单 + `AskUserQuestion` + `archive_requirement`(⚠️ 禁止直接调用 archive |
| `/req review` | `submit_requirement` |
| `/req review pass` | `approve_requirement` |
| `/req review reject` | `reject_requirement` |
| `/req link` | `link_tasks_to_requirement` |
## 任务关联类型
| link_role | 说明 | 阶段前缀 | 进度权重 |
|-----------|------|----------|----------|
| prd | PRD 文档 | 【评审】 | 0.1 |
| design | 技术设计 | 【评审】 | 0.05 |
| implementation | 开发实现 | 【开发】 | 0.5 |
| code_review | 代码评审 | 【代码评审】 | 0.05 |
| test | 测试验证 | 【测试】 | 0.15 |
| deploy | 部署发布 | 【部署】 | 0.1 |
| regression | 回归用例 | 【回归】 | 0.0 |
| documentation | 文档编写 | 【文档】 | 0.05 |

View File

@@ -1,8 +0,0 @@
{
"name": "req-deploy-plugin",
"description": "Plugin for req-deploy",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,18 +0,0 @@
{
"name": "req-deploy",
"version": "1.0.0",
"description": "需求部署技能。用于 Docker 镜像构建、Staging/Production 环境部署、API 验证、前端截图验证、部署文档创建。当用户执行 /req deploy 或需要部署需求时自动激活。",
"triggerPatterns": [
"部署",
"deploy",
"staging",
"production",
"镜像构建",
"docker build",
"Jenkins",
"生产环境",
"预发布"
],
"autoActivate": false,
"hidden": false
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +0,0 @@
# 代码评审指南 (Code Review Guide)
代码评审是测试阶段的前置条件,确保代码质量在测试前得到验证。
## 评审时机
```
开发完成 → 代码评审 → 测试
↑ ↓
└── 发现问题,修复后重新评审
```
## 评审检查清单
### 1. 代码风格
- [ ] 符合项目编码规范Go/TypeScript
- [ ] 命名清晰有意义
- [ ] 代码格式统一(已运行 lint/format
### 2. 安全性
- [ ] 无 SQL 注入风险
- [ ] 无 XSS 漏洞
- [ ] 无敏感信息硬编码(密码、密钥)
- [ ] 权限检查完善
### 3. 错误处理
- [ ] 异常捕获完善
- [ ] 错误信息友好(不暴露内部细节)
- [ ] 边界条件处理
### 4. 性能
- [ ] 无 N+1 查询
- [ ] 无不必要的循环/递归
- [ ] 大数据量有分页处理
### 5. 日志与监控
- [ ] 关键操作有日志
- [ ] 日志级别适当
- [ ] 无敏感信息输出到日志
### 6. 测试覆盖
- [ ] 关键逻辑有单元测试
- [ ] 测试用例有效
### 7. 文档
- [ ] 复杂逻辑有注释
- [ ] API 有文档说明
## 评审方式
| 方式 | 适用场景 |
|------|----------|
| 自评 (Self Review) | AI 开发的代码Claude 自动检查 |
| 他人评审 (Peer Review) | 团队协作,提交 PR 等待评审 |
| 结对评审 (Pair Review) | 复杂功能,实时讨论 |
## 执行流程
### `/req cr` 命令执行步骤
1. **验证开发完成**
```
检查所有 implementation 任务状态 = completed
```
2. **生成变更摘要**
```bash
git diff --stat HEAD~N # N = 开发期间的提交数
git diff --name-only HEAD~N
```
3. **显示检查清单**
- 输出上述检查清单
- 逐项确认或标记问题
4. **记录评审结果**
- 通过:创建 code_review 任务并标记 completed
- 不通过:列出问题,等待修复后重新评审
## 常见问题
### Go 后端
- 未检查 `error` 返回值
- 缺少 `defer` 关闭资源
- 并发访问未加锁
### TypeScript 前端
- `any` 类型滥用
- 缺少空值检查
- 未处理异步错误
### 数据库
- 缺少索引
- 大事务未拆分
- 未考虑并发更新
## 评审不通过时
```
/req cr REQ-XXXX
→ 发现问题:
⚠️ handlers/task_handler.go:245 - 缺少错误处理
⚠️ pages/TaskList.tsx:88 - 存在 XSS 风险
→ 请修复后重新执行 /req cr
```
## 跳过评审(紧急情况)
```bash
/req test REQ-XXXX --skip-cr --reason="紧急生产修复"
```
> 跳过评审需记录原因,事后补充评审。

View File

@@ -1,273 +0,0 @@
# 部署指南
## 部署流程概览
```
Staging 部署(手动) Production 部署Jenkins
↓ ↓
本地构建 :test 镜像 本地构建 :latest 镜像
↓ ↓
推送到 DockerHub 推送到 DockerHub
↓ ↓
显示部署命令 调用 Jenkins API
↓ ↓
用户手动执行 自动触发部署
↓ ↓
验证 API 轮询构建状态
验证 API
```
## 环境说明
| 环境 | 触发方式 | 镜像标签 | 用途 |
|------|----------|----------|------|
| staging | 手动 SSH | `:test` | 预发布测试 |
| production | Jenkins API | `:latest` | 正式生产 |
## 镜像构建规范
> ⚠️ **重要**: 必须理解 Dockerfile target 和镜像标签的区别
### Dockerfile Target vs 镜像标签
| 概念 | 说明 | 示例 |
|------|------|------|
| **Dockerfile Target** | 构建阶段,决定镜像内容 | `--target production`, `--target test` |
| **镜像标签** | 版本标识,决定部署环境 | `:test`, `:latest` |
### 正确的构建方式
| 用途 | Dockerfile Target | 镜像标签 | 镜像大小 |
|------|-------------------|----------|----------|
| **Staging 部署** | `--target production` | `:test` | ~50MB |
| **Production 部署** | `--target production` | `:latest` | ~50MB |
| **运行单元测试** | `--target test` | 无需推送 | ~900MB+ |
### 常见错误
**错误做法**:用 `--target test` 构建部署镜像
```bash
# 错误!这会生成 900MB+ 的镜像,包含测试框架和源代码
docker buildx build --target test -t xxx:test ...
```
**正确做法**:用 `--target production` 构建部署镜像
```bash
# 正确!生成 ~50MB 的精简镜像,只包含二进制文件
docker buildx build --target production -t xxx:test ...
```
### Staging vs Production 镜像区别
两者都使用 `--target production` 构建,区别在于:
| 区别点 | Staging (`:test`) | Production (`:latest`) |
|--------|-------------------|------------------------|
| 镜像标签 | `:test` | `:latest` |
| 前端 API URL | `staging.ai.pipexerp.com` | `ai.pipexerp.com` |
| 后端代码 | 完全相同 | 完全相同 |
| 部署服务器 | singapore | tools_ai_proj |
> **注意**: 不是把 staging 镜像部署到生产,而是测试通过后用生产 URL **重新构建** `:latest` 镜像
## Staging 部署
### 前置条件
> ⚠️ **必须完成本机测试才能部署 staging**
| 检查项 | 说明 |
|--------|------|
| 代码评审 | `/req cr` 已完成 |
| 后端单元测试 | `go test ./... -v` 全部通过 |
| **前端截图验证** | 使用 chrome-dev MCP 截图确认 UI 正确显示 |
如果本机测试未通过,将拒绝部署并提示:
```
→ ❌ 本机测试未完成,禁止部署到 staging
→ 请先执行: /req test REQ-XXX
```
### 命令格式
```bash
/req deploy REQ-XXX --env staging [--service <service>]
```
### 支持的服务
| 服务 | 说明 |
|------|------|
| `backend` | 后端 API 服务 |
| `frontend` | 前端 Web 应用 |
| `all` | 全部服务(默认) |
### 执行流程
1. **构建镜像**(本地执行)
```bash
# 后端
docker buildx build --platform linux/amd64 \
-f backend/Dockerfile --target production \
-t saltthing123/ai-proj-backend:test --push backend/
# 前端(注意 API URL 配置)
docker buildx build --platform linux/amd64 \
-f frontend/Dockerfile.prod --target production \
--build-arg REACT_APP_API_URL=https://staging.ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_API_BASE_URL=https://staging.ai.pipexerp.com/api/v1 \
-t saltthing123/ai-proj-frontend:test --push frontend/
```
2. **部署命令**(用户手动执行)
```bash
ssh singapore "cd /opt/ai-project-staging && \
sudo docker-compose pull && \
sudo docker-compose up -d"
```
3. **验证**
```bash
curl -s https://staging.ai.pipexerp.com/api/v1/health | jq .
```
## Production 部署
### 命令格式
```bash
/req deploy REQ-XXX --env production [--service <service>]
```
### 支持的服务
| 服务 | 镜像名 | Jenkins 参数 |
|------|--------|--------------|
| `backend` | saltthing123/ai-proj-backend | SERVICE=backend |
| `frontend` | saltthing123/ai-proj-frontend | SERVICE=frontend |
| `ios` | - | SERVICE=ios |
| `android` | - | SERVICE=android |
| `all` | 全部 | SERVICE=all默认 |
### 执行流程
1. **构建镜像**(本地执行)
```bash
# 后端
docker buildx build --platform linux/amd64 \
-f backend/Dockerfile --target production \
-t saltthing123/ai-proj-backend:latest --push backend/
# 前端
docker buildx build --platform linux/amd64 \
-f frontend/Dockerfile.prod --target production \
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
-t saltthing123/ai-proj-frontend:latest --push frontend/
```
2. **触发 Jenkins 部署**
```bash
source ~/.config/devops/credentials.env
curl -X POST "$JENKINS_URL/job/ai-proj/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "SERVICE=backend&IMAGE_TAG=latest"
```
3. **查看构建状态**
```bash
source ~/.config/devops/credentials.env
curl -s "$JENKINS_URL/job/ai-proj/lastBuild/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN" | jq '.result, .building'
```
4. **验证**
```bash
curl -s https://ai.pipexerp.com/api/v1/health | jq .
```
## 安全约束
- **禁止自动 SSH 部署到生产服务器**
- 生产环境部署必须通过 Jenkins API 触发
- Staging 部署命令只显示,由用户手动执行
- 构建失败时必须显示错误原因和解决方案
## 项目配置
### AI-Proj
| 配置项 | 值 |
|--------|-----|
| Jenkins Job | ai-proj |
| Staging 服务器 | singapore |
| Production 服务器 | tools_ai_proj |
| DockerHub 用户 | saltthing123 |
### Coolbuy-Paas
| 配置项 | 值 |
|--------|-----|
| Jenkins Job | coolbuy-paas |
| Staging 服务器 | fnos 测试环境 |
| Production 服务器 | 39.106.88.83 |
| DockerHub 用户 | saltthing123 |
## 常见问题
### Docker 推送失败
**错误**: `push access denied`
**解决**:
```bash
docker login
# 输入 Docker Hub 凭据
```
### Jenkins 构建失败
**查看日志**:
```bash
source ~/.config/devops/credentials.env
curl -s "$JENKINS_URL/job/ai-proj/lastBuild/consoleText" \
-u "$JENKINS_USER:$JENKINS_TOKEN" | tail -100
```
### 镜像架构不匹配
**错误**: `exec format error`
**原因**: 在 ARM64 (M1/M2 Mac) 构建的镜像部署到 AMD64 服务器
**解决**: 构建时必须指定 `--platform linux/amd64`
### 镜像体积异常大900MB+
**错误**: 构建的镜像超过 100MB
**原因**: 使用了错误的 Dockerfile target
**检查**:
```bash
# 查看镜像层大小
docker history <image>:<tag> --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" | head -10
```
**常见原因**:
| 层内容 | 大小 | 说明 |
|--------|------|------|
| `go mod download` | 600MB+ | Go 依赖包(不应出现在生产镜像) |
| `ginkgo/gomega` | 200MB+ | 测试框架(不应出现在生产镜像) |
| `COPY . .` | 100MB+ | 源代码(不应出现在生产镜像) |
**解决**: 确保使用 `--target production` 而不是 `--target test`
```bash
# 错误
docker buildx build --target test ...
# 正确
docker buildx build --target production ...
```

View File

@@ -1,55 +0,0 @@
# Hook 自动同步机制
Hook 机制可在特定事件发生时自动触发同步,无需手动执行。
## 支持的 Hook 事件
| 事件 | 触发条件 | 自动执行操作 |
|------|---------|-------------|
| `requirement.created` | 创建新需求 | 同步需求到远程 |
| `requirement.submitted` | 提交评审 | 发送评审通知 |
| `requirement.approved` | 需求评审通过 | 同步需求 + 关联任务到远程 |
| `requirement.archived` | 需求归档 | 最终同步 + 同步到思源笔记 + 发送通知 |
| `task.completed` | 任务完成 | 同步任务状态到远程 |
## 配置 Hook
`.claude/settings.local.json` 中配置:
```json
{
"hooks": {
"requirement.approved": {
"enabled": true,
"actions": ["sync_requirement_to_remote", "sync_tasks_to_remote"]
},
"requirement.archived": {
"enabled": true,
"actions": ["sync_requirement_to_remote", "sync_to_siyuan", "send_notification"]
},
"task.completed": {
"enabled": true,
"actions": ["sync_task_to_remote"]
}
}
}
```
## 手动触发 Hook
```bash
/req hook trigger requirement.approved REQ-2026-0010
```
## 查看 Hook 执行历史
```bash
/req hook history REQ-2026-0010
```
## 禁用/启用 Hook
```bash
/req hook disable REQ-2026-0010
/req hook enable REQ-2026-0010
```

View File

@@ -1,64 +0,0 @@
# MCP 认证配置
## 环境选择原则
> 需求和任务的主数据源是**生产环境 (ai.pipexerp.com)**。
> 所有需求创建、任务创建、查询、更新操作必须在生产环境执行。
| 环境 | 用途 | API 地址 |
|------|------|----------|
| **生产环境** | 需求创建、任务创建、数据管理 | https://ai.pipexerp.com/api/v1 |
| 本地环境 | 代码开发调试、功能测试 | http://localhost:8080/api/v1 |
## MCP 配置
确保 `~/.claude/.mcp.json` 配置:
```json
{
"mcpServers": {
"ai-proj": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_xxxxxxxx...",
"SYNC_REMOTE_API_BASE": "https://ai.pipexerp.com/api/v1",
"SYNC_REMOTE_API_KEY": "aiproj_pk_xxxxxxxx..."
}
}
}
}
```
## 认证方式
### PAT 秘钥(推荐)
- 格式: `aiproj_pk_` + 64 字符十六进制(共 74 字符)
- 优势: 长期有效,无需频繁更新
### dev-quick-login备选
仅在 PAT 秘钥不可用时使用:
```bash
curl -s -X POST "http://localhost:8080/api/v1/auth/dev-quick-login" \
-H "Content-Type: application/json" \
-d '{"username":"qiudl"}' | jq -r '.data.access_token'
```
> JWT token 有效期 24 小时,日常使用推荐 PAT 秘钥。
## 验证 PAT 秘钥
```bash
# 测试本地
curl -s -H "X-API-Key: aiproj_pk_xxx..." \
"http://localhost:8080/api/v1/tasks?limit=1" | jq '.success'
# 测试远程
curl -s -H "Authorization: Bearer aiproj_pk_xxx..." \
"https://ai.pipexerp.com/api/v1/tasks?limit=1" | jq '.success'
```

View File

@@ -1,42 +0,0 @@
# 通知与自动化配置
## 邮件通知
### 默认邮件组
| 收件人 |
|--------|
| qiudl@zhiyuncai.com |
| fuxing@zhiyuncai.com |
| haiqing@zhiyuncai.com |
| wuweier@zhiyuncai.com |
### 通知类型
| 类型 | 触发时机 | 邮件主题 | 附件文档 |
|------|----------|----------|----------|
| `prd` | PRD完成 | [REQ-PRD] REQ-XXXX PRD文档已完成 | 01-PRD.md |
| `dev` | 开发完成 | [REQ-开发] REQ-XXXX 开发完成 | 02-开发设计.md |
| `test` | 测试完成 | [REQ-测试] REQ-XXXX 测试完成 | 03-测试报告.md |
| `deploy` | 发布完成 | [REQ-发布] REQ-XXXX 已发布 | 04-发布记录.md |
| `archive` | 归档 | [REQ-归档] REQ-XXXX 已归档 | 05-生命周期总结.md |
### 使用方式
```bash
# 使用默认邮件组
/req notify REQ-2026-0007 --type deploy
# 自定义收件人
~/.claude/skills/req/notify.sh -r REQ-2026-0007 -t deploy -e "user1@example.com,user2@example.com"
# 不发送附件
~/.claude/skills/req/notify.sh -r REQ-2026-0007 -t archive -n
```
## 脚本文件
| 脚本 | 功能 | 位置 |
|------|------|------|
| notify.sh | 发送邮件通知 | ~/.claude/skills/req/ |
| update-siyuan-release.sh | 更新思源笔记发布记录 | ~/.claude/skills/req/ |

View File

@@ -1,126 +0,0 @@
# PRD 评审方法论
> 评审 PRD 是需求流程中的关键质量关卡。
## 评审流程
1. **结构完整性检查** - 检查 PRD 是否包含所有必要章节
2. **需求清晰度评估** - 验证需求描述是否明确无歧义
3. **技术可行性分析** - 评估技术方案是否可实现
4. **数据模型验证** - 检查数据结构设计是否合理
5. **API 设计审查** - 验证接口设计是否符合规范
## PRD 评审检查清单
### 一、结构完整性检查
| 检查项 | 必须 | 说明 |
|--------|------|------|
| 基本信息 | ✓ | 需求编号、标题、创建日期、作者 |
| 需求背景 | ✓ | 为什么需要这个功能 |
| 目标用户 | ✓ | 明确功能面向的用户群体 |
| 功能描述 | ✓ | 详细的功能需求说明 |
| 用户故事 | ○ | As a... I want... So that... |
| 数据模型 | ✓ | 数据库表结构设计 |
| API 设计 | ✓ | RESTful 接口定义 |
| 页面原型 | ○ | 界面布局和交互说明 |
| 非功能需求 | ○ | 性能、安全、可用性要求 |
| 验收标准 | ✓ | 明确的功能验收条件 |
> ✓ = 必须包含, ○ = 建议包含
### 二、需求清晰度评估SMART 原则)
| 原则 | 检查点 | 示例 |
|------|--------|------|
| **S**pecific | 需求描述是否具体明确 | ❌ "支持搜索" → ✅ "支持按需求编号、标题模糊搜索" |
| **M**easurable | 是否有量化指标 | ❌ "快速响应" → ✅ "响应时间 < 200ms" |
| **A**chievable | 技术上是否可行 | 评估现有技术栈能否支持 |
| **R**elevant | 是否与业务目标相关 | 功能是否解决实际问题 |
| **T**ime-bound | 是否有明确的时间范围 | 开发周期、上线日期 |
### 三、技术可行性分析
| 检查维度 | 评估内容 |
|----------|----------|
| 技术栈兼容性 | 现有技术栈是否支持所需功能 |
| 系统架构影响 | 是否需要修改现有架构 |
| 第三方依赖 | 是否引入新的外部依赖 |
| 性能影响 | 对系统性能的潜在影响 |
| 安全考量 | 是否存在安全风险 |
| 数据迁移 | 是否需要数据迁移方案 |
### 四、数据模型验证
| 检查项 | 说明 |
|--------|------|
| 表结构设计 | 字段类型、约束、索引是否合理 |
| 关联关系 | 外键、多对多关系是否正确 |
| 命名规范 | 表名、字段名是否符合项目规范 |
| 扩展性 | 是否预留扩展字段 |
| 数据量预估 | 数据增长预估和存储方案 |
| 查询性能 | 常用查询是否有索引支持 |
### 五、API 设计审查
| 检查项 | 标准 |
|--------|------|
| RESTful 规范 | URL 使用名词、HTTP 方法语义正确 |
| 响应格式 | 统一的响应结构 `{success, data, message}` |
| 错误处理 | 明确的错误码和错误信息 |
| 分页设计 | 列表接口支持分页 `?page=1&page_size=20` |
| 参数验证 | 必填参数、类型、范围说明 |
| 版本控制 | API 路径包含版本 `/api/v1/...` |
## 评审意见模板
### 通过模板
```
✅ PRD 评审通过
【评审结论】
PRD 文档结构完整,需求描述清晰,技术方案可行,建议批准进入开发阶段。
【肯定之处】
- 需求背景阐述清晰
- 数据模型设计合理
- API 接口规范
【建议改进】(非阻塞)
- 建议补充性能测试用例
- 建议增加边界条件说明
【评审人】xxx
【评审时间】2026-01-24 10:00
```
### 驳回模板
```
❌ PRD 评审驳回
【驳回原因】
1. 数据模型缺少索引设计
2. API 接口缺少错误处理说明
3. 搜索功能需求描述模糊
【修改要求】
□ 补充数据表索引设计
□ 明确 API 错误码定义
□ 细化搜索功能的具体实现方式
【驳回人】xxx
【驳回时间】2026-01-24 10:00
```
## 常见驳回原因
| 类别 | 常见问题 | 改进建议 |
|------|----------|----------|
| 结构缺失 | 缺少数据模型或 API 设计 | 补充完整的技术设计章节 |
| 需求模糊 | 功能描述不够具体 | 按 SMART 原则重新描述 |
| 边界不清 | 缺少边界条件和异常处理 | 补充边界条件和错误场景 |
| 设计缺陷 | 数据模型或 API 设计不合理 | 重新设计并说明理由 |
| 范围过大 | 需求范围过大难以实现 | 拆分为多个小需求 |
| 验收不明 | 缺少验收标准 | 补充可验证的验收条件 |

View File

@@ -1,50 +0,0 @@
# 思源笔记集成
需求的 5 阶段文档统一存储到思源笔记中。
## 文档结构
```
需求管理/
└── REQ-2026-XXXX/
├── 01-PRD.md # 产品需求文档
├── 02-开发设计.md # 开发技术文档
├── 03-测试报告.md # 测试验收报告
├── 04-发布记录.md # CI/CD发布记录
└── 05-生命周期总结.md # 需求归档总结
```
## 同步命令
```bash
/req sync-siyuan REQ-2026-0007
```
## 自动同步时机
| 阶段 | 触发命令 | 同步文档 |
|------|---------|---------|
| PRD 完成 | `/req review` | 01-PRD.md |
| 开发完成 | `/req test` | 02-开发设计.md |
| 测试完成 | `/req deploy` | 03-测试报告.md |
| 发布完成 | 发布任务完成 | 04-发布记录.md |
| 归档完成 | `/req done` | 05-生命周期总结.md (全量同步) |
## MCP 工具调用
```python
# 创建文档
mcp__siyuan__createDocWithMd(
notebook="需求管理",
path="/REQ-2026-0007/01-PRD",
markdown=prd_content
)
```
## 配置
环境变量(可选):
```bash
export SIYUAN_URL="http://100.118.62.18:6806"
export SIYUAN_TOKEN="your-token"
```

View File

@@ -376,9 +376,185 @@ ai-proj req tasks --id <id> # 查看关联任务
**linkRole**: `prd`, `design`, `implementation`, `code_review`, `test`, `deploy`, `regression`, `documentation` **linkRole**: `prd`, `design`, `implementation`, `code_review`, `test`, `deploy`, `regression`, `documentation`
## 详细阶段管理命令
### `/req phase [REQ-ID]`
查看需求当前开发阶段和任务状态。
**执行逻辑**
1. `get_requirement(id)` → 获取 `delivery_stage`
2. `get_requirement_tasks(id)` → 获取所有关联任务
3. 按 linkRole 分组展示,标注当前阶段任务完成度
**输出示例**
```
REQ-20260218-0013 | 阶段: dev (开发)
────────────────────────────────────
✅ analysis (评审)
✅ #6035 【评审】PRD: 需求全生命周期阶段化管理
▶ dev (开发) ← 当前阶段
🔄 #6042 【开发-后端】实现阶段管理 API [in_progress]
⬜ #6043 【开发-前端】阶段可视化组件 [todo]
⬜ review (代码评审)
⬜ testing (测试)
```
### `/req resume [REQ-ID]`
从上次中断的位置恢复工作。**会话被截断后的首选命令**。
**执行逻辑**
1. 若无 REQ-ID → `list_requirements(status=approved)` 找最近活跃需求
2. `get_requirement(id)` → 获取 delivery_stage
3. `get_requirement_tasks(id)` → 获取所有关联任务及状态
4. 汇总展示恢复上下文
**输出格式**
```
📋 恢复工作上下文
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
需求: REQ-20260218-0016 | 需求标题
状态: approved | 阶段: dev (开发)
📊 任务进度: 2/4 完成
✅ #6051 【开发-后端】实现 API
🔄 #6053 【开发-Skill】xxx [in_progress]
⬜ #6054 【开发-Skill】xxx [todo]
▶ 建议操作:
1. 继续任务 #6053当前 in_progress
2. 执行 /req next 推进阶段
```
### `/req regression [--module <name>] [--mode <mode>]`
**运行回归测试**。系统级持续质量活动。
- `--module` 指定模块,不指定则按影响域推断
- `--mode``impact`(影响域,默认)| `critical`(关键路径)| `full`(全量)
**执行逻辑**
1. 确定范围:指定 module → 直接运行;未指定 → `git diff` + `module-deps.json` 推断
2. 运行 `regression-suite/suites/` 下对应脚本
3. 对比上次运行结果,标记回归(上次 PASS + 本次 FAIL
4. 有回归 → AskUserQuestion「是否创建 bug 需求?」
## 辅助命令
**`/req link [REQ-ID] --task-id [TASK-ID]`** — 关联任务到需求
**`/req decompose [REQ-ID]`** — 分解需求为任务,自动加阶段前缀
**`/req generate-tasks [REQ-ID]`** — 根据 PRD 自动生成开发任务,带【开发】前缀
**`/req priority [REQ-ID] [low|medium|high]`** — 设置需求优先级
**`/req stats [REQ-ID|--all]`** — 查看需求统计信息
## 阶段任务 Checklist 模板
`/req next` 推进到新阶段时,通过 `create_stage_task` 自动创建建议任务:
### analysis评审
```
☐ 【评审】PRD: {需求标题} (linkRole: prd)
☐ 【评审】技术设计: {需求标题} (linkRole: design) [可选]
```
### design设计
```
☐ 【设计】技术方案: {需求标题} (linkRole: design)
```
### dev开发
```
☐ 【开发-后端】{需求标题} (linkRole: implementation)
☐ 【开发-前端】{需求标题} (linkRole: implementation) [可选]
```
### review代码评审
```
☐ 【代码评审】{需求标题} (linkRole: code_review)
```
### testing测试
```
☐ 【测试】单元测试: {需求标题} (linkRole: test)
☐ 【测试】集成测试: {需求标题} (linkRole: test) [可选]
```
### 部署(由 `/req deploy` 批量触发)
```
testing 完成 → 进入「待部署池」→ /req deploy 创建批次任务
```
**按需求类型的最低测试标准**
| 需求类型 | 最低测试要求 |
|----------|-------------|
| **code** | `go test` 或前端测试通过 + API 验证 + 截图验证 |
| **skill** | 关键词一致性 + 规则无歧义 + 边界情况(至少 3 项) |
| **ops** | 部署命令可执行 + 健康检查通过 |
## MCP 工具映射
| 命令 | MCP 工具 |
|------|----------|
| `/req` | `list_requirements` |
| `/req new` | `create_requirement` |
| `/req phase` | `get_requirement` + `get_requirement_tasks` |
| `/req next` | `advance_delivery_stage` + `create_stage_task` |
| `/req resume` | `get_requirement` + `get_requirement_tasks` |
| `/req dev` | `get_requirement` + `get_requirement_tasks` + `start_task_with_timer` |
| `/req cr` | `get_requirement_tasks` + Git diff |
| `/req test` | `req-test-gate` 5-Gate 流程 |
| `/req deploy` | Deploy Gates DG1-DG6 |
| `/req regression` | `git diff` + 回归套件 |
| `/req done` | 类型推断 + 检查清单 + `archive_requirement` |
| `/req review` | `submit_requirement` |
| `/req review pass` | `approve_requirement` |
| `/req link` | `link_tasks_to_requirement` |
## 环境选择
> **重要**:正式需求应直接在**生产环境** (`mcp__ai-proj-prod__*`) 创建。
> 仅在功能测试、流程验证时使用开发环境 (`mcp__ai-proj-dev__*`)。
> 开发环境同步到生产时,`due_date`、`reviewer_id`、`allow_self_approve` 等字段会丢失,需手动补充。
## Hook 自动同步
需求操作自动触发同步,无需手动执行:
| 事件 | 触发操作 |
|------|----------|
| `requirement.created` | 同步到远程 |
| `requirement.approved` | 同步需求和任务 |
| `task.completed` | 同步任务状态 |
| `requirement.archived` | 最终同步 + 思源笔记 |
**手动同步**
```typescript
mcp__ai-proj__sync_requirement_to_remote(requirementId)
mcp__ai-proj__batch_sync_tasks_to_remote(taskIds)
```
**同步已知限制**
| 字段 | 同步支持 | 说明 |
|------|----------|------|
| title, description, status, priority | ✅ | 正常同步 |
| **due_date** | ❌ | 不会同步,需手动补充 |
| reviewer_id | ❌ | 不会同步 |
| allow_self_approve | ❌ | 不会同步 |
## 思源笔记集成
归档时自动同步 5 阶段文档到思源笔记:
- 路径:`需求管理/REQ-XXXX/`
- 文档01-PRD.md ~ 05-生命周期总结.md
- 手动同步:`/req sync-siyuan [REQ-ID]`
## 相关技能 ## 相关技能
| 技能 | 用途 | | 技能 | 用途 |
|------|------| |------|------|
| `req-prd` | PRD 文档编写 + 评审方法论 | | `req-prd` | PRD 文档编写 + 评审方法论 |
| `dev-test` | 测试 + 质量门禁 | | `req-test-gate` | 测试 5-Gate + Deploy Gates |
| `req-dev` | PRD 到代码转换、开发计划 |

View File

@@ -1,177 +0,0 @@
# 测试环境流程指南
> 测试必须按照以下环境顺序依次进行,每个环境通过后才能进入下一个环境。
## 测试环境流程
```
[1] 本机环境 ─── 通过 ──→ [2] 预发布环境 ─── 通过 ──→ [3] 生产环境
│ │ │
↓ 失败 ↓ 失败 ↓ 失败
修复并重测 回到步骤[1] 回到步骤[1]
```
## 项目环境配置表
| 项目 | 本机环境 | 预发布环境 | 生产环境 |
|------|---------|-----------|---------|
| ai-proj | localhost:3000/8080 | staging.ai.pipexerp.com | ai.pipexerp.com |
| coolbuy-paas | localhost | fnos 测试环境 | 39.106.88.83:8888 |
| coolbuy-platform | localhost | fnos 测试环境 | 生产服务器 |
## 第一阶段:本机测试环境
> ⚠️ **关键约束**:本机测试必须全部通过,才能部署到 staging 环境。
**测试内容**
- 单元测试 - 测试单个函数/方法Mock 外部依赖
- 集成测试 - 测试模块间交互,使用测试数据库
- 功能验证 - 验证功能逻辑正确性
- **前端截图验证** - 使用 chrome-dev MCP 截图确认 UI 显示正确
### 后端测试
```bash
# Go 后端单元测试
go test ./... -v
# 指定模块测试
go test ./backend/handlers/... -v
go test ./backend/services/... -v
```
### 前端截图验证(⚠️ 必须步骤)
> **重要**:前端改动必须通过截图验证,不能只测后端 API。这一步经常被忽略导致功能未正确显示。
**验证流程**
1. **确保本机服务运行**
```bash
# 终端1后端
cd backend && go run main.go
# 终端2前端
cd frontend && npm start
```
2. **使用 chrome-dev MCP 截图验证**
```python
# 步骤1导航到目标页面
mcp__chrome-dev__navigate_page(url="http://localhost:3000/requirements/686")
# 步骤2等待页面加载完成可选
mcp__chrome-dev__wait_for(selector=".requirement-detail")
# 步骤3截图
mcp__chrome-dev__take_screenshot()
# 步骤4检查截图中功能是否正确显示
# - 新增的列/字段是否显示
# - 样式是否正确
# - 数据是否正确渲染
```
3. **常见验证场景**
| 改动类型 | 验证页面 | 检查项 |
|---------|---------|--------|
| 列表新增列 | 列表页面 | 新列是否显示、数据是否正确 |
| 表单新增字段 | 表单页面 | 字段是否显示、能否正常输入 |
| 样式调整 | 相关页面 | 样式是否生效、布局是否正确 |
| 权限控制 | 相关页面 | 按钮/菜单是否正确显示/隐藏 |
4. **截图保存**
- 截图应保存到测试任务文档中作为验证记录
- 命名规范:`REQ-XXXXX-本机测试-功能名称.png`
### 前端截图验证示例
```
/req test REQ-20260125-0002
→ 检查代码评审... ✓ 已完成
→ 验证开发任务... ✓ 已完成
=== 本机测试阶段 ===
1. 后端单元测试
→ go test ./backend/handlers/requirement_handler_test.go -v
→ ✓ 3/3 测试通过
2. 前端截图验证
→ 启动 chrome-dev MCP...
→ 导航到: http://localhost:3000/requirements/687
→ 截图验证...
→ ✓ 任务ID列正确显示 (#5284 格式)
→ ✓ 列宽度和样式正确
→ 截图已保存
=== 本机测试通过 ===
→ 可以执行: /req deploy REQ-20260125-0002 --env staging
```
### 通过标准
- [ ] 所有后端单元测试通过
- [ ] **前端截图验证通过**(有前端改动时必须)
- [ ] 功能在本地环境正常运行
- [ ] 无控制台错误
- [ ] 截图已保存到测试文档
### 跳过前端验证
仅当改动不涉及前端时,可使用 `--backend-only` 参数:
```bash
/req test REQ-XXXXX --backend-only
```
## 第二阶段:预发布环境
**测试内容**
- E2E 测试 - 测试完整用户流程
- 跨浏览器测试 - Chrome、Firefox、Safari
- 性能测试 - 页面加载时间、API 响应时间
**通过标准**
- [ ] 功能在预发布环境正常运行
- [ ] 与生产环境配置一致
- [ ] 无跨环境兼容性问题
## 第三阶段:生产环境
**测试内容**
- UAT 验收 - 用户验收测试
- 冒烟测试 - 核心功能快速验证
- 回归测试 - 确保未破坏现有功能
**通过标准**
- [ ] 功能在生产环境正常运行
- [ ] 用户验收通过
- [ ] 无生产环境特有问题
## API 验证清单
```bash
# 1. 本机环境
curl -s "http://localhost:8080/api/v1/requirements?search=REQ-2026" \
-H "Authorization: Bearer $TOKEN" | jq '.data | length'
# 2. 预发布环境
curl -s "https://staging.ai.pipexerp.com/api/v1/requirements?search=REQ-2026" \
-H "X-API-Key: $SYNC_REMOTE_API_KEY" | jq '.data | length'
# 3. 生产环境
curl -s "https://ai.pipexerp.com/api/v1/requirements?search=REQ-2026" \
-H "X-API-Key: $SYNC_REMOTE_API_KEY" | jq '.data | length'
```
## 测试失败处理
| 失败阶段 | 处理方式 |
|---------|---------|
| 本机测试 | 修复代码,重新运行本机测试 |
| 预发布测试 | 修复代码,重新从本机测试开始 |
| 生产环境测试 | 修复代码,重新从本机测试开始 |
> 任何阶段测试失败,修复后必须从本机测试环境重新开始。

View File

@@ -1,120 +0,0 @@
# 完整开发工作流示例
以「酷采3.0 标签管理模块」为例的完整需求生命周期。
## 第一步:创建需求
```bash
/req new 酷采3.0 商品标签管理模块
```
执行:`mcp__ai-proj__create_requirement` → 自动分配 display_id如 REQ-2026-0006
## 第二步:编写 PRD 文档
调用 `req-prd` 技能:
1. 创建 PRD 任务并关联到需求
2. 调用 `mcp__ai-proj__create-and-attach` 写入 PRD 文档
## 第三步:创建开发子任务
```python
# 创建子任务
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端:数据模型设计")
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端Store/Biz实现")
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端API Handler实现")
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="前端:页面开发")
# 批量关联到需求
mcp__ai-proj__link_tasks_to_requirement(requirementId=需求ID, taskIds=[...])
```
## 第四步:提交并审批需求
```bash
/req review # draft → pending
/req review pass # pending → approved
```
## 第五步:执行开发任务
```bash
/req dev REQ-2026-0006
```
按分层架构开发Model → Store → Biz → Handler → Router
## 第六步:代码评审
```bash
/req cr REQ-2026-0006
```
开发完成后必须进行代码评审,评审通过后才能进入测试。
## 第七步:创建测试任务
```python
mcp__ai-proj__create_subtask(parentId=测试父任务, title="后端:单元测试")
mcp__ai-proj__create_subtask(parentId=测试父任务, title="后端:集成测试")
mcp__ai-proj__create_subtask(parentId=测试父任务, title="E2E端到端测试")
mcp__ai-proj__create_subtask(parentId=测试父任务, title="UAT用户验收测试")
```
## 第八步:执行测试
```bash
/req test REQ-2026-0006
```
按环境顺序:本机 → 预发布 → 生产
## 第九步CI/CD 发布
```bash
/req deploy REQ-2026-0006 --env staging
```
## 第十步:完成归档
```bash
/req done REQ-2026-0006
```
自动生成需求生命周期总结文档,归档需求。
---
## 标准任务结构
```
需求: REQ-2026-XXXX
├── PRD 任务 (父任务,包含 PRD 文档)
│ ├── 后端:数据模型设计 (implementation)
│ ├── 后端:业务层实现 (implementation)
│ ├── 后端API 实现 (implementation)
│ └── 前端:页面开发 (implementation)
├── 代码评审任务 (code_review) ← 必须步骤
├── 测试任务 (父任务)
│ ├── 单元测试 (test)
│ ├── 集成测试 (test)
│ ├── E2E测试 (test)
│ └── UAT验收 (test, 包含测试报告)
└── 发布任务 (父任务,包含发布记录)
├── Docker 镜像构建 (deploy)
├── 前端资源构建 (deploy)
└── 部署到环境 (deploy)
```
## 5 阶段文档
| 序号 | 文档 | 阶段 |
|------|------|------|
| 01 | PRD | 需求定义 |
| 02 | 开发设计 | 开发实现 |
| 03 | 测试报告 | 测试验收 |
| 04 | 发布记录 | CI/CD部署 |
| 05 | 生命周期总结 | 归档 |

View File

@@ -1,6 +1,6 @@
--- ---
name: req-prd name: req-prd
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。 description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划、PRD 评审。当用户提到产品设计、PRD、需求文档、功能规划、用户故事、PRD 评审相关任务时自动激活。
--- ---
# 产品需求设计 Skill (req-prd) # 产品需求设计 Skill (req-prd)
@@ -657,3 +657,114 @@ mcp__ai-proj__export_task_document_to_file
- 数据安全分级 - 数据安全分级
- 敏感操作审计 - 敏感操作审计
- 权限最小化原则 - 权限最小化原则
---
## PRD 评审方法论
PRD 评审是需求流程的关键质量关卡。
### 评审流程
```
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
```
### 结构完整性检查
| 检查项 | 必须 | 说明 |
|--------|:----:|------|
| 基本信息 | ✓ | 编号、标题、日期、作者 |
| 需求背景 | ✓ | 为什么需要这个功能 |
| 目标用户 | ✓ | 面向的用户群体 |
| 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 |
| 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 界面布局 |
| 非功能需求 | ○ | 性能、安全 |
### 需求清晰度SMART 原则)
| 原则 | 检查点 |
|------|--------|
| **S**pecific | 描述是否具体明确 |
| **M**easurable | 是否有量化指标 |
| **A**chievable | 技术上是否可行 |
| **R**elevant | 是否与业务目标相关 |
| **T**ime-bound | 是否有时间范围 |
**示例**
- ❌ "用户可以搜索需求"
- ✅ "用户可按编号精确搜索、按标题模糊搜索、按状态筛选,结果分页显示"
### 技术可行性
| 维度 | 评估内容 |
|------|----------|
| 技术栈兼容 | 现有栈是否支持 |
| 架构影响 | 是否需修改架构 |
| 第三方依赖 | 是否引入新依赖 |
| 性能影响 | 潜在性能问题 |
| 安全考量 | 安全风险 |
### 数据模型验证
| 检查项 | 说明 |
|--------|------|
| 表结构 | 字段类型、约束、索引 |
| 关联关系 | 外键、多对多 |
| 命名规范 | 符合项目规范 |
| 扩展性 | 预留扩展字段 |
| 查询性能 | 常用查询有索引 |
### API 设计审查
| 检查项 | 标准 |
|--------|------|
| RESTful | URL 用名词HTTP 方法语义正确 |
| 响应格式 | `{success, data, message}` |
| 错误处理 | 明确的错误码 |
| 分页 | `?page=1&page_size=20` |
| 版本控制 | `/api/v1/...` |
### 评审结论模板
**通过**
```
✅ PRD 评审通过
【结论】文档完整,需求清晰,方案可行,建议批准。
【肯定】需求背景清晰、数据模型合理、API 规范
【建议】(非阻塞)补充性能测试用例
【评审人】xxx 【时间】2026-xx-xx
```
**驳回**
```
❌ PRD 评审驳回
【原因】
1. 数据模型缺少索引
2. API 缺少错误处理
3. 搜索需求描述模糊
【修改要求】
□ 补充索引设计
□ 明确错误码
□ 细化搜索实现
【驳回人】xxx 【时间】2026-xx-xx
```
### 常见驳回原因
| 类别 | 问题 | 建议 |
|------|------|------|
| 结构缺失 | 缺数据模型或 API | 补充技术设计 |
| 需求模糊 | 描述不具体 | 按 SMART 重写 |
| 边界不清 | 缺异常处理 | 补充边界条件 |
| 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 |

View File

@@ -1,8 +0,0 @@
{
"name": "req-review-plugin",
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,113 +0,0 @@
---
name: req-review
description: PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。
---
# PRD 评审方法论
PRD 评审是需求流程的关键质量关卡。
## 评审流程
```
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
```
## 结构完整性检查
| 检查项 | 必须 | 说明 |
|--------|:----:|------|
| 基本信息 | ✓ | 编号、标题、日期、作者 |
| 需求背景 | ✓ | 为什么需要这个功能 |
| 目标用户 | ✓ | 面向的用户群体 |
| 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 |
| 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 界面布局 |
| 非功能需求 | ○ | 性能、安全 |
## 需求清晰度SMART 原则)
| 原则 | 检查点 |
|------|--------|
| **S**pecific | 描述是否具体明确 |
| **M**easurable | 是否有量化指标 |
| **A**chievable | 技术上是否可行 |
| **R**elevant | 是否与业务目标相关 |
| **T**ime-bound | 是否有时间范围 |
**示例**
- ❌ "用户可以搜索需求"
- ✅ "用户可按编号精确搜索、按标题模糊搜索、按状态筛选,结果分页显示"
## 技术可行性
| 维度 | 评估内容 |
|------|----------|
| 技术栈兼容 | 现有栈是否支持 |
| 架构影响 | 是否需修改架构 |
| 第三方依赖 | 是否引入新依赖 |
| 性能影响 | 潜在性能问题 |
| 安全考量 | 安全风险 |
## 数据模型验证
| 检查项 | 说明 |
|--------|------|
| 表结构 | 字段类型、约束、索引 |
| 关联关系 | 外键、多对多 |
| 命名规范 | 符合项目规范 |
| 扩展性 | 预留扩展字段 |
| 查询性能 | 常用查询有索引 |
## API 设计审查
| 检查项 | 标准 |
|--------|------|
| RESTful | URL 用名词HTTP 方法语义正确 |
| 响应格式 | `{success, data, message}` |
| 错误处理 | 明确的错误码 |
| 分页 | `?page=1&page_size=20` |
| 版本控制 | `/api/v1/...` |
## 评审结论模板
**通过**
```
✅ PRD 评审通过
【结论】文档完整,需求清晰,方案可行,建议批准。
【肯定】需求背景清晰、数据模型合理、API 规范
【建议】(非阻塞)补充性能测试用例
【评审人】xxx 【时间】2026-xx-xx
```
**驳回**
```
❌ PRD 评审驳回
【原因】
1. 数据模型缺少索引
2. API 缺少错误处理
3. 搜索需求描述模糊
【修改要求】
□ 补充索引设计
□ 明确错误码
□ 细化搜索实现
【驳回人】xxx 【时间】2026-xx-xx
```
## 常见驳回原因
| 类别 | 问题 | 建议 |
|------|------|------|
| 结构缺失 | 缺数据模型或 API | 补充技术设计 |
| 需求模糊 | 描述不具体 | 按 SMART 重写 |
| 边界不清 | 缺异常处理 | 补充边界条件 |
| 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 |

View File

@@ -1,8 +0,0 @@
{
"name": "req-workflow-plugin",
"description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,198 +0,0 @@
---
name: req-workflow
description: 需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。
---
# 需求完整工作流
从 PRD 到归档的完整流程。
## 需求创建环境选择
> **重要**:正式需求应直接在**生产环境** (`mcp__ai-proj-prod__*`) 创建。
> 仅在功能测试、流程验证时使用开发环境 (`mcp__ai-proj-dev__*`)。
> 如果在开发环境创建了需求后同步到生产,`due_date`、`reviewer_id`、`allow_self_approve` 等字段会丢失,需手动补充。
## 完整流程概览(阶段化)
```
1. /req new → 创建需求 (draft)
2. req-prd 技能 → 编写 PRD创建【评审】PRD 任务)
3. /req review → 提交评审 (pending)
4. /req review pass → 评审通过 (approved, delivery_stage=analysis)
5. /req next → 推进到 design/dev 阶段
6. /req dev → 启动开发(创建【开发】任务, delivery_stage=dev
7. req-dev 技能 → 编写开发文档
8. /req next → 推进到 review 阶段
9. /req cr → 代码评审(创建【代码评审】任务, delivery_stage=review
10. /req next → 推进到 testing 阶段
11. /req test → 测试验收(创建【测试】任务, delivery_stage=testing
12. /req next → 推进到 staging 阶段
13. /req deploy staging → 部署 staging创建【部署】任务, delivery_stage=staging
14. /req next → 推进到 released 阶段
15. /req deploy prod → 部署生产(创建【部署】任务, delivery_stage=released
16. /req done → 归档 (archived)
```
**每个阶段都有明确的任务、检查点和交付物,防止遗漏。**
## 5 阶段文档
| 阶段 | 文档名 | 技能 |
|------|--------|------|
| PRD | 01-PRD.md | `req-prd` |
| 开发 | 02-开发设计.md | `req-dev` |
| 测试 | 03-测试报告.md | 自动生成 |
| 发布 | 04-发布记录.md | 自动生成 |
| 归档 | 05-生命周期总结.md | 自动生成 |
## Hook 自动同步
需求操作自动触发同步,无需手动执行:
| 事件 | 触发操作 |
|------|----------|
| `requirement.created` | 同步到远程 |
| `requirement.approved` | 同步需求和任务 |
| `task.completed` | 同步任务状态 |
| `requirement.archived` | 最终同步 + 思源笔记 |
**手动同步**(如需):
```typescript
mcp__ai-proj__sync_requirement_to_remote(requirementId)
mcp__ai-proj__batch_sync_tasks_to_remote(taskIds)
```
**同步已知限制**
| 字段 | 同步支持 | 说明 |
|------|----------|------|
| title, description, status, priority | ✅ | 正常同步 |
| project_id | ✅ | 正常同步 |
| **due_date** | ❌ | **不会同步**,需手动通过 REST API 在目标环境补充 |
| reviewer_id | ❌ | 不会同步 |
| allow_self_approve | ❌ | 不会同步 |
> **经验教训**2026-02-20`sync_requirement_to_remote` 不同步 `due_date` 字段。同步后务必在目标环境验证并手动补充缺失字段。
## 测试环境流程
**必须按顺序执行,任何阶段失败后从本机重新开始**
```
[本机] → 通过 → [预发布] → 通过 → [生产]
↑ │ │
└─────────────────┴──── 失败 ────┘
```
| 环境 | 用途 | 验证方式 |
|------|------|----------|
| 本机 | 开发调试 | `go test ./...` |
| 预发布 | 集成测试 | API 验证 |
| 生产 | 最终验收 | API + 功能验证 |
## 任务关联规范
创建任务时设置 `link_role` 并加阶段前缀:
| link_role | 阶段前缀 | 所属阶段 | 权重 |
|-----------|----------|----------|------|
| prd | 【评审】 | analysis | 10% |
| design | 【评审】 | design | 5% |
| implementation | 【开发】 | dev | 50% |
| code_review | 【代码评审】 | review | 5% |
| test | 【测试】 | testing | 15% |
| deploy | 【部署】 | staging/released | 10% |
| documentation | 【文档】 | any | 5% |
**进度计算**:按 link_role 权重统计已完成任务。
## 标准任务结构(阶段化)
```
需求 REQ-xxx
├── 📝 analysis 阶段
│ └── 【评审】PRD: {需求标题} (linkRole: prd)
├── 📐 design 阶段
│ └── 【评审】技术设计: {需求标题} (linkRole: design)
├── 💻 dev 阶段
│ ├── 【开发-后端】{描述} (linkRole: implementation)
│ └── 【开发-前端】{描述} (linkRole: implementation)
├── 🔍 review 阶段
│ └── 【代码评审】CR: {需求标题} (linkRole: code_review)
├── 🧪 testing 阶段
│ └── 【测试】集成测试: {需求标题} (linkRole: test)
├── 🚀 staging 阶段
│ └── 【部署】部署到 staging (singapore) (linkRole: deploy)
└── 🏁 released 阶段
├── 【部署】部署到 prod (tools_ai_proj) (linkRole: deploy)
└── 【验收】功能验收确认 (linkRole: documentation)
```
**命名规则**:所有任务标题必须以阶段前缀开头(如【评审】、【开发】、【部署】)。
## 环境配置
**双环境 MCP 配置**:区分开发测试和生产环境
```json
// ~/.claude/.mcp.json
{
"mcpServers": {
"ai-proj-dev": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "http://localhost:8080/api/v1",
"TASK_API_TOKEN": "aiproj_pk_xxx...",
"NODE_ENV": "development"
}
},
"ai-proj-prod": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_xxx...",
"NODE_ENV": "production"
}
}
}
}
```
**环境使用指南**
| 环境 | 使用场景 | 工具前缀 |
|------|----------|----------|
| `ai-proj-dev` | 功能测试、流程验证、本地调试 | `mcp__ai-proj-dev__*` |
| `ai-proj-prod` | 正式需求管理、生产数据操作 | `mcp__ai-proj-prod__*` |
**跨机器支持**
- `ai-proj-dev` 支持 melbourne 和 adelaide 机器的本地环境(都是 localhost:8080
- 无论在哪台开发机器上,都使用 `ai-proj-dev` 连接本地 API
**项目配置**
```json
// .claude/settings.local.json
{
"env": {
"REQUIREMENT_PROJECT": "coolbuy-paas"
}
}
```
## 思源笔记集成
归档时自动同步 5 阶段文档到思源笔记:
- 路径:`需求管理/REQ-XXXX/`
- 文档01-PRD.md ~ 05-生命周期总结.md
手动同步:`/req sync-siyuan [REQ-ID]`
## 邮件通知
发送邮件:`/req notify [REQ-ID] --type <prd|dev|test|deploy|archive>`
默认收件人:项目邮件组(见项目配置)

View File

@@ -1,8 +0,0 @@
{
"name": "requirement-plugin",
"description": "[已废弃] 需求撰写功能已合并到 req-plugin。请使用 /req 命令。",
"version": "2.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -1,30 +0,0 @@
---
name: requirement
description: "[已废弃] 请使用 /req 命令。需求撰写功能已合并到 req 技能中。"
arguments: <subcommand> [args]
---
# Requirement 技能 - 已合并到 req
> **此技能已废弃。** 所有需求撰写命令已合并到 `req` 技能中。
## 命令迁移对照
| 原命令 | 新命令 | 说明 |
|--------|--------|------|
| `/requirement new` | `/req new` | 对话式创建需求(仅创建草稿) |
| `/requirement draft <描述>` | `/req draft <描述>` | 快速生成需求草稿 |
| `/requirement edit <ID>` | `/req edit <ID>` | 编辑需求内容 |
| `/requirement review <ID>` | `/req check <ID>` | 需求完整性检查 |
| `/requirement split <ID>` | `/req split <ID>` | 拆分为开发任务 |
| `/requirement history <ID>` | `/req history <ID>` | 查看变更历史 |
| `/requirement compare <ID>` | `/req compare <ID>` | 版本对比 |
| `/requirement list` | `/req``/req list` | 列出需求 |
## 重要变更
- 需求创建后**只能是 draft 状态**,禁止自动提交
- 从 draft 到提交评审需通过 **4 道门禁**(讨论 → 确认 → PRD → 完整性检查)
- 提交评审使用 `/req submit`(原 `/req review`
请使用 `/req` 命令,详细参考见 `req``req-commands` 技能。

View File

@@ -1,124 +0,0 @@
#!/bin/bash
# Sync local skills to marketplace plugins
# Usage: ./sync-skills.sh [marketplace-dir]
set -e
# Configuration
LOCAL_SKILLS_DIR="$HOME/.claude/skills"
MARKETPLACE_DIR="${1:-$(dirname "$0")}"
PLUGINS_DIR="$MARKETPLACE_DIR/skills"
echo "🔄 Syncing skills to marketplace..."
echo "Source: $LOCAL_SKILLS_DIR"
echo "Target: $PLUGINS_DIR"
echo ""
# Check if local skills directory exists
if [ ! -d "$LOCAL_SKILLS_DIR" ]; then
echo "❌ Error: Local skills directory not found: $LOCAL_SKILLS_DIR"
exit 1
fi
# Track changes
new_count=0
updated_count=0
unchanged_count=0
# Loop through each local skill
for skill_dir in "$LOCAL_SKILLS_DIR"/*; do
# Skip non-directories and special files
if [ ! -d "$skill_dir" ] || [ "$(basename "$skill_dir")" = ".git" ]; then
continue
fi
# Skip registry.yaml if it exists as a directory
if [ "$(basename "$skill_dir")" = "registry.yaml" ]; then
continue
fi
skill_name=$(basename "$skill_dir")
plugin_name="${skill_name}-plugin"
plugin_dir="$PLUGINS_DIR/$plugin_name"
# Check if SKILL.md exists
if [ ! -f "$skill_dir/SKILL.md" ]; then
echo "⚠️ Skipping $skill_name (no SKILL.md)"
continue
fi
# Check if plugin already exists
if [ -d "$plugin_dir" ]; then
# Compare SKILL.md files
if diff -q "$skill_dir/SKILL.md" "$plugin_dir/skills/SKILL.md" > /dev/null 2>&1; then
echo "$skill_name (unchanged)"
((unchanged_count++))
else
echo "📝 $skill_name (updated)"
cp "$skill_dir/SKILL.md" "$plugin_dir/skills/"
((updated_count++))
fi
else
echo " $skill_name (new)"
# Create plugin directory structure
mkdir -p "$plugin_dir/.claude-plugin"
mkdir -p "$plugin_dir/skills"
# Copy SKILL.md
cp "$skill_dir/SKILL.md" "$plugin_dir/skills/"
# Extract description from SKILL.md frontmatter
description=$(grep "^description:" "$skill_dir/SKILL.md" | sed 's/^description: *//' | tr -d '\n\r')
if [ -z "$description" ]; then
description="Plugin for $skill_name"
fi
# Create plugin.json
cat > "$plugin_dir/.claude-plugin/plugin.json" << EOF
{
"name": "$plugin_name",
"description": "$description",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}
EOF
((new_count++))
fi
done
echo ""
echo "📊 Summary:"
echo " New: $new_count"
echo " Updated: $updated_count"
echo " Unchanged: $unchanged_count"
echo ""
# Regenerate marketplace.json if there are changes
if [ $new_count -gt 0 ] || [ $updated_count -gt 0 ]; then
echo "🔄 Regenerating marketplace.json..."
cd "$MARKETPLACE_DIR"
# Run the generate script if it exists
if [ -f "generate-marketplace.py" ]; then
python3 generate-marketplace.py
else
echo "⚠️ Warning: generate-marketplace.py not found, skipping marketplace.json regeneration"
fi
echo ""
echo "✅ Sync complete! Changes ready to commit."
echo ""
echo "Next steps:"
echo " cd $MARKETPLACE_DIR"
echo " git status"
echo " git add ."
echo " git commit -m 'Sync skills from local'"
echo " git push"
else
echo "✅ All plugins are up to date!"
fi