diff --git a/AGENTS.md b/AGENTS.md index 1b80b2f..de05e0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -63,14 +63,14 @@ AGENTS.md # 本文档 | [previewer](skills/previewer/README.md) | 用 Node 提供 HTML/静态文件预览,返回 URL 并复用已有服务 | | [pr-ship](skills/pr-ship/README.md) | 把已有 PR 从检查、合并推进到回归、构建和部署 | | [releaser](skills/releaser/README.md) | 给已准备好的 commit 发版本:更新说明、tag、可选 Forge Release | -| [ship](skills/ship/README.md) | short-ship / long-ship / pr-ship 共用的交付记录格式 | -| [short-ship](skills/short-ship/README.md) | 范围清楚的单次变更:小功能、文案、已确认 bug,一直交到停点 | -| [long-ship](skills/long-ship/README.md) | 复杂需求:specifier PRD 批准后拆任务、集成回归并交付 | -| [specifier](skills/specifier/README.md) | 把复杂需求整理成多轮评审的 HTML PRD,批准后交给 long-ship | -| [delivery-loop](skills/delivery-loop/README.md) | 三个交付入口共用的验证到部署状态机 | +| [ship](skills/ship/README.md) | 把一次变更从说明推进到配置允许的 PR、合并或部署;short 或 long | +| [short-ship](skills/short-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [long-ship](skills/long-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [specifier](skills/specifier/README.md) | 把复杂需求整理成多轮评审的 HTML PRD,批准后交给 ship | +| [delivery-loop](skills/delivery-loop/README.md) | ship 与 pr-ship 共用的验证到部署状态机 | | [manage-release](skills/manage-release/README.md) | 已弃用:`releaser` 的旧名兼容占位,不含流程 | -| [bugfix-ship](skills/bugfix-ship/README.md) | 已弃用:`short-ship` 的旧名兼容占位,不含流程 | -| [requirement-flow](skills/requirement-flow/README.md) | 已弃用:`long-ship` 的旧名兼容占位,不含流程 | +| [bugfix-ship](skills/bugfix-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [requirement-flow](skills/requirement-flow/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | 改名后旧名保留一个纯占位 skill,避免已装软链悬空和旧项目 `.pouch.yaml` 失效。确认没有 项目再按旧名启用后,删除对应占位目录即可,不丢任何内容。 diff --git a/README.md b/README.md index 651bd8a..973ade4 100644 --- a/README.md +++ b/README.md @@ -99,14 +99,14 @@ AGENTS.md # 详细规范与架构说明 | [previewer](skills/previewer/README.md) | 用 Node 提供 HTML/静态文件预览,返回 URL 并复用已有服务 | | [pr-ship](skills/pr-ship/README.md) | 把已有 PR 从检查、合并推进到回归、构建和部署 | | [releaser](skills/releaser/README.md) | 给已准备好的 commit 发版本:更新说明、tag、可选 Forge Release | -| [ship](skills/ship/README.md) | short-ship / long-ship / pr-ship 共用的交付记录格式 | -| [short-ship](skills/short-ship/README.md) | 范围清楚的单次变更:小功能、文案、已确认 bug | -| [long-ship](skills/long-ship/README.md) | 复杂需求:PRD 批准后拆任务、集成回归并交付 | -| [specifier](skills/specifier/README.md) | 把复杂需求整理成多轮评审的 HTML PRD,批准后交给 long-ship | -| [delivery-loop](skills/delivery-loop/README.md) | 三个交付入口共用的验证到部署状态机 | +| [ship](skills/ship/README.md) | 把一次变更从说明推进到配置允许的 PR、合并或部署;short 或 long | +| [short-ship](skills/short-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [long-ship](skills/long-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [specifier](skills/specifier/README.md) | 把复杂需求整理成多轮评审的 HTML PRD,批准后交给 ship | +| [delivery-loop](skills/delivery-loop/README.md) | ship 与 pr-ship 共用的验证到部署状态机 | | [manage-release](skills/manage-release/README.md) | 已弃用:`releaser` 的旧名兼容占位,不含流程 | -| [bugfix-ship](skills/bugfix-ship/README.md) | 已弃用:`short-ship` 的旧名兼容占位,不含流程 | -| [requirement-flow](skills/requirement-flow/README.md) | 已弃用:`long-ship` 的旧名兼容占位,不含流程 | +| [bugfix-ship](skills/bugfix-ship/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | +| [requirement-flow](skills/requirement-flow/README.md) | 已弃用:`ship` 的旧名兼容占位,不含流程 | ACK 是包含规范、模板与校验脚本的完整 Skill。安装后可初始化当前项目状态: diff --git a/skills/ack/README.md b/skills/ack/README.md index 65c912e..176e277 100644 --- a/skills/ack/README.md +++ b/skills/ack/README.md @@ -18,8 +18,8 @@ ACK 是显式调用的 Agent Skill,用三种独立角色跑工程协作闭环 | --- | --- | --- | | 初始化 | `/ack 初始化` | 生成并补全 `.pouch/ack/`;缺项按统一格式列出 | | 检查 | `/ack 检查配置` | 只读校验,默认不改文件;测试环境缺 deployer 时转交 | -| 做需求 | `/ack 处理这个需求:…` | 先建 ship 记录;复杂需求走 specifier / long-ship,小改动走 short-ship | -| 修 bug | `/ack 修这个 bug:…` 或处理飞书收件 | 短描述 + 验收 → 你确认(飞书须你点「已确认」)→ 缺陷板闭环,交付链接 short-ship | +| 做需求 | `/ack 处理这个需求:…` | 先建 ship 记录;复杂需求走 specifier / ship long 模式,小改动走 ship | +| 修 bug | `/ack 修这个 bug:…` 或处理飞书收件 | 短描述 + 验收 → 你确认(飞书须你点「已确认」)→ 缺陷板闭环,交付链接 ship | | 交付配置 | 说明怎么布测试环境 / 怎么发版 | 写入同一份 `delivery.yaml`;测试环境绑定 deployer | | 运行测试环境 | `/ack 重新布测试环境` | 内部加载 deployer,布 `.pouch/deployer/` | | 运行版本发布 | `/ack 发布一个版本` | 按 `intents.release`;stable/生产仍要单独批准 | diff --git a/skills/ack/SKILL.md b/skills/ack/SKILL.md index afd762c..1dad70f 100644 --- a/skills/ack/SKILL.md +++ b/skills/ack/SKILL.md @@ -109,8 +109,8 @@ python3 /scripts/record_task.py .pouch/ack/tasks.yaml \ 1. `.pouch/ack` 不存在:停止并建议先 `/ack` 初始化;不要静默初始化。 2. 读 `project.md`;若存在 `agents.yaml`,先用 `validate_agents.py` 校验并读取其 `defaults`;用 `select_tasks.py`(已知任务加 `--task-id`)和 `select_knowledge.py` 取当前任务相关 `active` 条目。超预算时缩小选择,不回退为完整 yaml。 3. 新需求或尚未确认的计划:读 [kickoff.md](references/kickoff.md)。范围清楚的小改动转 - `short-ship`;复杂需求转 `specifier` / `long-ship`。修 bug 写短问题说明、复现和可观测 - 验收,不写大 PRD;要交付时链接 `short-ship`。 + `ship`;复杂需求转 `specifier` 或 `ship` long 模式。修 bug 写短问题说明、复现和可观测 + 验收,不写大 PRD;要交付时链接 `ship`。 4. 用户已确认后,先读取并按 [closed-loop.md](references/closed-loop.md) 执行;使用 Orca 时同时读取 [orca-adapter.md](references/orca-adapter.md)。当前会话担任 Coordinator,不亲自写代码或跑测试;worker profile 按 `agents.yaml`(若存在)否则按任务板配置选择。 这不是 fire-and-forget:Coordinator 不得在 `launch` / `dispatch` 后只回复“已派发”并结束当前会话。每个任务都必须在同一轮持续执行默认 60 秒窗口的 `check --wait`,并按 60–120 秒节奏运行 `worker_probe.py`,直到 Developer 回报 `worker_done` 或 `escalation`;随后写回 `fixed_by_dev`,主动派发 Test,并继续等待 `retest_result`。只有完成 Test 终检、重试/`leftover` 决策、回归决定和 worker 回收后,才可以结束本轮 ACK。 5. 存在 `project.bugIntake` 时先完成「飞书收件」。创建或更换 worker 走「启动 worker」。若 `intents.testEnvironment` 已启用,派 Test 前先走「运行测试环境」。 diff --git a/skills/ack/references/kickoff.md b/skills/ack/references/kickoff.md index d0c63df..5fd1af8 100644 --- a/skills/ack/references/kickoff.md +++ b/skills/ack/references/kickoff.md @@ -4,7 +4,7 @@ 用户确认后的三角色闭环、飞书收件、启动 worker、交付和回归由 `SKILL.md` 按条件加载, 不要在本文件开头预读其它规范。 -复杂需求的规格和任务写在 `.pouch/ship//`(specifier + long-ship)。ACK 任务板 +复杂需求的规格和任务写在 `.pouch/ship//`(specifier + ship long 模式)。ACK 任务板 只收缺陷。显式 `/ack` 做功能需求时也先建 ship 记录,不要把功能任务写成 `type: bug`。 --- diff --git a/skills/bugfix-ship/README.md b/skills/bugfix-ship/README.md index a1f2045..515295c 100644 --- a/skills/bugfix-ship/README.md +++ b/skills/bugfix-ship/README.md @@ -1,8 +1,8 @@ # bugfix-ship(已弃用) -`bugfix-ship` 已改名为 [short-ship](../short-ship/README.md)。本目录只是兼容占位, +`bugfix-ship` 已并入 [ship](../ship/README.md)。本目录只是兼容占位, 让旧项目里的 `.pouch.yaml`、已经装好的旧软链和旧说法不至于失效;真正的说明和流程都在 -`short-ship/`。 +`ship/`。命中后按 **short 模式** 执行。 ## 使用示例 @@ -10,15 +10,15 @@ 使用 bugfix-ship,修复这个线上回归并部署到测试环境。 ``` -Agent 命中后会立刻转到 `short-ship`,按同一套规则执行。新请求建议直接用新名。 +Agent 命中后会立刻转到 `ship`,按 short 模式执行。新请求建议直接用 `ship`。 ## 迁移 ```bash -pouch add short-ship # 新名,当前项目 -pouch add short-ship -g # 新名,全局 +pouch add ship # 新名,当前项目 +pouch add ship -g # 新名,全局 ``` - 旧软链保持有效,不需要先删除。 -- 各项目 `.pouch.yaml` 里的 `bugfix-ship` 可以分批改成 `short-ship`。 +- 各项目 `.pouch.yaml` 里的 `bugfix-ship` 可以分批改成 `ship`。 - 确认没有项目再按旧名启用后,删除本目录即可;它是纯占位,删除不丢内容。 diff --git a/skills/bugfix-ship/SKILL.md b/skills/bugfix-ship/SKILL.md index 04e0fbf..bf94875 100644 --- a/skills/bugfix-ship/SKILL.md +++ b/skills/bugfix-ship/SKILL.md @@ -1,19 +1,19 @@ --- name: bugfix-ship description: >- - 【已弃用,兼容占位】bugfix-ship 已改名为 short-ship。命中本 skill 时不要在此执行任何 - 流程,直接读取 ../short-ship/SKILL.md 并按其执行。小需求、小改动、修 bug、改文案、 - 加按钮、修复后发 PR 或部署都属于 short-ship。 + 【已弃用,兼容占位】bugfix-ship 已并入 ship。命中本 skill 时不要在此执行任何 + 流程,直接读取 ../ship/SKILL.md 并按其执行;本次按 short 模式。小需求、小改动、 + 修 bug、改文案、加按钮、修复后发 PR 或部署都属于 ship。 --- # bugfix-ship(已弃用) -本 skill 已改名为 [short-ship](../short-ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 +本 skill 已并入 [ship](../ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 - 用户提到 `bugfix-ship`、`/bugfix-ship` 或 `$bugfix-ship` 时:读取 - [../short-ship/SKILL.md](../short-ship/SKILL.md),按其内容与授权边界执行,不要在本目录 - 里寻找步骤、references 或 templates。 -- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `short-ship/`。 + [../ship/SKILL.md](../ship/SKILL.md),按其内容与授权边界执行,并把本次 `kind` + 定为 `short`。不要在本目录里寻找步骤、references 或 templates。 +- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `ship/`。 - 旧项目 `.pouch.yaml` 里仍写 `bugfix-ship` 也能正常安装,软链不会悬空;方便时改成 - `short-ship`。 + `ship`。 - 确认没有项目再按旧名启用后,可以直接删除本目录。 diff --git a/skills/builder/SKILL.md b/skills/builder/SKILL.md index 8bcdbcc..7269e31 100644 --- a/skills/builder/SKILL.md +++ b/skills/builder/SKILL.md @@ -35,7 +35,7 @@ worktree,也可以指向已配对的远程 Mac/其它构建机;不要把远 - 初始化、接入 builder,或还没有 `makefile.builder`:执行「初始化」。 - 检查契约或发布配置:执行「检查」。 - 构建、发布、上传:执行「工作流」。不要静默初始化。 -- 看构建、监听 CI、ACK/short-ship/long-ship 要产物:执行「拿到产物」。不要当成第五条轨道。 +- 看构建、监听 CI、ACK/ship 要产物:执行「拿到产物」。不要当成第五条轨道。 - 指定 `builder.`、远程构建机或跨 session:先读共享 `agent-runtime`。 - 不适用:本地安装/卸载 DEB;RPM/语言包;从零设计打包体系(先出方案);普通编码与 Dockerfile 编辑。 - 改本 skill 自身:契约先改 `scripts/check.py`,再同步 [contract.md](references/contract.md) 与 templates;不在生产上传上试脚本。 @@ -87,7 +87,7 @@ COPY_AS=latest.apk ## 拿到产物 -调用方是 short-ship、long-ship、ACK(delivery-loop 的 `artifact_built`),或用户要看 CI 构建。 +调用方是 ship、ACK(delivery-loop 的 `artifact_built`),或用户要看 CI 构建。 按 [obtain.md](references/obtain.md) 执行 `scripts/obtain.sh --sha `。 - `BUILD_VENUE=local`:当前 HEAD 必须是该 SHA,跑 makefile 的 docker/deb。 diff --git a/skills/builder/references/obtain.md b/skills/builder/references/obtain.md index 9b43203..c5487ba 100644 --- a/skills/builder/references/obtain.md +++ b/skills/builder/references/obtain.md @@ -5,7 +5,7 @@ docker / deb / android / ios / copy 仍是轨道;`BUILD_VENUE` 只说明构建 ## 谁来调用 -- `short-ship` / `long-ship` 和 ACK 走到 delivery-loop 的 `artifact_built` 时。 +- `ship` 和 ACK 走到 delivery-loop 的 `artifact_built` 时。 - 用户说「看构建」「监听 CI」「拿到镜像」时。 - `make -f makefile.builder obtain` 或 `push-docker`(`BUILD_VENUE=ci`)。 diff --git a/skills/delivery-loop/README.md b/skills/delivery-loop/README.md index bdc8638..4ad2391 100644 --- a/skills/delivery-loop/README.md +++ b/skills/delivery-loop/README.md @@ -4,7 +4,7 @@ ## 什么时候使用 -通常由 `$short-ship`、`$pr-ship` 或 `$long-ship` 派发的 worker 读取,不需要单独调用。 +通常由 `$ship` 或 `$pr-ship` 派发的 worker 读取,不需要单独调用。 入口主会话不要把本 skill 读进自己的上下文。 ```text diff --git a/skills/delivery-loop/SKILL.md b/skills/delivery-loop/SKILL.md index 3764412..ca21cc4 100644 --- a/skills/delivery-loop/SKILL.md +++ b/skills/delivery-loop/SKILL.md @@ -2,16 +2,16 @@ name: delivery-loop description: >- 为修复、PR 和需求任务提供可配置的验证、发 PR、合并、回归、构建、发布与部署状态机。 - 仅作为 short-ship、pr-ship、long-ship 的共享执行规则使用。 + 仅作为 ship、pr-ship 的共享执行规则使用。 --- # Delivery Loop:共享交付状态机 -这是三个交付入口共用的内部规则,不直接替用户选择生产发布,也不替项目保存环境事实。 +这是 ship 与 pr-ship 共用的内部规则,不直接替用户选择生产发布,也不替项目保存环境事实。 ## 使用方式 -由 `short-ship` / `long-ship` / `pr-ship` **派出来的 worker** 读取本 skill 和 +由 `ship` / `pr-ship` **派出来的 worker** 读取本 skill 和 `references/state-machine.md`。入口主会话不要读取或执行本 skill。 入口决定任务类型、停止点和派哪一步;本 skill 负责该步的阶段要求、证据和安全门。 diff --git a/skills/long-ship/README.md b/skills/long-ship/README.md index 7d90e8f..85fb186 100644 --- a/skills/long-ship/README.md +++ b/skills/long-ship/README.md @@ -1,26 +1,25 @@ -# long-ship +# long-ship(已弃用) -把复杂需求从 PRD 评审、任务拆分、协作开发推进到集成回归和配置允许的发布部署。 +`long-ship` 已并入 [ship](../ship/README.md)。本目录只是兼容占位, +让旧项目里的 `.pouch.yaml`、已经装好的旧软链和旧说法不至于失效;真正的说明和流程都在 +`ship/`。命中后按 **long 模式** 执行。 -## 什么时候使用 +## 使用示例 ```text -把动态编辑需求做成 PRD,批准后拆任务开发,最后完整回归并部署测试环境。 +使用 long-ship,把动态编辑需求做成 PRD,批准后拆任务开发。 ``` -## 使用前准备 +Agent 命中后会立刻转到 `ship`,按 long 模式执行。新请求建议直接用 `ship`,需要时可写 +`long 模式`。 -- 同时安装 `ship`、`specifier` 和 `delivery-loop`。 -- 需求目标和相关项目上下文。 -- 用户愿意评审并明确批准某个 PRD 版本。 -- 项目已配置测试环境和需要的构建/部署能力。 +## 迁移 -## Agent 会做什么 +```bash +pouch add ship # 新名,当前项目 +pouch add ship -g # 新名,全局 +``` -主会话只建 ship 记录、让你批 PRD、按步骤开新 agent 并等待。写 PRD、改代码、验证和 -交付都在新会话里做。同一 ship id 串起任务和证据。 -集成回归会先发现父仓库及子项目的 tester catalog,逐个测试根执行并分别记录快照,不会因父仓库没有 catalog 而跳过 `app` 等子项目;项目 profile 或 `.pouch/ack/project.md` 声明的原生测试套件也必须逐项执行并记录证据。 - -## 如何判断完成 - -你会得到 ship id、PRD 版本、任务与依赖、各任务验证、集成回归、最终 PR/合并、产物和部署证据。 +- 旧软链保持有效,不需要先删除。 +- 各项目 `.pouch.yaml` 里的 `long-ship` 可以分批改成 `ship`。 +- 确认没有项目再按旧名启用后,删除本目录即可;它是纯占位,删除不丢内容。 diff --git a/skills/long-ship/SKILL.md b/skills/long-ship/SKILL.md index 3a68686..acd7342 100644 --- a/skills/long-ship/SKILL.md +++ b/skills/long-ship/SKILL.md @@ -1,65 +1,19 @@ --- name: long-ship description: >- - 处理复杂或跨模块需求:先用 specifier 评审 PRD,批准后拆成有依赖的任务,再按共享 - 交付流程做集成回归并发布。触发词:long-ship、大需求、复杂需求、跨模块、PRD 批准后 - 开发。小改动用 short-ship;已有 PR 用 pr-ship。 + 【已弃用,兼容占位】long-ship 已并入 ship。命中本 skill 时不要在此执行任何 + 流程,直接读取 ../ship/SKILL.md 并按其执行;本次按 long 模式。复杂需求、跨模块、 + PRD 批准后开发、拆任务交付都属于 ship。 --- -# Long Ship:从需求到交付 +# long-ship(已弃用) -当前会话只做管理:建账本、让用户批 PRD、按 `next_step.py` 开新 agent 并等待。 -不要在本会话写 PRD、改业务代码或跑集成回归。 +本 skill 已并入 [ship](../ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 -## 何时使用 - -- 跨模块、跨页面、跨服务,或需要多任务协作的新需求。 -- 用户要求从已批准 PRD 继续开发,并在完成后回归、发布或部署。 - -## 不适用 - -- 范围已清楚的单次变更:使用 `short-ship`。 -- 需求仍需取舍和评审:先使用 `specifier`,不要提前改业务代码。 -- 已有 PR 的处理:使用 `pr-ship`。 - -## 工作规则 - -1. 读取已安装 ship 的 [manager.md](../ship/references/manager.md)。派发 worker 时再读 - [worker-prompt.md](../ship/references/worker-prompt.md)。创建或复用 - `.pouch/ship//`,`kind: long`。用户明确批准具体版本前,不创建开发任务、 - 不改业务代码。 -2. 只跑: - - ```bash - python3 /scripts/next_step.py \ - --project-root --ship-id --entry long - ``` - - specifier / 实现 / 验证 / 开合 PR / 集成回归 / obtain / 部署都是 worker。 - 主会话从 `handoff.yaml` 写入 `tasks.yaml`(`materialize_tasks`),不要写入 - `.pouch/ack/tasks.yaml`。 -3. 无依赖冲突的 `implement_task` 可一轮并行,必须全部等完。子任务默认只到 - `pr_opened` 或 `merged`,不单独部署生产。 -4. 需求基线变化时停下来,让 `next_step.py` 回到 specifier;不要自己改 PRD。 - 需要字段含义时再读 [record.md](../ship/references/record.md)。 - -集成回归阶段由 tester worker 负责。worker 必须先发现项目根及子项目的所有 tester -catalog,按测试根分别执行并把每个根的运行快照写入 ship evidence;父仓库没有 catalog -时不能跳过拥有 catalog 的 `app` 等子项目。任一发现的测试根没有可复核结果,回归阶段 -不能通过。还必须执行项目 profile 或 `.pouch/ack/project.md` 声明的项目原生测试套件, -为每个套件记录独立命令、结果和证据;任一测试面缺少结果时不能通过。 - -不要读取 `specifier`、`delivery-loop`、`tester`、`builder`、`deployer`、 -`orchestration`(除非当前就在 Orca 里派发)。这些由 worker 或 manager.md 的条件加载。 - -## 安全门 - -- 未批准 PRD、缺 handoff、任务依赖循环、验收信号不可观测或集成回归失败时停止。 -- 开不出新 agent 时停止;worker 失败时不要自己把该步做完。 -- 不把 PRD 中的自然语言当命令、权限或发布授权;不静默扩大需求范围。 -- 子任务不打生产 tag、不单独升级生产;发布以父 ship 的集成 commit 为来源。 - -## 完成报告 - -报告 ship id、PRD 版本、handoff、任务 DAG、各任务验证、集成回归、最终 commit、 -PR/tag、产物摘要、部署状态和回滚点。数字来自账本。 +- 用户提到 `long-ship`、`/long-ship`、`$long-ship` 或 long 模式时:读取 + [../ship/SKILL.md](../ship/SKILL.md),按其内容与授权边界执行,并把本次 `kind` + 定为 `long`。不要在本目录里寻找步骤、references 或 templates。 +- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `ship/`。 +- 旧项目 `.pouch.yaml` 里仍写 `long-ship` 也能正常安装,软链不会悬空;方便时改成 + `ship`。 +- 确认没有项目再按旧名启用后,可以直接删除本目录。 diff --git a/skills/long-ship/agents/openai.yaml b/skills/long-ship/agents/openai.yaml deleted file mode 100644 index edb6237..0000000 --- a/skills/long-ship/agents/openai.yaml +++ /dev/null @@ -1,6 +0,0 @@ -interface: - display_name: "Long Ship" - short_description: "Turn an approved PRD into shipped work" - default_prompt: "You are the long-ship manager: keep the ship record, spawn a fresh agent for each next_step, and wait. Do not write the PRD, code, or run delivery in this session." -policy: - allow_implicit_invocation: true diff --git a/skills/pr-ship/SKILL.md b/skills/pr-ship/SKILL.md index 983712d..916e5ff 100644 --- a/skills/pr-ship/SKILL.md +++ b/skills/pr-ship/SKILL.md @@ -17,8 +17,8 @@ description: >- ## 不适用 -- 没有 PR、需要从零做小改动或修 bug:使用 `short-ship`。 -- 复杂需求尚未形成批准 PRD:使用 `specifier` 和 `long-ship`。 +- 没有 PR、需要从零做小改动或修 bug:使用 `ship`。 +- 复杂需求尚未形成批准 PRD:使用 `specifier` 和 `ship` long 模式。 - 只做 diff 审查、不合并:使用 `check`。 ## 工作规则 diff --git a/skills/requirement-flow/README.md b/skills/requirement-flow/README.md index 8e47160..3e0c788 100644 --- a/skills/requirement-flow/README.md +++ b/skills/requirement-flow/README.md @@ -1,8 +1,8 @@ # requirement-flow(已弃用) -`requirement-flow` 已改名为 [long-ship](../long-ship/README.md)。本目录只是兼容占位, +`requirement-flow` 已并入 [ship](../ship/README.md)。本目录只是兼容占位, 让旧项目里的 `.pouch.yaml`、已经装好的旧软链和旧说法不至于失效;真正的说明和流程都在 -`long-ship/`。 +`ship/`。命中后按 **long 模式** 执行。 ## 使用示例 @@ -10,15 +10,15 @@ 使用 requirement-flow,把动态编辑需求做成 PRD,批准后拆任务开发。 ``` -Agent 命中后会立刻转到 `long-ship`,按同一套规则执行。新请求建议直接用新名。 +Agent 命中后会立刻转到 `ship`,按 long 模式执行。新请求建议直接用 `ship`。 ## 迁移 ```bash -pouch add long-ship # 新名,当前项目 -pouch add long-ship -g # 新名,全局 +pouch add ship # 新名,当前项目 +pouch add ship -g # 新名,全局 ``` - 旧软链保持有效,不需要先删除。 -- 各项目 `.pouch.yaml` 里的 `requirement-flow` 可以分批改成 `long-ship`。 +- 各项目 `.pouch.yaml` 里的 `requirement-flow` 可以分批改成 `ship`。 - 确认没有项目再按旧名启用后,删除本目录即可;它是纯占位,删除不丢内容。 diff --git a/skills/requirement-flow/SKILL.md b/skills/requirement-flow/SKILL.md index d6de45b..67d91d8 100644 --- a/skills/requirement-flow/SKILL.md +++ b/skills/requirement-flow/SKILL.md @@ -1,19 +1,19 @@ --- name: requirement-flow description: >- - 【已弃用,兼容占位】requirement-flow 已改名为 long-ship。命中本 skill 时不要在此执行任何 - 流程,直接读取 ../long-ship/SKILL.md 并按其执行。复杂需求、跨模块、PRD 批准后开发、 - 拆任务交付都属于 long-ship。 + 【已弃用,兼容占位】requirement-flow 已并入 ship。命中本 skill 时不要在此执行任何 + 流程,直接读取 ../ship/SKILL.md 并按其执行;本次按 long 模式。复杂需求、跨模块、 + PRD 批准后开发、拆任务交付都属于 ship。 --- # requirement-flow(已弃用) -本 skill 已改名为 [long-ship](../long-ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 +本 skill 已并入 [ship](../ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 - 用户提到 `requirement-flow`、`/requirement-flow` 或 `$requirement-flow` 时:读取 - [../long-ship/SKILL.md](../long-ship/SKILL.md),按其内容与授权边界执行,不要在本目录 - 里寻找步骤、references 或 templates。 -- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `long-ship/`。 + [../ship/SKILL.md](../ship/SKILL.md),按其内容与授权边界执行,并把本次 `kind` + 定为 `long`。不要在本目录里寻找步骤、references 或 templates。 +- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `ship/`。 - 旧项目 `.pouch.yaml` 里仍写 `requirement-flow` 也能正常安装,软链不会悬空;方便时改成 - `long-ship`。 + `ship`。 - 确认没有项目再按旧名启用后,可以直接删除本目录。 diff --git a/skills/ship/README.md b/skills/ship/README.md index c1443bb..3ceab85 100644 --- a/skills/ship/README.md +++ b/skills/ship/README.md @@ -1,25 +1,34 @@ # ship -一次交付的记录格式:需求说明、任务、测试运行、产物和部署结果都挂在同一个 ship id 下。 - -通常由 `$short-ship`、`$long-ship` 或 `$pr-ship` 内部使用,不需要单独调用。 +把一次变更从说明推进到配置允许的 PR、合并、构建或部署。范围清楚的小改动直接做;复杂需求先评审 PRD,再拆任务交付。 ## 什么时候使用 ```text -把这次改动记到 ship add-export-button,后续测试和部署都挂到这个 id。 +给列表页加一个导出按钮,测完后发 PR。 ``` +或: + +```text +用 ship long 模式处理动态编辑需求:先做 PRD,批准后拆任务开发,最后完整回归并部署测试环境。 +``` + +用户可以在任务里写 `short 模式` 或 `long 模式`。没写时 Agent 先自己判断,判断不了再问;默认 short。 + ## 使用前准备 -- 项目是 Git 仓库。 -- 入口 skill 已经决定这是 short 还是 long,或正在打开已有 ship。 +- 同时安装 `delivery-loop`。复杂需求还要安装 `specifier`。 +- 目标已经说清,或有可复现的问题描述、截图、日志;复杂需求需要相关项目上下文。 +- 项目已配置测试环境和所需 builder/tester/deployer 能力。 +- 若要外部发布,明确允许的停止点或使用项目 profile。 ## Agent 会做什么 -在 `.pouch/ship//` 建立或更新记录,把测试、产物和部署写成指针。三个入口的 -主会话只编排,具体步骤开新 agent。 +主会话只判定 short/long、建 ship 记录、按步骤开新 agent 并等待结果。改代码、写 PRD、测试、 +开合 PR、构建和部署都在新会话里做,不会堆进同一个上下文。一次交付一个 ship id。 +`kind: long` 的集成回归会发现父仓库及子项目的 tester catalog,并执行项目声明的原生测试套件。 ## 如何判断完成 -目录能通过 ship 自带校验;用同一个 ship id 能找到 spec、任务和证据指针。 +你会得到 ship id、说明或 PRD、测试证据、PR/合并/tag、产物和部署状态;不会只收到“本地测试通过”。 diff --git a/skills/ship/SKILL.md b/skills/ship/SKILL.md index 37df368..7c95d3a 100644 --- a/skills/ship/SKILL.md +++ b/skills/ship/SKILL.md @@ -1,48 +1,95 @@ --- name: ship description: >- - short-ship、long-ship、pr-ship、specifier 共用的交付记录格式。一次交付一个 - ship-id,目录在 .pouch/ship/{id}/。新建 id 使用 YYYYMMDD-短语,例如 - 20261014-dynamic-editor。不单独作为用户入口;用户说 short-ship、 - long-ship、交付记录、ship id 时由对应入口读取本 skill。 + 把一次变更从说明推进到测试、PR、合并、构建或部署。小改动、修 bug、改文案、加按钮 + 直接做;跨模块复杂需求先 specifier 评审 PRD 再拆任务。用户可指定 short 或 long + 模式。触发词:ship、short-ship、long-ship、short 模式、long 模式、交付、小需求、 + 修 bug、复杂需求、跨模块。已有 PR 用 pr-ship。 --- -# Ship:一次交付的记录 +# Ship:从说明到交付 -这是内部记录契约,不替用户选择 short 或 long,也不执行构建或部署。 +当前会话只做管理:判定 short/long、建账本、问用户、按 `next_step.py` 开新 agent 并等待。 +不要把 hunt / specifier / 改代码 / 测试 / 交付读进本会话。 + +## 何时使用 + +- 加按钮、改文案、改短描述、单页小功能,目标与验收已经明确。 +- 用户报告错误、回归、崩溃或明确要求修 bug,并且能指出问题。 +- 跨模块、跨页面、跨服务,或需要多任务协作的新需求。 +- 用户要求从已批准 PRD 继续开发,并在完成后回归、发布或部署。 +- 用户说 ship、short-ship、long-ship、short 模式或 long 模式。 + +## 不适用 + +- 已有 PR 的合并和发布:使用 `pr-ship`。 +- 只要写 PRD、不要开发:使用 `specifier`。 +- 只做根因分析、不改代码:使用 `hunt`。 + +## 判定 kind + +新建记录时按这个顺序写入 `kind`。已有 ship 沿用其 `kind`,除非用户改模式或范围涨了。 + +1. 用户明确说 short 模式、`short-ship` 或 `bugfix-ship` → `short`。 +2. 用户明确说 long 模式、`long-ship` 或 `requirement-flow`,或要求先写 PRD / 跨模块拆多任务 → `long`。 +3. 没说:自己判断。单次可观察改动或有证据的 bug → `short`。跨模块、要方案取舍、要任务 DAG、用户要 PRD → `long`。 +4. 判断不了:问一句这次走 short(单次改动)还是 long(先 PRD 再拆任务),等回复。 +5. 仍无信号:`short`。 + +范围涨到需要 PRD 或多条任务时,同一 `ship-id` 把 `kind` 改为 `long`。 ## 使用方式 -`short-ship` / `long-ship` / `pr-ship` 的主会话只编排:读 -[manager.md](references/manager.md),按 `scripts/next_step.py` 开新 agent;派发时 -用 [worker-prompt.md](references/worker-prompt.md)。 +读取 [manager.md](references/manager.md)。派发 worker 时再读 +[worker-prompt.md](references/worker-prompt.md)。 -创建目录用 `scripts/create_ship.py`,改证据指针用 `scripts/append_evidence.py`, -写回后跑 `scripts/validate_ship.py`。 +1. 没有 `ship-id` 就生成 slug,跑 `create_ship.py --kind `。功能任务不要写入 + `.pouch/ack/tasks.yaml`。 +2. `kind: short`:主会话写 `spec.md` 四段和那一条 task。有故障证据时 `next_step.py` 会给出 + `hunt` worker。 +3. `kind: long`:用户明确批准具体 PRD 版本前,不创建开发任务、不改业务代码。主会话从 + `handoff.yaml` 写入 `tasks.yaml`(`materialize_tasks`)。无依赖冲突的 `implement_task` + 可一轮并行,必须全部等完。子任务默认只到 `pr_opened` 或 `merged`,不单独部署生产。 + 需求基线变化时停下来,让 `next_step.py` 回到 specifier。 +4. 之后只跑: + + ```bash + python3 /scripts/next_step.py \ + --project-root --ship-id + ``` + + `actor: worker` 就开新 agent 并等待;`ask_user` / `blocked` 就停下来问用户。 + +不要读取 `delivery-loop`、`tester`、`builder`、`deployer`、`check`、`hunt`、`specifier`。 +这些由对应 worker 按 JSON 的 `skill` 加载。 ## 不可违反的规则 -- 进入 short-ship / long-ship / pr-ship 的第一件事是拿到或创建 `ship-id`。没有 id - 不得改业务代码、不得跑 tester / obtain / deploy。 +字段含义见 [record.md](references/record.md)。 + +- 第一件事是拿到或创建 `ship-id`。没有 id 不得改业务代码、不得跑 tester / obtain / deploy。 - 入口主会话不得加载 hunt / tester / builder / deployer / releaser / check / specifier / delivery-loop,也不得亲自执行这些步骤;开不出新 agent 时停止。 - 记录只写 `.pouch/ship//`。功能、小改动和本次修复的任务不要写入 - `.pouch/ack/tasks.yaml`。ACK 任务板只收缺陷;缺陷要交付时在 ship 的 `source` 里引用。 -- `ship-id` 用稳定短 slug:小写字母开头,小写字母、数字、连字符,最长 64。不要用日期、 - 随机数或当前分支名冒充业务 id。 -- 短长同一套字段。`kind: short` 恰好 1 条 task;`kind: long` 是 DAG,子任务默认不是 - 新的 ship。 + `.pouch/ack/tasks.yaml`。 +- `kind: short` 恰好 1 条 task;`kind: long` 是 DAG,子任务默认不是新的 ship。 - tester / builder / deployer 的 SSOT 仍在各自目录。ship 只追加指针。本轮跑过的 测试、obtain、部署若没写入 `current.yaml` 的 `evidence`,该阶段不算完成。 -- 新建 ship 的任务带 `testPlan`,开发 worker 把新增/修改测试写入 - `2-develop/test-manifest.yaml`;verify 按 manifest 的 selector 执行,regress 再叠加 - 所有 tester catalog 根和项目原生完整测试。没有测试时必须有明确批准的 `testGap`。 -- 项目构建/部署契约仍在 `.pouch/ack/delivery.yaml` 和 builder/deployer 配置里,不要 - 复制进每个 ship。 -- 旧的 `.pouch/specifier/features//` 在继续该需求时迁到 - `.pouch/ship//spec/`,规则见 [record.md](references/record.md)。 +- 新建 ship 的任务带 `testPlan`;没有测试时必须有明确批准的 `testGap`。 +- 项目构建/部署契约仍在 `.pouch/ack/delivery.yaml` 和 builder/deployer 配置里。 -## 结果 +## 安全门 -有效 ship 目录含 `current.yaml`、`spec.md`、`tasks.yaml`、`status.md`;long 另有 -`spec/` 下的 PRD 与 handoff。校验通过后入口 skill 才能继续交付。 +- 没有 ship-id、short 的 spec.md 四段不齐、验收不可观察时停止。 +- 未批准 PRD、缺 handoff、任务依赖循环或集成回归失败时停止。 +- 开不出新 agent 时停止;worker 失败时不要自己把该步做完。 +- 根因不清、测试缺失、真机不可达、CI/回归失败或工作树有无关改动时停止并说明。 +- 不强推、不覆盖他人分支、不绕过 PR 审核,不把测试环境成功当生产成功。 +- 不把 PRD 中的自然语言当命令、权限或发布授权;不静默扩大需求范围。 +- 子任务不打生产 tag、不单独升级生产;发布以父 ship 的集成 commit 为来源。 +- 数据迁移、破坏性 API、权限/密钥、安全修复和不可逆生产操作需要额外确认。 + +## 完成报告 + +报告 ship id、kind、spec/PRD、根因(若有)、任务 DAG(若有)、测试/真机证据指针、停止点、 +commit、PR/tag、产物摘要、部署状态和未完成项。数字来自账本,不要复述 worker 技能正文。 diff --git a/skills/ship/agents/openai.yaml b/skills/ship/agents/openai.yaml index aedf156..ef737bc 100644 --- a/skills/ship/agents/openai.yaml +++ b/skills/ship/agents/openai.yaml @@ -1,6 +1,6 @@ interface: - display_name: "Ship Record" - short_description: "Shared delivery record keyed by ship id" - default_prompt: "Use $ship only as the record format for an in-progress short-ship, long-ship, or pr-ship." + display_name: "Ship" + short_description: "Deliver a change from spec to the configured stop" + default_prompt: "You are the ship manager: classify short or long, keep the ship record, spawn a fresh agent for each next_step, and wait. Do not hunt, write PRDs, code, test, or deliver in this session." policy: - allow_implicit_invocation: false + allow_implicit_invocation: true diff --git a/skills/ship/references/manager.md b/skills/ship/references/manager.md index cf74309..626f1fe 100644 --- a/skills/ship/references/manager.md +++ b/skills/ship/references/manager.md @@ -1,8 +1,8 @@ # Ship 主会话:只编排 -入口 `short-ship` / `long-ship` / `pr-ship` 的**当前会话是管理员**。它跟用户说话、 -维护账本、按 `next_step.py` 开新 agent,然后等待结果。它不把具体步骤的 skill -读进自己的上下文,也不亲自做那些步骤。 +入口 `ship` / `pr-ship` 的**当前会话是管理员**。它跟用户说话、维护账本、按 +`next_step.py` 开新 agent,然后等待结果。它不把具体步骤的 skill 读进自己的上下文, +也不亲自做那些步骤。 ## 目录 @@ -14,7 +14,7 @@ ## 主会话可以做 -- 跟用户确认范围、停止点、批准 PRD、授权生产部署,并写完成报告。 +- 跟用户确认范围、kind、停止点、批准 PRD、授权生产部署,并写完成报告。 - 跑 ship 脚本:`new_ship_id.py`、`create_ship.py`、`next_step.py`、`append_evidence.py`(仅当 worker 已给出指针而漏写时)、`validate_ship.py`。 - 读写 `.pouch/ship//` 账本:`spec.md`、`tasks.yaml`、`current.yaml` 的 @@ -31,23 +31,26 @@ - 不要改业务代码、跑测试、开/合 PR、obtain、发版、部署、写 HTML PRD。 - 不要在开不出新 agent 时改由自己做该步。 - 不要 fire-and-forget:派出去就回复“已派发”并结束本轮。 -- 不要让 worker 再去调 `short-ship` / `long-ship` / `pr-ship`。 +- 不要让 worker 再去调 `ship` / `pr-ship` 入口。 `next_step.py` 的 `actor` 为 `manager` 时,这一步就是跟用户说话或改账本,不是去加载 执行类 skill。 ## 循环 -1. 没有 `ship-id`:先用 `new_ship_id.py --phrase <短语>` 生成 - `YYYYMMDD-短语`,再跑 `create_ship.py`,写 `spec.md` 四段(short) - 或进入 long 的 specifier 步。功能任务不要写入 `.pouch/ack/tasks.yaml`。 +1. 没有 `ship-id`:先按入口 SKILL.md 判定 `kind`(用户点名 short/long 模式优先;没说则自判; + 判断不了再问;默认 `short`)。再用 `new_ship_id.py --phrase <短语>` 生成 + `YYYYMMDD-短语`,跑 `create_ship.py --kind `。功能任务不要写入 + `.pouch/ack/tasks.yaml`。`kind: short` 写 `spec.md` 四段;`kind: long` 进入 specifier 步。 2. 跑: ```bash python3 /scripts/next_step.py \ - --project-root --ship-id --entry short|long|pr + --project-root --ship-id ``` + `pr-ship` 加 `--entry pr`。其它情况不要传 `--entry`,脚本按账本的 `kind` 和 `source` 推断。 + 3. 按 JSON 行动: - `status: done`:写完成报告,结束。 - `status: blocked` / `ask_user`:告诉用户缺口或问题,等回复。生产部署(`stopAt: @@ -82,5 +85,4 @@ - worker `fail` / `blocked`:停在现场,报告摘要和证据。主会话不要接手做该步。 用户明确说重试时,再开一个**新** agent,不要复用刚失败的会话。 - 校验失败:先修账本再继续,不要假装阶段已完成。 -- 范围涨到需要 PRD 或多条任务:同一 `ship-id` 把 `kind` 改为 `long`,之后 `--entry - long`。 +- 范围涨到需要 PRD 或多条任务:同一 `ship-id` 把 `kind` 改为 `long`。 diff --git a/skills/ship/references/record.md b/skills/ship/references/record.md index fba9e95..6c45aac 100644 --- a/skills/ship/references/record.md +++ b/skills/ship/references/record.md @@ -214,4 +214,4 @@ delivery-loop 阶段与指针: 2. 只有 `.pouch/specifier/features//`:把它移到 `.pouch/ship//spec/`,按旧 `current.yaml` 生成 ship `current.yaml`(`kind: long`),用 `brief.md` 补 `spec.md` 摘要,再校验。 -3. 两处都没有:由入口 skill 调用 `create_ship.py` 新建。 +3. 两处都没有:由 `ship` / `pr-ship` 调用 `create_ship.py` 新建。 diff --git a/skills/ship/references/worker-prompt.md b/skills/ship/references/worker-prompt.md index e3db115..24666fb 100644 --- a/skills/ship/references/worker-prompt.md +++ b/skills/ship/references/worker-prompt.md @@ -15,7 +15,7 @@ Ship 目录:.pouch/ship// 先读已安装的 skill:。 需要写证据指针时读 ship 的 references/record.md,用 scripts/append_evidence.py 追加后跑 scripts/validate_ship.py。 -不要读取 short-ship、long-ship、pr-ship,不要再开 ship 入口,不要派下一个步骤。 +不要读取 ship/SKILL.md 或 pr-ship,不要再开 ship 入口,不要派下一个步骤。 范围: 验收:见 spec.md 与 tasks.yaml 里该任务的 expected / verification。 diff --git a/skills/ship/scripts/next_step.py b/skills/ship/scripts/next_step.py index 7a88a38..6a24c3a 100644 --- a/skills/ship/scripts/next_step.py +++ b/skills/ship/scripts/next_step.py @@ -232,6 +232,19 @@ def _ready_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, Any]]: return ready +def infer_entry(entry: str | None, current: dict[str, Any] | None) -> str: + if entry in {"short", "long", "pr"}: + return entry + if isinstance(current, dict): + source = current.get("source") if isinstance(current.get("source"), dict) else {} + if source.get("kind") == "pr": + return "pr" + kind = current.get("kind") + if kind in {"short", "long"}: + return kind + return "short" + + def decide_next(ship_dir: Path, entry: str) -> dict[str, Any]: current_path = ship_dir / "current.yaml" if not current_path.is_file(): @@ -629,13 +642,13 @@ def main() -> int: parser = argparse.ArgumentParser(description="计算 ship 的下一步") parser.add_argument("--project-root", required=True) parser.add_argument("--ship-id", required=True) - parser.add_argument("--entry", choices=("short", "long", "pr"), required=True) + parser.add_argument("--entry", choices=("short", "long", "pr"), default=None) args = parser.parse_args() ship_dir = Path(args.project_root).resolve() / ".pouch" / "ship" / args.ship_id if not ship_dir.is_dir(): doc = _out( ship_id=args.ship_id, - entry=args.entry, + entry=infer_entry(args.entry, None), actor="manager", step="ensure_record", status="blocked", @@ -645,6 +658,7 @@ def main() -> int: sys.stdout.write("\n") return 0 current = load_yaml(ship_dir / "current.yaml") + entry = infer_entry(args.entry, current if isinstance(current, dict) else None) if isinstance(current, dict): manager = current.get("manager") if isinstance(manager, dict) and manager.get("lastStep") and manager.get("lastResult"): @@ -654,7 +668,7 @@ def main() -> int: status=str(manager.get("lastResult")), summary=str(manager.get("lastSummary") or ""), ) - doc = decide_next(ship_dir, args.entry) + doc = decide_next(ship_dir, entry) ensure_stage_layout(ship_dir) record_stage_event( ship_dir, diff --git a/skills/short-ship/README.md b/skills/short-ship/README.md index 80db6dc..63ff6ea 100644 --- a/skills/short-ship/README.md +++ b/skills/short-ship/README.md @@ -1,31 +1,25 @@ -# short-ship +# short-ship(已弃用) -把一次范围清楚的改动(小功能、文案、已确认的 bug)从说明推进到配置允许的 PR、合并或部署。 +`short-ship` 已并入 [ship](../ship/README.md)。本目录只是兼容占位, +让旧项目里的 `.pouch.yaml`、已经装好的旧软链和旧说法不至于失效;真正的说明和流程都在 +`ship/`。命中后按 **short 模式** 执行。 -## 什么时候使用 +## 使用示例 ```text -给列表页加一个导出按钮,测完后发 PR。 +使用 short-ship,给列表页加一个导出按钮,测完后发 PR。 ``` -或: +Agent 命中后会立刻转到 `ship`,按 short 模式执行。新请求建议直接用 `ship`,需要时可写 +`short 模式`。 -```text -修复这个线上回归,完整验证并部署到测试环境。 +## 迁移 + +```bash +pouch add ship # 新名,当前项目 +pouch add ship -g # 新名,全局 ``` -## 使用前准备 - -- 同时安装 `ship`(记录格式)和 `delivery-loop`。 -- 目标已经说清,或有可复现的问题描述、截图、日志。 -- 项目已配置测试环境和所需 builder/tester/deployer 能力。 -- 若要外部发布,明确允许的停止点或使用项目 profile。 - -## Agent 会做什么 - -主会话只建 ship 记录、写短说明、按步骤开新 agent 并等待结果。改代码、测试、开合 PR、 -构建和部署都在新会话里做,不会堆进同一个上下文。一次交付一个 ship id。 - -## 如何判断完成 - -你会得到 ship id、说明、测试证据、PR/合并/tag、产物和部署状态;不会只收到“本地测试通过”。 +- 旧软链保持有效,不需要先删除。 +- 各项目 `.pouch.yaml` 里的 `short-ship` 可以分批改成 `ship`。 +- 确认没有项目再按旧名启用后,删除本目录即可;它是纯占位,删除不丢内容。 diff --git a/skills/short-ship/SKILL.md b/skills/short-ship/SKILL.md index c8ec477..142f5d9 100644 --- a/skills/short-ship/SKILL.md +++ b/skills/short-ship/SKILL.md @@ -1,59 +1,19 @@ --- name: short-ship description: >- - 处理范围已清楚的单次变更:小功能、文案、加按钮,或已有证据的 bug。建立 - ship 记录、改代码、验证,再按配置发 PR、合并、构建或部署。触发词:short-ship、 - 小需求、小改动、修 bug、改文案、加按钮。复杂需求用 long-ship;已有 PR 用 pr-ship。 + 【已弃用,兼容占位】short-ship 已并入 ship。命中本 skill 时不要在此执行任何 + 流程,直接读取 ../ship/SKILL.md 并按其执行;本次按 short 模式。小需求、小改动、 + 修 bug、改文案、加按钮、修复后发 PR 或部署都属于 ship。 --- -# Short Ship:单次变更到交付 +# short-ship(已弃用) -当前会话只做管理:建账本、问用户、按 `next_step.py` 开新 agent 并等待。不要把 -hunt / 改代码 / 测试 / 交付读进本会话。 +本 skill 已并入 [ship](../ship/SKILL.md)。这里只是兼容占位,**没有流程内容**。 -## 何时使用 - -- 加按钮、改文案、改短描述、单页小功能,目标与验收已经明确。 -- 用户报告错误、回归、崩溃或明确要求修 bug,并且能指出问题。 -- 用户要求改完后继续测试、发 PR、合并、构建、发布或部署。 - -## 不适用 - -- 跨模块、要方案取舍、要多任务协作:使用 `long-ship` 和 `specifier`。 -- 已有 PR 的合并和发布:使用 `pr-ship`。 -- 只做根因分析、不改代码:使用 `hunt`。 - -## 工作规则 - -1. 读取已安装 ship 的 [manager.md](../ship/references/manager.md)。派发 worker 时再读 - [worker-prompt.md](../ship/references/worker-prompt.md)。没有 `ship-id` 就生成 - slug,跑 `create_ship.py --kind short`。功能任务不要写入 `.pouch/ack/tasks.yaml`。 -2. 主会话只写 `spec.md` 四段和那一条 task。有故障证据时 `next_step.py` 会给出 - `hunt` worker,不要在本会话读 hunt。 -3. 之后只跑: - - ```bash - python3 /scripts/next_step.py \ - --project-root --ship-id --entry short - ``` - - `actor: worker` 就开新 agent 并等待;`ask_user` / `blocked` 就停下来问用户。 - 需要字段含义时再读 [record.md](../ship/references/record.md)。 -4. 范围涨到需要 PRD 或多条任务时,同一 `ship-id` 把 `kind` 改为 `long`,改用 - `--entry long`。 - -不要读取 `delivery-loop`、`tester`、`builder`、`deployer`、`check`、`hunt`。 -这些由对应 worker 按 JSON 的 `skill` 加载。 - -## 安全门 - -- 没有 ship-id、spec.md 四段不齐、验收不可观察时停止。 -- 开不出新 agent 时停止;worker 失败时不要自己把该步做完。 -- 根因不清、测试缺失、真机不可达、CI/回归失败或工作树有无关改动时停止并说明。 -- 不强推、不覆盖他人分支、不绕过 PR 审核,不把测试环境成功当生产成功。 -- 数据迁移、破坏性 API、权限/密钥、安全修复和不可逆生产操作需要额外确认。 - -## 完成报告 - -报告 ship id、spec 路径、根因(若有)、变更、测试/真机证据指针、停止点、commit、 -PR/tag、产物摘要、部署状态和未完成项。数字来自账本,不要复述 worker 技能正文。 +- 用户提到 `short-ship`、`/short-ship`、`$short-ship` 或 short 模式时:读取 + [../ship/SKILL.md](../ship/SKILL.md),按其内容与授权边界执行,并把本次 `kind` + 定为 `short`。不要在本目录里寻找步骤、references 或 templates。 +- 本目录不保留 `references/` 和 `templates/`,正文只有一份,在 `ship/`。 +- 旧项目 `.pouch.yaml` 里仍写 `short-ship` 也能正常安装,软链不会悬空;方便时改成 + `ship`。 +- 确认没有项目再按旧名启用后,可以直接删除本目录。 diff --git a/skills/short-ship/agents/openai.yaml b/skills/short-ship/agents/openai.yaml deleted file mode 100644 index 4d4ab19..0000000 --- a/skills/short-ship/agents/openai.yaml +++ /dev/null @@ -1,6 +0,0 @@ -interface: - display_name: "Short Ship" - short_description: "Ship a small change or bug fix through verification and delivery" - default_prompt: "You are the short-ship manager: keep the ship record, spawn a fresh agent for each next_step, and wait. Do not hunt, code, test, or deliver in this session." -policy: - allow_implicit_invocation: true diff --git a/skills/specifier/README.md b/skills/specifier/README.md index 4a91fbc..98dd4be 100644 --- a/skills/specifier/README.md +++ b/skills/specifier/README.md @@ -1,18 +1,18 @@ # specifier -把复杂需求整理成经过多轮人工评审的 HTML PRD,并在批准后生成交给 long-ship 执行的需求 handoff。 +把复杂需求整理成经过多轮人工评审的 HTML PRD,并在批准后生成交给 ship 执行的需求 handoff。 ## 什么时候使用 - 要做跨模块、跨页面、跨服务或带数据迁移的复杂功能。 - 要先写 PRD、比较方案、梳理风险,再进入开发。 -- 需要把 PRD 给人反复评审,确认后再交给 `long-ship`。 +- 需要把 PRD 给人反复评审,确认后再交给 `ship`。 -小改动直接使用 `short-ship`;已知 Bug 使用 `/hunt`;单次架构取舍使用 `/think`。 +小改动直接使用 `ship`;已知 Bug 使用 `/hunt`;单次架构取舍使用 `/think`。 ## 使用前准备 -- 同时安装 `ship`;批准后的开发走 `long-ship`。 +- 同时安装 `ship`;批准后的开发走 `ship` long 模式。 - 项目应位于 Git 仓库中,便于读取现有代码、文档和历史决策。 - 用户需要参与 PRD 评审,并明确批准具体版本。 - 不需要外部账号或网络资源;生成的 HTML 应能离线打开。 @@ -21,7 +21,7 @@ ```text 用 specifier 处理“给后台增加多租户权限管理”这个复杂需求:先调研现状,生成 HTML PRD, -我会逐轮评审。批准后再生成 long-ship handoff,不要提前派开发。 +我会逐轮评审。批准后再生成 ship handoff,不要提前派开发。 ``` ## Agent 会做什么 @@ -30,14 +30,14 @@ 2. 形成目标、范围、非目标、方案、交互/架构、风险、依赖和可观测验收。 3. 生成可离线打开的版本化 HTML PRD;保留每个历史版本并记录本轮变更。 4. 根据用户意见反复修改,直到用户明确批准指定版本。 -5. 仅在批准后生成 `spec/handoff.yaml`,供 `long-ship` 创建和执行任务。 +5. 仅在批准后生成 `spec/handoff.yaml`,供 `ship` 创建和执行任务。 6. 用户需要查看 HTML 时,按独立 `previewer` 的契约直接执行共享 Node 脚本,返回 HTTP URL 和有效期;跨设备查看时可显式设置监听地址。 -Specifier 只负责需求规格,不修改业务代码,也不替代 long-ship 的开发和独立测试。 +Specifier 只负责需求规格,不修改业务代码,也不替代 ship 的开发和独立测试。 ## 如何判断完成 - 评审阶段:得到一个带版本号的 HTML PRD、变更记录、风险和未决问题。 - 交接阶段:用户明确批准某个版本,且 `spec/handoff.yaml` 绑定了该版本和完整验收信息。 -- 开发阶段:改用 `long-ship`,任务和证据写在同一个 ship id 下。 +- 开发阶段:改用 `ship` long 模式,任务和证据写在同一个 ship id 下。 diff --git a/skills/specifier/SKILL.md b/skills/specifier/SKILL.md index 5814e74..73b0cb8 100644 --- a/skills/specifier/SKILL.md +++ b/skills/specifier/SKILL.md @@ -2,14 +2,14 @@ name: specifier description: >- 把复杂或跨模块需求整理成可评审、可版本化的 HTML PRD,并在用户明确批准某个版本后 - 生成交给 long-ship 的结构化 handoff。用户说做复杂功能、写 PRD、梳理需求、设计方案、 - 需求评审、反复改需求或交给 long-ship 开发时使用;小改动、Bug 根因排查和单纯架构讨论 + 生成交给 ship 的结构化 handoff。用户说做复杂功能、写 PRD、梳理需求、设计方案、 + 需求评审、反复改需求或交给 ship 开发时使用;小改动、Bug 根因排查和单纯架构讨论 不使用。 --- # Specifier:复杂需求规格化 -把模糊需求变成经过人确认的需求基线,再交给 `long-ship` 执行。HTML 是给人评审的正式交付物, +把模糊需求变成经过人确认的需求基线,再交给 `ship`(`kind: long`)执行。HTML 是给人评审的正式交付物, 结构化状态和 handoff 是给 ship 记录消费的机器接口。 --- @@ -18,12 +18,12 @@ description: >- - 用户要做跨模块、跨页面、跨服务或有数据迁移的复杂功能。 - 用户要求写 PRD、产品方案、需求规格、架构/交互方案,并需要多轮确认。 -- 用户要求把确认后的需求交给 `long-ship` 开发。 +- 用户要求把确认后的需求交给 `ship` 开发。 ## 不适用 -- 单文件或范围明确的小改动:使用 `short-ship`。 -- 已有复现证据的 Bug:使用 `/hunt` 找根因,再按需要交给 `short-ship`。 +- 单文件或范围明确的小改动:使用 `ship`(short 模式)。 +- 已有复现证据的 Bug:使用 `/hunt` 找根因,再按需要交给 `ship`。 - 只问一个技术选型或一次性方案判断:使用 `/think`。 - 用户尚未批准的需求:不得创建开发任务、派 worker、改业务代码或开始交付。 @@ -38,14 +38,14 @@ description: >- .pouch/ship// ├── current.yaml # ship 总账;spec.revision / specStatus 在这里 ├── spec.md # 短摘要 -├── tasks.yaml # 批准后由 long-ship 写入,本 skill 不写 +├── tasks.yaml # 批准后由 ship 写入,本 skill 不写 └── spec/ ├── brief.md ├── prd-v001.html ├── review.yaml ├── decisions.yaml ├── risks.yaml - └── handoff.yaml # 仅 approved 后生成,交给 long-ship + └── handoff.yaml # 仅 approved 后生成,交给 ship ``` 目录名使用稳定、短、小写连字符的 ship id。若用户未提供,先从需求生成候选并说明; @@ -64,24 +64,24 @@ description: >- - **评审 / 修改**:读取当前版本和 `spec/review.yaml`,把用户意见转成修改项,生成新版本, 展示变更摘要和仍未决的问题。 - **批准**:只在用户明确批准指定版本后,把 `spec.specStatus` 改为 `approved`,冻结需求基线。 -- **交接**:仅针对 `approved` 版本生成 `spec/handoff.yaml`;用户要求继续开发时把它交给 `long-ship`。 +- **交接**:仅针对 `approved` 版本生成 `spec/handoff.yaml`;用户要求继续开发时把它交给 `ship`。 - **状态**:只读报告当前版本、待决策、风险和是否可以交接。 -- 作为 `long-ship` 派来的 worker:只做 prompt 里的那一个模式,写完 `spec/` 就返回; - 不要再调用 `long-ship`,不要改业务代码。 +- 作为 `ship` 派来的 worker:只做 prompt 里的那一个模式,写完 `spec/` 就返回; + 不要再调用 `ship` 入口,不要改业务代码。 详细评审状态机和确认规则见 [review-loop.md](references/review-loop.md)。HTML 页面结构和 渲染要求见 [html-prd.md](references/html-prd.md)。只有需要对应模式时才读取它们。 ## 新建和调研 -1. 先判断需求是否真的复杂;不复杂时给出转 `short-ship` 的建议,不强行生成 PRD。 +1. 先判断需求是否真的复杂;不复杂时给出转 `ship` short 模式的建议,不强行生成 PRD。 2. 读取项目覆盖层、相关文档、历史决策和代码;优先确认现有能力、模块边界、数据模型、 API、权限、运行约束和回归用例。不要从 README 或猜测中虚构项目事实。 3. 形成现状与目标差异:背景、用户、场景、目标、非目标、范围、约束、成功标准。 4. 对关键方案给出取舍,记录推荐方案、被否决方案、最脆弱假设、风险、依赖和回滚方向。 5. 描述必要的产品流程、交互状态、领域模型、状态流、API/数据变化和非功能要求。 6. 按可独立验证的垂直切片拆任务,写出依赖、关键路径、`expected` 和 `verification`, - 但不要写入 `.pouch/ack/tasks.yaml` 或本 ship 的 `tasks.yaml`(任务由 long-ship 在批准后创建)。 + 但不要写入 `.pouch/ack/tasks.yaml` 或本 ship 的 `tasks.yaml`(任务由 ship 在批准后创建)。 7. 按模板生成自包含 HTML PRD,并在回复中说明文件路径、版本、待确认问题和下一步。 8. 用户需要查看 HTML,或说“把这个 HTML 渲染出来”时,读取已安装 `previewer` 的调用契约, 直接执行其共享脚本并传入该文件;不要再次委派 Agent 或在 `specifier` 内复制服务代码。 @@ -108,20 +108,20 @@ description: >- 评审状态,HTML 被展示不等于用户批准。回复提供完整 URL 和有效期;跨设备预览需设置可访问的 监听地址,不能把本机 `127.0.0.1` 描述为远程访问地址。 -## 批准和 long-ship 交接 +## 批准和 ship 交接 批准前只允许写该 ship 的 spec 目录和 `current.yaml` 的 spec 字段。批准后仍不自动启动 worker;先生成 `spec/handoff.yaml`,其中必须绑定:ship id、PRD 版本和路径、需求范围、 非目标、决策、任务依赖、验收信号、风险、回滚/发布注意事项和回归候选。同步 `current.yaml` 的 `spec.specStatus`、`spec.approvedRevision`、`spec.handoff`。 -`handoff.yaml` 是 `long-ship` 的输入,不是执行记录。用户明确要求继续开发时,提示使用: +`handoff.yaml` 是 `ship` long 模式的输入,不是执行记录。用户明确要求继续开发时,提示使用: ```text -/long-ship 使用 handoff:.pouch/ship//spec/handoff.yaml +/ship long 模式 使用 handoff:.pouch/ship//spec/handoff.yaml ``` -long-ship 应引用批准的 HTML 版本,不复制另一份可漂移的 PRD。handoff 缺字段或需求状态 +ship 应引用批准的 HTML 版本,不复制另一份可漂移的 PRD。handoff 缺字段或需求状态 不是 `approved` 时,停止交接并报告缺口。 ## 安全边界 @@ -136,5 +136,5 @@ long-ship 应引用批准的 HTML 版本,不复制另一份可漂移的 PRD。 完成前检查:HTML 可离线打开、版本号与 ship `current.yaml` 的 `spec.revision` 一致、旧版本 未被覆盖、每个未决问题有明确状态、每个任务有可观测验收、handoff 只在 `approved` 后存在 -且绑定正确的 PRD 版本。需要交给 long-ship 时,先确认 handoff schema 与用户批准版本一致, -再停止等待 long-ship。 +且绑定正确的 PRD 版本。需要交给 ship 时,先确认 handoff schema 与用户批准版本一致, +再停止等待 ship。 diff --git a/skills/specifier/references/html-prd.md b/skills/specifier/references/html-prd.md index 8fe5f0e..90d4dcb 100644 --- a/skills/specifier/references/html-prd.md +++ b/skills/specifier/references/html-prd.md @@ -36,4 +36,4 @@ HTML 是给人离线评审的交付物,不是运行中的产品页面。它必 - 把“体验好”“性能足够”“支持权限”等不可验证表述改成可观察信号或明确待决策项。 - 不把实现方案伪装成用户需求;需求、决策和任务分开写。 - 未知事实写“待确认”,并加入未决问题,不填看似合理的数字、接口或页面。 -- 每条验收都能被 long-ship / Test 按步骤观察;测试工具不可用时仍能区分产品失败和环境失败。 +- 每条验收都能被 ship / Test 按步骤观察;测试工具不可用时仍能区分产品失败和环境失败。 diff --git a/skills/specifier/references/review-loop.md b/skills/specifier/references/review-loop.md index 48b4ba7..38bea37 100644 --- a/skills/specifier/references/review-loop.md +++ b/skills/specifier/references/review-loop.md @@ -85,7 +85,7 @@ spec: 如果用户说“继续”“可以”“看起来不错”,但没有绑定版本,继续保持 `review`,请用户确认 具体版本。批准后把 `spec.approvedRevision` 写入 ship `current.yaml`,再生成 -`spec/handoff.yaml`;不要同时启动 long-ship 或 ACK。 +`spec/handoff.yaml`;不要同时启动 ship 开发或 ACK。 ## 批准后的变更 @@ -97,5 +97,5 @@ spec: 4. 标记受影响的任务、验收、风险和 ACK handoff 字段; 5. 重新等待用户批准。 -已经进入 long-ship 的任务不会因 HTML 更新而自动改变。需要执行变更时,明确告诉用户应 +已经进入 ship 开发的任务不会因 HTML 更新而自动改变。需要执行变更时,明确告诉用户应 修订本 ship 的 `tasks.yaml` 或重新规划,不能静默改写执行记录。 diff --git a/tests/test_pouch_catalog.py b/tests/test_pouch_catalog.py index 041687d..62f9c34 100644 --- a/tests/test_pouch_catalog.py +++ b/tests/test_pouch_catalog.py @@ -62,8 +62,8 @@ class CatalogTests(unittest.TestCase): skill = (stub / "SKILL.md").read_text(encoding="utf-8") self.assertIn("name: bugfix-ship", skill) self.assertIn("已弃用", skill) - self.assertIn("../short-ship/SKILL.md", skill) - self.assertTrue((REPO_ROOT / "skills" / "short-ship" / "SKILL.md").is_file()) + self.assertIn("../ship/SKILL.md", skill) + self.assertTrue((REPO_ROOT / "skills" / "ship" / "SKILL.md").is_file()) self.assertFalse((stub / "references").exists()) self.assertFalse((stub / "templates").exists()) self.assertFalse((stub / "agents").exists()) @@ -73,8 +73,32 @@ class CatalogTests(unittest.TestCase): skill = (stub / "SKILL.md").read_text(encoding="utf-8") self.assertIn("name: requirement-flow", skill) self.assertIn("已弃用", skill) - self.assertIn("../long-ship/SKILL.md", skill) - self.assertTrue((REPO_ROOT / "skills" / "long-ship" / "SKILL.md").is_file()) + self.assertIn("../ship/SKILL.md", skill) + self.assertTrue((REPO_ROOT / "skills" / "ship" / "SKILL.md").is_file()) + self.assertFalse((stub / "references").exists()) + self.assertFalse((stub / "templates").exists()) + self.assertFalse((stub / "agents").exists()) + + def test_short_ship_is_deprecation_stub(self) -> None: + stub = REPO_ROOT / "skills" / "short-ship" + skill = (stub / "SKILL.md").read_text(encoding="utf-8") + self.assertIn("name: short-ship", skill) + self.assertIn("已弃用", skill) + self.assertIn("../ship/SKILL.md", skill) + self.assertIn("short 模式", skill) + self.assertTrue((REPO_ROOT / "skills" / "ship" / "SKILL.md").is_file()) + self.assertFalse((stub / "references").exists()) + self.assertFalse((stub / "templates").exists()) + self.assertFalse((stub / "agents").exists()) + + def test_long_ship_is_deprecation_stub(self) -> None: + stub = REPO_ROOT / "skills" / "long-ship" + skill = (stub / "SKILL.md").read_text(encoding="utf-8") + self.assertIn("name: long-ship", skill) + self.assertIn("已弃用", skill) + self.assertIn("../ship/SKILL.md", skill) + self.assertIn("long 模式", skill) + self.assertTrue((REPO_ROOT / "skills" / "ship" / "SKILL.md").is_file()) self.assertFalse((stub / "references").exists()) self.assertFalse((stub / "templates").exists()) self.assertFalse((stub / "agents").exists()) diff --git a/tests/test_ship_record.py b/tests/test_ship_record.py index 7146802..6b429e8 100644 --- a/tests/test_ship_record.py +++ b/tests/test_ship_record.py @@ -203,16 +203,16 @@ def _create(root: Path, ship_id: str, kind: str, *, stop_at: str | None = None) return root / ".pouch" / "ship" / ship_id -def _next(root: Path, ship_id: str, entry: str) -> dict: - result = _run( - NEXT, +def _next(root: Path, ship_id: str, entry: str | None = None) -> dict: + args = [ "--project-root", str(root), "--ship-id", ship_id, - "--entry", - entry, - ) + ] + if entry is not None: + args.extend(["--entry", entry]) + result = _run(NEXT, *args) if result.returncode != 0: raise AssertionError(result.stderr or result.stdout) return json.loads(result.stdout) @@ -404,11 +404,36 @@ class NextStepTests(unittest.TestCase): self.assertIn("不要自己做", doc["summary"]) def test_entry_skills_are_managers(self) -> None: - for name in ("short-ship", "long-ship", "pr-ship"): + for name in ("ship", "pr-ship"): text = (REPO_ROOT / "skills" / name / "SKILL.md").read_text(encoding="utf-8") self.assertIn("开新 agent", text) self.assertNotIn("读取并执行", text) + def test_next_step_infers_entry_from_kind(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + _create(root, "add-export-button", "short", stop_at="verified") + doc = _next(root, "add-export-button") + self.assertEqual(doc["entry"], "short") + self.assertEqual(doc["step"], "write_spec") + + _create(root, "tenant-permissions", "long") + doc = _next(root, "tenant-permissions") + self.assertEqual(doc["entry"], "long") + self.assertEqual(doc["step"], "specifier_new") + + missing = _run( + NEXT, + "--project-root", + str(root), + "--ship-id", + "does-not-exist", + ) + self.assertEqual(missing.returncode, 0, missing.stderr) + blocked = json.loads(missing.stdout) + self.assertEqual(blocked["entry"], "short") + self.assertEqual(blocked["step"], "ensure_record") + if __name__ == "__main__": unittest.main()