skills/deploy/SKILL.md
# SKILL: deploy ## CLI Bootstrap 在执行任何 `harnessctl` 命令前,先解析本地 CLI 路径: ```bash if [ -z "${HARNESSCTL:-}" ]; then candidates=( "./stage-harness/scripts/harnessctl" "../stage-harness/scripts/harnessctl" "$(git rev-parse --show-toplevel 2>/dev/null)/stage-harness/scripts/harnessctl" ) for candidate in "${candidates[@]}"; do if [ -n "$candidate" ] && [ -x "$candidate" ]; then HARNESSCTL="$candidate" break fi done fi test -n "${HARNESSCTL:-}" && test -x "$H
npx skillsauth add LUAgam/stage-harness skills/deployInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
在执行任何 harnessctl 命令前,先解析本地 CLI 路径:
if [ -z "${HARNESSCTL:-}" ]; then
candidates=(
"./stage-harness/scripts/harnessctl"
"../stage-harness/scripts/harnessctl"
"$(git rev-parse --show-toplevel 2>/dev/null)/stage-harness/scripts/harnessctl"
)
for candidate in "${candidates[@]}"; do
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
HARNESSCTL="$candidate"
break
fi
done
fi
test -n "${HARNESSCTL:-}" && test -x "$HARNESSCTL" || {
echo "harnessctl not found. Set HARNESSCTL=/abs/path/to/stage-harness/scripts/harnessctl" >&2
exit 1
}
DEPLOY 阶段部署执行技能。将整个大项目(含所有需要部署的子项目)完整启动,为后续 E2E 测试提供运行环境。支持多子项目结构,每个子项目独立推断部署方式,不需要部署的子项目可标记跳过。
DEPLOY/stage-harness:harness-deploy 命令一个大项目可能由多个子项目构成(后端、前端、知识库、worker 等),每个子项目有自己的部署方式,部分子项目不需要部署(如纯静态知识库、文档站)。
project-profile.yaml 中用 sub_projects 列表描述各子项目的部署配置,每项包含以下字段:
name:子项目标识(唯一)path:相对于 PROJECT_ROOT 的路径deploy_command:部署命令(skip 时为空)deploy_type:部署类型(custom-script / docker-compose / node / k8s / makefile / cloud-platform)skip:true 表示不需要部署skip_reason:跳过原因(可选)workspace_mode: multi-repo 时强制走子项目扫描逻辑;单仓项目(workspace_mode: single-repo 或未设置)退化为单子项目,行为与旧版一致。
在任何推断之前,先探测当前环境的工具可用性,供后续所有子项目推断使用:
docker compose(插件形式)vs docker-compose(独立二进制),记录实际可用形式node / npm / yarn / pnpm 可用性kubectl / make / flyctl / vercel / heroku 可用性PROJECT_ROOT(当前工作目录绝对路径)输出环境探测摘要:
[ENV] PROJECT_ROOT: /abs/path/to/project
[ENV] docker compose: docker compose(插件形式)
[ENV] node: 18.x yarn: 1.22.x
对每个子项目依次执行以下四级推断链,得到该子项目的 deploy_command。
读取 project-profile.yaml 中的 sub_projects 列表:
skip: false 且 deploy_command 非空的子项目直接使用已有命令,跳过后续推断兼容旧格式:若只有顶层 deploy_command(无 sub_projects),将其视为单子项目,name = "main",path = "."。
扫描目标:PROJECT_ROOT 下的所有直接子目录(深度 = 1),以及根目录本身。
对每个候选目录,按以下优先级推断其部署方式:
bin/ 或 scripts/ 下含 start / deploy / ctl / run / up 关键词的可执行脚本docker-compose.yml / docker-compose.yaml(含 config/、deploy/ 子目录)k8s/ / kubernetes/ / manifests/ 目录(需 kubectl 可用)fly.toml / vercel.json / Procfile)Makefile 含 deploy targetpackage.json 含 start / dev / serve script(前端/Node 服务)Dockerfile(兜底,生成 build + run 命令)跳过判断:若某子目录不含任何上述特征文件,且不是根目录,则将该子项目标记为 skip: true,并记录 skip_reason: "未发现部署特征文件"。
生成命令规则:
PROJECT_ROOT)package.json)优先使用项目自身的包管理器(yarn / pnpm / npm)扫描完成后,将结果写入 project-profile.yaml 的 sub_projects 字段持久化,并输出扫描摘要(格式:✔ name (path) → command [type] 或 ⊘ name (path) → 跳过(原因))。
Level 2 扫描完成后,对每个 skip: false 的子项目执行本地可部署性检查:
deploy_command 所依赖的工具在 Step 0 探测中均可用docker-compose.yml 存在且 docker daemon 可达判定规则:
不可本地部署时的用户提示:
以下子项目在当前环境无法本地部署:
[1] backend → 缺少: docker daemon 不可达
[2] frontend → 通过(本地可部署)
是否需要远程部署不可用的子项目?
A. 提供远程服务器信息(SSH)进行远程部署
B. 为该子项目提供替代的本地命令
C. 将该子项目标记为跳过
D. 全部跳过,直接进入 E2E
用户选择远程部署时,收集该子项目的 SSH 连接信息(host / user / auth / project_path / service_type),写入对应子项目的 remote_deploy 配置块。
用户确认后将最终配置写回 project-profile.yaml。
对每个 skip: false 的子项目,在执行前检查其部署脚本和配置文件:
PROJECT_ROOT 下找到同名相对路径并替换;docker compose 命令形式与探测结果不一致时统一替换KEY = value 格式;检测并清空不可达的代理 URL修改前自动备份(*.preflight.bak),修复记录写入 receipt 的 fixes_applied 字段。
对 sub_projects 列表中所有 skip: false 的子项目,按列表顺序依次部署(后端通常先于前端,因为前端可能依赖后端服务):
[1/2] 部署 backend ...
[2/2] 部署 frontend ...
每个子项目:
deploy_command,捕获 stdout / stderr / exit_codeskip: true 的子项目直接记录为 SKIPPED,不执行任何命令。
当部署命令本身成功(exit_code=0)但服务随后崩溃或健康检查失败时,必须自主执行诊断-修复-重试循环,不得中断等待用户。此循环最多执行 3 轮。
以下任一情况触发自动恢复:
诊断 → 分类 → 修复 → 重试 → 验证
1. 诊断(自主执行,不中断):
2. 分类:将错误归入以下类别之一:
| 类别 | 特征模式 | 处理方式 | |------|---------|---------| | 环境配置 | connection refused(外部依赖)、proxy/DNS 不可达、env variable missing、invalid URL/host | 修复配置文件后重试 | | 端口冲突 | address already in use、port occupied | 释放端口或偏移端口后重试 | | 权限问题 | permission denied、access denied、EACCES | 修复文件权限后重试 | | 依赖服务未就绪 | connection refused(内部依赖如 DB/Redis)、timeout waiting for | 等待依赖服务就绪后重试 | | 代码逻辑错误 | import error、syntax error、type error、未归入上述类别的异常 | 标记为代码问题,终止恢复循环 |
3. 修复(仅配置类问题):
fixes_applied,标明文件、原值、新值、原因4. 重试:
5. 验证:
| 条件 | 结果 | |------|------| | 健康检查通过 | 标记 PASS | | 错误分类为"代码逻辑错误" | 立即终止循环,标记 FAIL | | 达到 3 轮上限仍未恢复 | 标记 FAIL | | 连续两轮相同错误且修复无效 | 升级为代码问题,标记 FAIL |
fixes_applied,确保可审计部署失败或服务状态验证失败时,对失败的子项目自动采集日志,策略与部署类型对应(docker compose logs / journalctl / pm2 logs / kubectl logs 等)。
写入路径:.harness/features/<epic-id>/deploy-receipt.json
{
"epic_id": "<epic-id>",
"status": "PASS | FAIL | SKIPPED",
"started_at": "<iso8601>",
"completed_at": "<iso8601>",
"sub_projects": [
{
"name": "<子项目名>",
"path": "<相对路径>",
"deploy_command": "<cmd>",
"deploy_type": "<type>",
"detected_by": "config | auto-detect | user-input | skipped",
"status": "PASS | FAIL | SKIPPED",
"exit_code": 0,
"service_status": "<验证结果>",
"stdout": "<最后200行>",
"error_summary": "",
"remote_logs": "",
"fixes_applied": []
}
],
"failed_sub_projects": ["<name>"],
"skipped_sub_projects": ["<name>"]
}
整体 status:所有需部署子项目均 PASS → PASS;任一 FAIL → FAIL;全部 SKIPPED → SKIPPED。
✅ DEPLOY PASS
后端 (backend): PASS [custom-script] 耗时 45s
前端 (frontend): PASS [node] 耗时 12s
知识库: SKIPPED(无需部署)
产物: .harness/features/<epic-id>/deploy-receipt.json
❌ DEPLOY FAIL
后端 (backend): PASS
前端 (frontend): FAIL (exit_code=1)
错误摘要: <error_summary>
=== 日志 ===
<前50行>
产物: .harness/features/<epic-id>/deploy-receipt.json
| 条件 | 说明 | |------|------| | 任一子项目部署退出码非 0 | 写 FAIL receipt,停止后续子项目,触发 FIX | | 任一子项目服务状态验证失败 | 写 FAIL receipt(含日志),触发 FIX | | 任一子项目部署超时(> 60 分钟) | 写 FAIL receipt(timeout),触发 FIX | | Level 3 预算耗尽且仍有未确认子项目 | 终止,提示手动配置 sub_projects | | 写 receipt 失败 | 报告 IO 错误,终止 |
所有子项目均 SKIPPED 视为正常(用户主动选择),推进 E2E。
-o StrictHostKeyChecking=accept-newdevelopment
在 generate-test-cases 阶段之后执行,逐个验证测试用例并在失败时修复项目代码、重新编译部署、再次验证, 直到通过或达到最大修复次数。覆盖 UI / API / API+UI / 性能测试四个维度,UI 测试通过浏览器真实模拟用户操作并截图, API 测试根据项目代码生成可执行的接口脚本,性能测试调用现有性能/质量技能全量执行。 涉及真实用户登录信息(如手机号+验证码、账号密码、JWT)时必须中断要求用户提供,禁止编造无效凭证。 所有 case 状态变更必须通过 e2e-case-tracker.sh 脚本持久化,确保中途崩溃可恢复、无 case 遗漏。
development
# SKILL: e2e > **核心原则**: > 1. 测试范围跟着本次变动走。后端接口改了,对应的前端流程必须做联调验证;与本次需求无关的功能不测。对于涉及算法、转换准确率等质量敏感型需求,需额外生成专项质量测试。 > 2. **覆盖完整性优先于执行便利性**。不得以"链路复杂"、"需要外部依赖"为由跳过本次变动相关的用例;凡是受变动影响的接口和 UI 流程,都必须生成真实调用/操作用例。 > 3. **UI 测试必须模拟真实用户操作**(定位元素、点击、键入、等待渲染、断言可见文本/状态)。**禁止**将 UI 套件退化为浏览器上下文里的 `page.evaluate(fetch(...))` API 验证——那只是把 API 测试换了执行环境,没有额外价值,不算 UI 测试。 > 4. **通用性**:本 skill 不假设具体业务域,所有规则均以抽象变动面(文件、接口、页面、用户动作)为单位组织,不针对任何特定项目的数据库/领域词汇。 > 5. **E2E 套件必须验证运行时行为**。严禁把"读取源码/配置文件并做字符串/结构匹配"的检查封装成独立 E2E 套件——这类检
tools
# SKILL: build ## CLI Bootstrap 在执行任何 `harnessctl` 命令前,先解析本地 CLI 路径: ```bash if [ -z "${HARNESSCTL:-}" ]; then candidates=( "./stage-harness/scripts/harnessctl" "../stage-harness/scripts/harnessctl" "$(git rev-parse --show-toplevel 2>/dev/null)/stage-harness/scripts/harnessctl" ) for candidate in "${candidates[@]}"; do if [ -n "$candidate" ] && [ -x "$candidate" ]; then HARNESSCTL="$candidate" break fi done fi test -n "${HARNESSCTL:-}" && test -x "$HA
tools
# SKILL: feedback-triage ## CLI Bootstrap ```bash test -n "${HARNESSCTL:-}" && test -x "$HARNESSCTL" || { echo "ERROR: HARNESSCTL 环境变量未设置或不可执行。请先执行: export HARNESSCTL=/path/to/stage-harness/scripts/harnessctl" >&2 exit 1 } ``` --- ## 概述 Feedback Triage Council 调度技能。当 stage-reminder hook 自动提交 feedback 后, 本 skill 负责完整执行多 agent 评审流程,决定是否 reopen 及返回哪个阶段。 --- ## 触发条件 - stage-reminder.sh 检测到 feedback_candidate 并自动提交 HFB-xxx - additionalContext 注入 `[Feedback - AUTO SUBMITTED]` 指令 - 也可手动触发