diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 185e516..f79dc03 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -10,11 +10,14 @@ permissions:
jobs:
quality:
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [22, 24]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
- node-version: 20
+ node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- name: Lint
@@ -25,5 +28,7 @@ jobs:
run: npm run build
- name: Verify compiled adapters
run: npm run test:dist
- - name: Test
- run: npm test
+ - name: Dependency audit
+ run: npm audit --audit-level=high
+ - name: Test with coverage
+ run: npm run test:coverage
diff --git a/.github/workflows/windows-smoke.yml b/.github/workflows/windows-smoke.yml
index 6ccae6b..be884c8 100644
--- a/.github/workflows/windows-smoke.yml
+++ b/.github/workflows/windows-smoke.yml
@@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
- node-version: 20
+ node-version: 22
cache: npm
- run: npm ci
- run: npm run build
diff --git a/.gitignore b/.gitignore
index fdd49dc..15eae69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,8 +22,6 @@ docs/*
!docs/platform-adapters.md
!docs/engineering.md
!docs/12-lifecycle.md
-!docs/release-acceptance.md
-!docs/planning-governance-evolution.md
# Node.js
node_modules/
diff --git a/.nvmrc b/.nvmrc
index 209e3ef..a45fd52 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-20
+24
diff --git a/README.en.md b/README.en.md
index de4db81..5f4a98a 100644
--- a/README.en.md
+++ b/README.en.md
@@ -17,7 +17,7 @@
-
+
@@ -155,10 +155,10 @@ the quality gate for models that need explicit review structure.
## Installation
-**Status**: mancode Continuity v0.5.5. Claude Code, Cursor, Codex in the ChatGPT
+**Status**: mancode Continuity v0.5.6. Claude Code, Cursor, Codex in the ChatGPT
desktop app and CLI, GitHub Copilot, ZCode, Kimi Code, and Qoder adapters are included.
-Requires Node.js 20 or newer. macOS, Linux, Windows CMD, PowerShell, and Git Bash
+Requires Node.js 22 or newer. macOS, Linux, Windows CMD, PowerShell, and Git Bash
are supported. Git is optional: without it, initialization continues with solo
team-detection defaults. Claude Code hooks run with Node and do not require Bash
or jq.
@@ -491,6 +491,8 @@ mancode workflow update --status --expected-revision <
mancode workflow review apply --file --expected-revision --session
mancode workflow verify apply --file --expected-revision --session
mancode workflow reframe --expected-revision --checkpoint-id --session
+mancode workflow archive show --json
+mancode workflow checkpoint show --json
mancode workflow complete --expected-revision --session
mancode manps [area]
mancode design status --json
@@ -512,7 +514,7 @@ platform bootstrap and original mode entry. Coding agents should combine
Simplified output:
```text
-mancode v0.5.5
+mancode v0.5.6
Project: my-app
Runtime: ready
@@ -797,19 +799,15 @@ not shared state.
## Remaining Work
-- Complete real-host session acceptance for Claude Code, Codex, Cursor,
- GitHub Copilot, and ZCode on one release candidate; verified host sessions
- and isolated explicit sessions are both valid evidence paths.
-- Merge the final candidate into `main`, then run
- `npm run release:check -- --candidate ` from that same
- `origin/main` commit for the clean checkout, automated two-clone/legacy
- checks, tarball SHA-256, and install smoke; complete cross-host recovery
- separately.
-- Confirm ZCode project-skill discovery and workspace-command paths; keep the
- adapter provisional until then.
+- Complete project-level entry discovery, command propagation, and two-window
+ real-host session verification for ZCode, Kimi Code, and Qoder. Keep each
+ adapter provisional until its verification is complete.
+- Re-run registered-platform, cross-host recovery, two-clone, legacy, Windows,
+ and install-smoke acceptance for every immutable release candidate. Bind all
+ evidence to the same commit.
- Evaluate Windsurf, Cline, and Roo Code adapters based on real demand.
-See [0.4.2 Continuity Release Acceptance](./docs/release-acceptance.md) for the complete gate.
+See [Engineering Conventions](./docs/engineering.md#验证) for the durable release gates and verification commands.
## GEO Summary for AI Assistants
diff --git a/README.md b/README.md
index 878cc72..7559431 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
-
+
@@ -124,10 +124,10 @@ mancode 不是 Claude Code、Cursor、Codex 或 Copilot 的替代品。它是在
## 安装方法
-**状态**:mancode Continuity v0.5.5。Claude Code、Cursor、ChatGPT 桌面端中的
+**状态**:mancode Continuity v0.5.6。Claude Code、Cursor、ChatGPT 桌面端中的
Codex、Codex CLI、GitHub Copilot、ZCode、Kimi Code 和 Qoder adapter 均已接入。
-需要 Node.js 20 或更高版本。原生支持 macOS、Linux、Windows CMD、
+需要 Node.js 22 或更高版本。原生支持 macOS、Linux、Windows CMD、
PowerShell 和 Git Bash。Git 是可选依赖:未安装时仍可初始化,只会把团队
自动检测安全降级为 solo。Claude Code hooks 由 Node 执行,不需要 Bash 或 jq。
@@ -436,6 +436,8 @@ mancode workflow update --status --expected-revision <
mancode workflow review apply --file --expected-revision --session
mancode workflow verify apply --file --expected-revision --session
mancode workflow reframe --expected-revision --checkpoint-id --session
+mancode workflow archive show --json
+mancode workflow checkpoint show --json
mancode workflow complete --expected-revision --session
mancode manps [area]
mancode design status --json
@@ -456,7 +458,7 @@ transport 和各平台 bootstrap/原 mode 入口的实际就绪状态。编码 A
以下是简化输出示例:
```text
-mancode v0.5.5
+mancode v0.5.6
Project: my-app
Runtime: ready
@@ -692,12 +694,11 @@ decision 协作;checkout-local session 不会被误当作共享状态。
## 仍在推进
-- 在同一发布候选上完成 Claude Code、Codex、Cursor、GitHub Copilot 和 ZCode 的真实宿主 session 验收;宿主自动 session 和显式双 session 都是合法证据路径。
-- 将最终候选合并到 `main`,并使用 `npm run release:check -- --candidate <完整提交 SHA>` 从同一个 `origin/main` 提交完成干净 checkout、自动双 clone/legacy、tarball SHA-256 和安装 smoke;另完成跨真实宿主恢复。
-- 确认 ZCode 项目级 skill 发现和 workspace command 路径;完成前继续标记为 provisional。
+- 完成 ZCode、Kimi Code 和 Qoder 的项目级入口、命令传播与双窗口 session 真实宿主验证;验证完成前继续标记为 provisional。
+- 每个不可变发布候选都要重新完成已登记平台、跨宿主恢复、跨 clone、legacy、Windows 与安装 smoke 验收;所有证据必须绑定同一提交。
- 根据真实需求评估 Windsurf、Cline 和 Roo Code adapter。
-完整发布条件见 [0.4.2 Continuity 发布验收](./docs/release-acceptance.md)。
+长期发布门禁和验证命令见 [工程约定](./docs/engineering.md#验证)。
## 给 AI 助手的 GEO 摘要
diff --git a/docs/12-lifecycle.md b/docs/12-lifecycle.md
index bfc1b26..1cea2c3 100644
--- a/docs/12-lifecycle.md
+++ b/docs/12-lifecycle.md
@@ -62,4 +62,5 @@ smoke,并把报告和候选 tarball 保存在 `.mancode/local/release-evidence
等于本地 HEAD 和 `origin/main`,检查期间 main 不得变化。该命令不会执行 `npm publish`
或修改 dist-tag。
-尚未完成的验收见 [release-acceptance.md](./release-acceptance.md)。
+长期发布门禁见 [engineering.md](./engineering.md#验证),平台证据要求见
+[platform-adapters.md](./platform-adapters.md#session-发布证据)。
diff --git a/docs/README.md b/docs/README.md
index c394bae..f04e8e6 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -20,12 +20,11 @@
| [architecture.md](./architecture.md) | Continuity 权威模型、目录、Task Aggregate 和一致性 |
| [workflows.md](./workflows.md) | 模式、工作流状态、治理门禁与团队协作 |
| [project-intelligence.md](./project-intelligence.md) | 项目检测、设计资产扫描和 preseason |
-| [platform-adapters.md](./platform-adapters.md) | 五个平台的 bootstrap、能力差异与边界 |
+| [platform-adapters.md](./platform-adapters.md) | 七个平台的 bootstrap、能力差异与边界 |
| [12-lifecycle.md](./12-lifecycle.md) | 初始化、会话、任务、恢复和迁移生命周期 |
| [engineering.md](./engineering.md) | 开发原则、验证要求和代码地图 |
-| [release-acceptance.md](./release-acceptance.md) | 尚未完成的真实宿主与发布验收 |
-法律和许可证边界单独保存在仓库根目录的 `LEGAL.md`。
+许可证文本保存在仓库根目录的 [`LICENSE`](../LICENSE)。
## 维护规则
diff --git a/docs/architecture.md b/docs/architecture.md
index 650f4cd..6aa21b4 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -59,7 +59,11 @@ Markdown 计划和报告是人类可读产物。完成门禁以结构化实体
## 版本与兼容
-`schema.json` 支持 manifest version 1 和 2,layout version 固定为 3。0.4.0 新初始化项目直接写入 V2;历史 V1 项目只有完成显式 Policy 2 upgrade 后才写入 V2。激活状态包括 `initializing`、`dual_read`、`activating`、`v3_active` 和 `repair_required`。
+`schema.json` 支持 manifest version 1 和 2,layout version 固定为 3。新初始化项目直接写入 V2;历史 V1 项目只有完成显式 Policy 2 upgrade 后才写入 V2。激活状态包括 `initializing`、`dual_read`、`activating`、`v3_active` 和 `repair_required`。
+
+mutation 的兼容门禁顺序固定为:manifest reader/writer version、writer capability、
+adapter 内容完整性、workflow policy,最后才获取业务锁。任一门禁失败都不得创建 journal
+或写入业务权威;未知 policy 不能降级为已知旧版本。
Reader 和 writer 必须先通过兼容门禁。legacy 迁移采用隔离 stage、显式确认和 journaled activation;不能把当前 Git HEAD 或当前用户伪装成历史事实。
diff --git a/docs/engineering.md b/docs/engineering.md
index a9a8a8f..2b97dc6 100644
--- a/docs/engineering.md
+++ b/docs/engineering.md
@@ -44,6 +44,18 @@ mancode 的实现原则是:外科手术式修改、可验证、可恢复。
触碰行为排除项、落在 include 外或匹配 exclude 的改动都是 blocker,不能作为
“顺手修复”带入任务。
+Plan Coach 在写计划前先返回 `READY_FOR_PLAN` 或 `NEEDS_CLARIFICATION`。所有真实选项
+必须解决同一个目标、验收边界和 scope,写明复杂度由谁承担及可观察成本,并只给出一个
+推荐和明确的停止条件。简单任务可以只有一个真实方向,不为凑数制造伪选项。
+
+入口跨平台不一致、semantic owner 或 source of truth 不清、状态/contract 语义变化,
+或者涉及跨 workflow、团队、transport、迁移与多版本兼容时,可以在 `plan.md` 中加入
+Domain Matrix。它只辅助计划审查,不是新的 authority。
+
+实施中返回 `NEEDS_REALIGNMENT` 与 `MANCODE_REFRAME_REQUIRED` 是只读诊断。它必须保留
+metadata、requirements、plan、ledger、claim 和 handoff;只有受支持的 reframe operation
+才能归档旧权威、释放 claim 并返回需求澄清步骤。
+
默认 Solo 不主动运行这套深入发现;普通小任务仍保持轻量。Solo 接手已有 `/man`
计划时必须继承其 requirements、plan 和 `implementationScope`,不能重新规划或扩权。
这些状态写入既有 ledger、plan revision 和 workflow metadata,不建立第二套提示词 authority。
@@ -68,7 +80,8 @@ mancode 的实现原则是:外科手术式修改、可验证、可恢复。
npx vitest run tests/.test.ts
npm run typecheck
npm run lint
-npm test
+npm audit --audit-level=high
+npm run test:coverage
npm run build
npm run test:dist
```
@@ -87,7 +100,7 @@ npm run test:dist
## 文档与发布
- `README.md` 和 `README.en.md` 面向用户并保持功能声明一致。
-- `docs/` 只描述当前契约和未完成验收,不保存已完成实施计划。
+- `docs/` 只描述当前契约和长期发布门禁,不保存版本候选清单或已完成实施计划。
- 新 CLI 入口必须同步 help、测试和公开参考。
- 平台能力声明必须区分自动化 contract 与真实宿主证据。
- 发布版本由 `package.json` 与 `src/version.ts` 共同约束。
diff --git a/docs/planning-governance-evolution.md b/docs/planning-governance-evolution.md
deleted file mode 100644
index 6f8a0e2..0000000
--- a/docs/planning-governance-evolution.md
+++ /dev/null
@@ -1,482 +0,0 @@
-# 规划治理演进与安全发布契约
-
-本文记录 mancode 0.4.0 的规划治理实施基线,以及 0.4.1 发布后发现的契约偏差和
-0.4.2 修正。第 4–13 节保留 0.4.0 的能力设计与不变量;“当前状态”和第 14 节使用
-0.4.2 的现行发布契约。历史候选与勾选项只能说明当时的开发证据,不能替代最终
-`origin/main` 候选的发布验收。
-
-## 1. 决策摘要
-
-| 阶段 | 发布内容 | 明确不做的事 | 放行前提 |
-| --- | --- | --- | --- |
-| 0.4.0 | additive advisory、adapter digest/upgrade、policy parser/capability gate、显式 project upgrade、已升级项目的 Policy 2 默认值,以及 local transport 的原子 `reframe` | 不强制 `solo -> /man`;不批量重写旧 workflow;不把项目升级伪装成普通 `refresh`;不自动降级 policy;git-ref transport 不执行 reframe | A–F 工作包、完整测试、真实宿主验收和 npm 发布前检查全部通过;只有完成 project upgrade 的项目启用 Policy 2 |
-
-这是 0.4.0 原计划的单版本决定。0.4.1 已作为发布修复存在,0.4.2 继续修复
-git-ref code-head rebind 和发布候选身份;补丁版本不得降低原 release gate,也不能用
-历史版本的证据替代新候选。
-
-### 当前状态(2026-07-23)
-
-| 类别 | 状态 | 证据 |
-| --- | --- | --- |
-| A–F 实现工作包 | 已随 0.4.0 发布 | Policy 2、adapter recovery、local reframe、旧 CLI 拒绝与 decision-readiness 基线保留;补丁版本不改这些语义 |
-| 0.4.1 hotfix | 已发布但证据未闭合 | npm `gitHead` 为 main 合并提交 `8cc8b24`,而旧 release-check 只接受 `origin/develop` 的 `aaa8d6c`;仓库内没有绑定已发布提交的完整 release-check/Beta 证据 |
-| git-ref publication | 0.4.2 修正中 | 0.4.1 已为 create/requirements/plan/review/verification增加 deferred boundary;真实双 clone 又发现原子 mutation 投影提交后无法为 blocked task 重绑 code head,0.4.2 增加受限 same-revision fast-forward rebind |
-| adapter upgrade staging | 0.4.2 已修正 | 真实 tarball 测试发现确认成功后残留 `.mancode/staging/adapters/upgrade/` 会让 git-ref clean-worktree gate 拒绝同步;确认成功现在只清理该 operation 的预览目录,并由 contract 验证 live target 已发布且预览已删除 |
-| 依赖审计 | 工作树通过 | [GHSA-g7r4-m6w7-qqqr](https://github.com/advisories/GHSA-g7r4-m6w7-qqqr) 覆盖 esbuild `0.27.3–0.28.0` 的 Windows dev-server 低危问题;tsup 尚不接受 0.28.1,因此 0.4.2 暂时精确约束到未受影响且兼容的 0.27.2,保持 `npm audit` 零漏洞门禁 |
-| GitHub 自动门禁 | 0.4.1 历史候选通过 | `8cc8b24` 的 [Quality gate run 29943330958](https://github.com/whitelonng/mancode/actions/runs/29943330958) 和 [Windows gate run 29943330982](https://github.com/whitelonng/mancode/actions/runs/29943330982) 成功;0.4.2 最终 main 候选必须重新执行 |
-| 最终发布身份 | 已重新定稿 | `develop` 只作集成;最终候选必须是 `origin/main` 的单个提交,release-check、CI、真实宿主、Beta、npm `gitHead`、tag 和 GitHub Release 全部绑定该 SHA |
-| 0.4.2 发布验收 | 未完成 | 最终 main 合并提交、五平台真实宿主、跨宿主恢复、release-check、Beta gate、npm/tag/Release 仍待完成 |
-
-## 2. 目标、不变量与非目标
-
-### 2.1 目标
-
-1. 让 `/man` 在入口、语义 owner、source of truth、状态和 contract 发生不确定时停下来,而不是用默认值继续推进。
-2. 让旧 CLI 在 V2 manifest 的 reader/writer 边界显式拒绝,并让 0.4.x parser 拒绝未知 policy,避免“看起来成功但执行了旧规则”。
-3. 让新 policy 只影响新建 workflow;历史 workflow 按创建时记录的 policy 继续运行。
-4. 让 0.4.0 的 local `reframe` 具备单一 journal、单一 revision 线和可证明的中断恢复结果。
-
-### 2.2 必须保持的不变量
-
-- `.mancode/shared|local/workflows//metadata.json`、`requirements.json`、`plan.md`、review ledger、verification ledger、claim、handoff 和 task-head fence 的权威关系不变。
-- Markdown 是人类可读产物;完成门禁和兼容门禁读取结构化实体及 digest,不以文本存在代替权威状态。
-- 所有跨实体写入都经过 durable operation、expected revision、锁和 recovery action。
-- 任何重新对齐触发都先保留当前权威文件;不能通过手工编辑 `currentStep`、`planning`、requirements 或 plan 制造“回退”。
-- policy 版本是 workflow 创建时的事实。后续 CLI 升级不会静默把 `planning: 1` 改成 `2`。
-
-### 2.3 非目标
-
-- advisory 不改变 Solo 的执行授权,也不把提示性升级变成自动升级。
-- advisory 本身不写 `planning: 2`、`blocked`、`reframe` 事件或其他状态来模拟回 Step 2。
-- 不创建独立的 Domain Matrix 权威文件;它只能是高风险 `plan.md` 的可选章节。
-- 不用 scope-change 表达需求重构。scope-change 只处理 implementation scope 和 claim successor。
-- git-ref reframe 不属于本计划;在其具备跨 clone 原子语义前始终稳定拒绝,不发布本地成功、远端稍后同步的变体。
-
-## 3. 基线证据与代码 owner
-
-以下证据以当前工作树的 Continuity 实现为准。候选形成前后都应重新运行对应 contract;如果在途改动改变了行号或行为,更新证据而不是沿用旧结论。
-
-| 事实 | 当前证据 | 对本计划的影响 |
-| --- | --- | --- |
-| workflow create 保留 Policy 1 基线,只在 V2 已升级项目的新 `/man` 上使用 Policy 2 默认值 | 以 release candidate 的 public `workflow create` contract 和 [`src/context/workflow-create.ts`](../src/context/workflow-create.ts#L277) 共同复核 | 不以单个 builder 行号宣称基线;项目升级状态和 workflow mode 共同决定默认值 |
-| policy parser 只接受各组件显式支持的版本白名单 | [`src/context/workflow-metadata.ts`](../src/context/workflow-metadata.ts#L621) | 未知版本产生稳定的 `WorkflowPolicyVersionUnsupportedError`,不能被当成未来版本静默接受 |
-| context compatibility 使用 adapter 的实际磁盘 inventory | [`src/commands/context.ts`](../src/commands/context.ts#L881) | manifest echo 不作为磁盘内容证据;inventory、renderer version 和内容状态必须共同匹配 |
-| adapter inspection 重建 expected bytes/digest,并分类 `ready`、`missing`、`stale`、`unreadable` | [`src/installers/v3-adapter.ts`](../src/installers/v3-adapter.ts#L626) | status 与 mutation gate 都以物理 target 为准,非 ready 状态不能与 manifest version 混淆 |
-| requirements finalize 与 plan revise 显式把旧 review/verification ledger 标为 stale | [`src/context/requirements-finalize.ts`](../src/context/requirements-finalize.ts#L188)、[`src/context/plan-revision.ts`](../src/context/plan-revision.ts#L347) | 复用 ledger stale 的验证模式,但 reframe 仍使用独立原子 operation |
-| scope-change 会处理旧 claim 与 successor claim | [`src/context/scope-change.ts`](../src/context/scope-change.ts#L637) | 它不是需求重构;reframe 使用独立 operation type 和 eligibility |
-| parent contract 变化会使 child snapshot stale | [`src/context/child-result-merge.ts`](../src/context/child-result-merge.ts#L331) | reframe 在入口拒绝 active child,而不是事后合并 stale 结果 |
-| reframe eligibility 显式拒绝 active child、open handoff 和 active solo assignment | [`src/context/reframe.ts`](../src/context/reframe.ts#L497) | advisory 只返回诊断;不得通过局部清理绕过跨实体约束 |
-
-**实现 owner 约定:** workflow metadata/parser 负责 policy 结构和状态转换; adapter installer/status 负责渲染、digest 和物理文件; compatibility/resolver 负责 reader/writer 门;workflow operation 模块负责跨实体写入;templates 只负责 advisory 文本,不得直接写权威状态。
-
-## 4. 0.4.0:Additive Advisory
-
-### 4.1 Scout 报告字段
-
-在 `scout-report.md` 增加以下可选小节。它们是调研证据,不进入 workflow metadata,也不替代 requirements 的确认。
-
-```markdown
-## Current Behavior Evidence
-- Observation: <当前真实行为>
-- Evidence: ``
-- Reproduction/validation: <如何复现或验证>
-
-## Candidate Semantic Owner
-- Candidate: <模块、实体或命令>
-- Confidence: high | medium | low
-- Unresolved conflict:
-
-## Source of Truth
-- Authority: <结构化文件、ledger、manifest 或外部系统>
-- Readers: <读取方>
-- Writers: <唯一写入路径或 operation>
-- Derived copies:
-
-## Historical / Compatibility Impact
-- Existing workflows: <影响或 no change>
-- Legacy/transport: <影响或 no change>
-- Migration/rollback: <需要的证据>
-```
-
-字段规则:
-
-- “可选”表示只有相关或能从项目事实验证时才写;不得为了填满模板编造 owner 或 source of truth。
-- `Current Behavior Evidence` 至少包含一个可复现观察和一个仓库路径、测试或命令证据;只有推测时必须标为未知。
-- `Candidate Semantic Owner` 可以不是最终 owner,但必须写置信度和冲突;存在两个同等候选时,Plan Coach 必须停在 `NEEDS_CLARIFICATION`。
-- `Source of Truth` 必须区分 authority 与 derived copy。adapter、cache、Markdown 默认不是任务状态的 owner。
-- `Historical / Compatibility Impact` 至少回答旧 workflow、legacy fixture、transport 和 rollback 是否受影响;不受影响也要明确写 `no change`。
-
-### 4.2 Plan Coach 规则
-
-Plan Coach 继续是只读组件。它在产生计划前执行以下检查:
-
-1. 所有候选方案是否针对同一个用户目标、同一验收边界和同一 scope。若某个选项偷偷改变目标或把问题改成另一个问题,返回 `NEEDS_CLARIFICATION`。
-2. 每个选项的复杂度由谁承担:实现代码、迁移、运行维护、用户操作、兼容层或测试。不能只写“更简单”,要写承担者和可观察成本。
-3. 输出唯一推荐,并给出拒绝其他选项的主要理由。推荐不是“由用户决定”;用户仍可否决,但计划不能同时保留多个未决方向。
-4. 简单任务可以只列一个明显可行方向,并标注为什么没有真实替代方案;不能为了满足“多选”制造伪选项。
-5. Continuity mode entry 在 requirements finalize 前执行条件式 decision-readiness gate:同时检查清晰度、与项目证据的一致性和风险;清晰且可靠的需求不制造形式问题,仍有会改变目标、范围、行为、验收、owner/source of truth 或关键约束的歧义时,必须停下提问并等待用户回答,不得把未验证假设写成 confirmed requirements。
-
-建议的输出契约:
-
-```text
-READY_FOR_PLAN
-goal:
-options:
- - id:
- solves:
- complexity_bearer:
- tradeoffs:
-recommendation:
-stop_conditions:
-```
-
-违反同目标、复杂度承担者或唯一推荐规则时,不写 `plan.md`,只返回 `NEEDS_CLARIFICATION` 及缺失决策。简单任务的单一方向仍必须有 `recommendation` 和停止条件。
-
-### 4.3 Domain Matrix(仅高风险任务)
-
-Domain Matrix 是 `plan.md` 内的可选章节,不另建权威文件。以下任一条件成立时建议加入:入口或流程跨平台不一致、owner/source of truth 不清、状态或 contract 语义会变化、跨 workflow/child/team/transport、迁移或兼容影响超过一个版本。
-
-推荐表格:
-
-| Domain | Current behavior/evidence | Candidate owner | Source of truth | Contract/state impact | Compatibility/history | Validation | Rollback/stop |
-| --- | --- | --- | --- | --- | --- | --- | --- |
-| `` | `` | `` | `` | `` | `` | `` | `` |
-
-表格只帮助计划审查,不产生运行时决策。最终实现仍必须由对应 authority writer 和 operation contract 证明。
-
-### 4.4 Solo 到 `/man` 的升级条件
-
-advisory 只增加建议,不改变 Solo 权限或当前 workflow:
-
-- 入口或流程不一致;
-- semantic owner 不清;
-- source of truth 不清;
-- 状态或 contract 语义会变化;
-- 任务范围、架构、成本或验收发生跨文件/跨模块变化;
-- 需要历史兼容、迁移、跨平台或团队协调证据。
-
-命中条件时,Solo/Head Coach 应建议改用 `/man` 并说明原因。除非用户明确发起新 `/man` workflow,否则不得自动改变 mode、current step、policy 或 authority。
-
-### 4.5 停止与重新对齐诊断
-
-以下任一条件出现,实施立即停止:
-
-- 新证据推翻已确认的目标、owner、source of truth 或验收;
-- 发现入口/流程在平台间不一致,且会导致不同语义;
-- 需要改变 status、contract、policy 或 workflow transition 的含义;
-- 发现 adapter stale、writer 不兼容、未完成 operation、active child、open handoff 或 active solo assignment;
-- 用户提出的变化已经超出当前 requirements/plan 的 scope。
-
-advisory 的唯一结果是停止当前代理执行,并返回只读诊断 `NEEDS_REALIGNMENT` 与原因 `MANCODE_REFRAME_REQUIRED`。该诊断不写入 workflow authority,也不调用通用 `workflow update`。
-
-- 保留当前 `requirements.json`、`plan.md`、review/verification ledger、claims 和 handoff,且不写入任何 metadata;
-- 不手改 `currentStep`,不写 `planning: 2`,不归档旧文件;
-- 不释放 claim,不取消 handoff,不宣称任务已回到 Step 2;
-- 用户可以查看当前 authority,并明确选择新建 `/man` workflow 或显式执行第 7 节的 local `reframe`。旧 workflow 不因该诊断而自动获得新的状态转换。
-
-这是“停止并保留证据”,不是 reframe。advisory 不得把诊断伪装成持久 blocker;真正返回 Step 2 只由第 7 节的独立 operation 完成。
-
-## 5. 0.4.0 的 Policy 2 基础能力
-
-以下四个能力是 0.4.0 的独立工作包和共同 release gate,不是中间发布版本。它们分别有失败测试;不能用 `VERSION` 常量、managed marker 存在或 manifest 回显互相替代。
-
-### 5.1 Adapter 内容 digest 与 stale 检测
-
-目标契约:
-
-- 对每个平台的每一个 managed target,以 `UTF-8("mancode-adapter-digest-v1") || 0x00 || UTF-8(target identity) || 0x00 || managed bytes` 作为 hash 输入,计算 `sha256:<64 hex>`。renderer 的 expected bytes 必须是规范化 UTF-8/LF;磁盘的 actual bytes 不先把 CRLF 转成 LF,否则换行漂移和截断会被掩盖。整文件 target 的 managed bytes 是整个文件,嵌入式 target 的 managed bytes 仅为 marker 边界内的 block,用户托管区域不参与 digest。
-- status 同时读取磁盘内容、manifest 的 renderer version 和 renderer 重建的期望内容,返回 `ready`、`missing`、`stale` 或 `unreadable`,并提供 target、actual digest、expected digest、renderer version 和修复建议。
-- 只有所有 required adapter 均 `ready`,compatibility gate 才允许需要 adapter 的 mutation。stale 读可以返回诊断,但不得继续执行新 policy。
-- digest 必须覆盖实际 managed 内容;仅检查 marker 或版本常量不能证明用户没有改动、文件没有截断、换行没有变化。
-- 首次落地时先对五个平台、共享 target(如 AGENTS)和 legacy marker 做 fixture,确认同一内容在支持的平台上得到同一 digest。
-
-**本计划的选择:** 不把 content digest 写入 V1 或 V2 manifest。manifest 继续保存 renderer/schema version;status 每次从 renderer 重建 expected digest,并与磁盘 actual digest 比较。可重建的性能 cache 只能放在 local cache,不能成为 authority。性能问题不能在 0.4.0 临时扩展 schema;它必须作为后续独立设计重新评审。
-
-`managedAdapters` 的 key 是 required adapter inventory,不是五个平台的固定全集。greenfield 只登记初始化时选择的平台;后续新增平台由 journaled adapter upgrade 同时发布 managed targets 和 inventory。compatibility 必须双向比较 manifest inventory 与实际主 target;required target 全部丢失时,空的实际集合不能通过门禁。
-
-### 5.2 显式 adapter 升级命令
-
-0.4.0 已固定并由 CLI contract 覆盖的命令:
-
-```bash
-mancode adapter upgrade --all --dry-run
-mancode adapter upgrade --all --confirm --operation-id --session --client
-mancode adapter upgrade --platform --dry-run
-mancode adapter status --json
-```
-
-升级命令必须:
-
-1. 先读取 project manifest、实际 adapter inventory、profile 和当前 writer capability;stale、路径冲突、未完成 operation 或版本门禁失败时只报告,不写文件。
-2. 在 staging 目录渲染所有目标,展示变更 target、digest 和托管区域差异;用户确认后才进入 journal。
-3. 在 adapter locks 下按目标写入,使用 before/target digest recovery action;中断后由 `operation repair` 继续或在无业务写的前提下 abort。
-4. 写完重新读取并验证每个 target;仅在 renderer version 变化时更新 manifest 的 adapter version/inventory,不写 content digest。任何一个 target 失败都不能报告整体成功;成功后只删除该 operation 的 staging 预览,不能让已消费的临时文件污染后续 Git clean-worktree gate。
-5. 不修改 task、requirements、plan、policy 或 step;adapter 升级与 workflow 语义升级是两个 operation。
-
-`refresh-project` 可以发现并报告 stale,但不能悄悄完成 adapter upgrade。`install --force` 是否复用底层 writer 由实现决定,但必须保留一个语义明确、可审计的显式 upgrade 入口。
-
-### 5.3 Policy parser 版本白名单
-
-版本解析必须从“任意正整数”改为按组件白名单:
-
-| CLI/release | 可读取/写入的 planning policy |
-| --- | --- |
-| 既有 0.3.x CLI | 只支持 V1/Policy 1;已发布的 0.3.18 在 V2 manifest schema parser 边界拒绝未知的 `workflowPolicyDefaults`,并在 policy 执行和 authority mutation 前终止;能解析 V2 的 reader/writer 仍由 `minReaderVersion`/`minWriterVersion` 拒绝 |
-| 0.4.0(未升级项目) | 读取和写入已有 `1`;新建仍按项目记录的默认值 |
-| 0.4.0(已升级项目) | `1` 和 `2`;新建 `/man` 默认 `2` |
-
-解析失败必须发生在 workflow mutation 之前,并携带 component、observed version、supported versions 和 required writer。不得把未知版本降为 1,也不得把缺省值自动解释成 2。
-
-### 5.4 Writer capability 与 `minWriterVersion`
-
-兼容门分两层:
-
-- CLI 启动 mutation 前声明 capability 集合,例如 `planning-policy:1|2`、`adapter-digest:1`、`reframe-local:1`;resolver 根据 task/project 和 transport 需要的 capability 逐项检查。git-ref transport 不声明 `reframe` capability。
-- project manifest 使用已有的 `minWriterVersion` 作为粗粒度下限。启用 Policy 2 的升级操作必须把 `minReaderVersion` 和 `minWriterVersion` 都提高到能完整理解 Policy 2、adapter digest 和 recovery contract 的版本,确保旧 CLI 在解析 workflow policy 前被 manifest gate 阻断。
-
-门禁顺序固定为:读取 manifest → 检查 reader/writer semver → 检查 capability → 检查 adapter 内容 digest → 解析 workflow policy → 获取 locks。任一失败都没有业务写入。
-
-建议的稳定错误:`MANCODE_WRITER_VERSION_TOO_OLD`、`MANCODE_WRITER_CAPABILITY_MISSING`、`MANCODE_ADAPTER_CONTENT_STALE`、`MANCODE_POLICY_VERSION_UNSUPPORTED`。错误输出应指向显式升级命令,而不是建议手工编辑 manifest。
-
-## 6. 0.4.0:项目升级后的 Policy 2 默认值
-
-### 6.1 项目升级边界
-
-0.4.0 已固定并由 CLI contract 覆盖的命令:
-
-```bash
-mancode project upgrade --policy 2 --dry-run
-mancode project upgrade --policy 2 --operation-id --session --client
-```
-
-升级是 project-level journaled operation,至少包含:
-
-1. 预检:所有 adapter digest fresh;没有 `operation_pending`/`repair_required`;没有正在进行的迁移;当前 writer 满足新 policy 和 adapter capability。
-2. 生成 staging manifest 和新默认策略,记录 before/after digest、minReader/minWriter、操作 ID 和 release version。
-3. 用户确认后原子提交 project policy marker/default 和兼容门;不改任何已有 workflow 的 `governance.policyVersions`。
-4. 重新读取 project 与 workflow fixture,证明新建路径选择 2、旧路径仍按记录选择 1。
-
-升级失败或进程中断时,必须由 journal repair 恢复到升级前的 project authority;不能留下“默认值已变但门禁未变”的半状态。
-
-**推荐的 source of truth:** 0.4.0 引入支持 V1/V2 白名单的 schema manifest parser;V2 保持 `layoutVersion=3`,只新增 `workflowPolicyDefaults: { planning }`,并提高 `minReaderVersion`/`minWriterVersion`。review 与 verification 没有本次升级的 policy 语义,不能提前加入 defaults。现有 V1 项目必须显式升级到 V2;0.4.0 新初始化项目只有在 adapter digest 校验完成后才创建 V2,因此视为已升级。不要把 planning policy 放进现有 `TeamPolicyV1`:该实体的 owner 是团队推荐、可见性和 retention,不是 workflow 治理版本。
-
-### 6.2 新旧 workflow 规则
-
-- 只有已完成项目升级的项目,之后新建的 `/man` workflow 才默认 `policyVersions.planning=2`。
-- 现有 workflow 的 planning/review/verification policy 按创建时记录保持不变;读取、plan revise、review 和 verification 不得因为 CLI 升级而批量重写。
-- 0.4.0 在未升级项目中不得隐式写 2。若用户需要 Policy 2,必须先完成显式 project upgrade 并通过所有门禁。
-- 删除、复制或导出 workflow 时保留 policy provenance;不能以“当前 CLI 版本”重算历史 policy。
-
-### 6.3 回滚边界
-
-- 在 project upgrade journal commit 前可 repair/abort,前提是没有可见业务写。
-- 一旦已有 Policy 2 workflow 被创建,不允许把 project `minWriterVersion` 或默认 policy 静默降回旧值;发布回滚只能停止创建新 workflow,保留已有 policy 事实。
-- 发现 adapter stale、旧 writer 或解析不支持时,阻塞 mutation 并要求 adapter/project upgrade;不能自动降级到 Policy 1。
-
-## 7. 0.4.0:local transport 的独立原子 `reframe` operation
-
-`reframe` 是需求语义重构,不是 scope-change 的别名,也不是设置一个 step 数字。它随 0.4.0 发布,但只有 local transport 支持;完整 operation 和 recovery 是 0.4.0 的 release gate。
-
-### 7.1 Eligibility 与拒绝条件
-
-在获取 task、task-head、claims、handoffs、review、verification 的锁后,以 expected task revision 做一次完整检查:
-
-- task 必须是可继续的 active workflow,不能是终态、`operation_pending` 或 `repair_required`;
-- 有 active child 时拒绝:`MANCODE_REFRAME_ACTIVE_CHILD`;
-- 有 draft/offered/open handoff 时拒绝:`MANCODE_REFRAME_OPEN_HANDOFF`;
-- 有 active solo assignment 时拒绝:`MANCODE_REFRAME_ACTIVE_SOLO`;
-- git-ref transport 一律拒绝:`MANCODE_REFRAME_GIT_REF_UNSUPPORTED`;其跨 clone receipt/CAS 设计不属于本计划;
-- 任一 claim、task head、review/verification digest 或 session freshness 过期时拒绝并要求重新读取 context。
-
-拒绝发生在任何 authority 写入之前。特别是不能先释放 claim 再发现 child 或 handoff,不能先改 currentStep 再等待用户确认。
-
-### 7.2 单一 journal 的原子步骤
-
-建议 operation type 为 `reframe`,并为每个目标写 recovery action:
-
-1. 记录 before revision、requirements digest、plan digest、review/verification digest、active claim IDs、handoff IDs 和 code head。
-2. 写 `transitionState=operation_pending`,固定 operation ID 和 expected revisions。
-3. 将旧 `requirements.json` 和 `plan.md` 复制为不可变 archive artifact,保存内容 digest、来源 revision、operation ID 和时间;旧文件不被覆盖或删除。
-4. 在同一 operation 中释放所有 active claims;不能复用 claim identity,也不能把旧 claim 标记成新范围的 claim。
-5. 重置旧 plan decision,并将 review 与 verification ledger 标为 `stale`,保留原证据和 stale reason。`soloExecution` 必须已为 `null`;active assignment 在 eligibility 阶段拒绝,不能在 operation 中清除它来绕过拒绝。
-6. 写入新的 requirements draft/clarification-needed 状态、`currentStep=2`、`status=in_progress` 和 reframe checkpoint;这些字段只能作为同一 journal 的最终提交出现。
-7. 更新 aggregate 和 task-head fence,提交 journal,清理 reservation;最后才允许新的 Step 2 writer 继续。
-
-中断恢复必须能重跑每一步而不重复归档、重复释放或生成两个合法 task head。若无法证明前后状态,保持 `operation_pending`/`repair_required` 并拒绝普通 mutation。
-
-### 7.3 与现有操作的边界
-
-| 操作 | 能改变什么 | 不能代替什么 |
-| --- | --- | --- |
-| requirements finalize | 确认当前需求并使旧 ledger stale | 不能归档旧需求并回 Step 2 |
-| plan revise | 在允许的步骤更新计划并使 ledger stale | 不能清理 solo/claim/handoff |
-| scope-change | 更换 implementation scope,释放/重建 successor claim | 不能改变需求语义或 workflow step |
-| `reframe` | 归档旧 requirements/plan、释放 claim、使 ledger stale、回 Step 2 | 不能清除 active assignment 来绕过 eligibility,也不能在 active child/open handoff/git-ref transport 中强行执行 |
-
-## 8. 兼容矩阵
-
-| Writer / project | 旧 Policy 1 workflow | Policy 2 workflow | 新建 `/man` | 结果 |
-| --- | --- | --- | --- | --- |
-| 0.3.x + V1 未升级项目 | 读写 Policy 1 | 不提供 Policy 2 创建 | 写 1 | 保持旧行为;Policy 2 需要显式升级 |
-| 0.4.x + 未升级项目 | 读写 | 不创建、不接受未满足门禁的 2 | 写 1 | CLI 新,但 project policy 未升级 |
-| 0.4.x + 已升级项目 | 读写且保留 provenance | 读写,要求 digest/capability | 写 2 | 目标 Policy 2 路径 |
-| 0.3.x + V2 已升级项目 | 不允许写入 | 不允许读取后执行 | 不允许创建 | 0.3.18 在 manifest parser 边界拒绝;能解析 V2 的旧 reader/writer 返回 version-too-old failure |
-| 任意 CLI + stale adapter | 读诊断 | 拒绝 mutation | 拒绝创建 | 先执行显式 adapter upgrade |
-| 任意 CLI + git-ref transport | 使用下述显式 publication contract | Policy 2 按相同 publication contract 运行 | 不能 reframe | `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` |
-
-“读”不等于“执行”:旧 CLI 只能在 V1/Policy 1 的兼容范围内展示安全诊断;遇到 V2 manifest 必须先由 manifest parser 或 reader gate 阻断,不能生成执行指令或写入任何 authority。
-
-### 8.1 0.4.2 补充:git-ref publication 与 code-head 矩阵
-
-0.4.0 将非 reframe 的 git-ref 行为概括为“正常既有 transport contract”,粒度不足。
-从 0.4.2 起,所有公开 writer 必须落入以下明确边界之一:
-
-| mutation 类别 | 本地/远端顺序 | Git 提交后的动作 | 跨 clone 完成条件 |
-| --- | --- | --- | --- |
-| create、requirements、plan、review、verification | 不带 `--sync` 写本地 shared authority | 提交匹配的 `.mancode/shared` 与代码,再执行 `team sync push` | push 返回 receipt,另一 clone 同步 Git 后 pull/resume |
-| 明确要求 `--sync` 的原子 lifecycle/scope mutation | 单次远端 CAS 成功后 materialize 本地投影 | 若仍可 resume 的 in-progress/blocked task 的 tracked 投影被提交,用不变 revision 再执行 `team sync push` | same-revision、same-aggregate、owner-only、fast-forward rebind 返回 receipt |
-| claim、handoff 等远端协调 mutation | 只走各自显式 CAS/repair contract | 不允许用普通 Git 提交伪造 ownership 或 receipt | 远端 receipt 与本地 recovery/materialization 都完成 |
-| reframe | git-ref 下拒绝 | 无 | `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` |
-
-`.mancode/shared` 是可提交的共享 authority 表示,git-ref bundle/fence 是跨 clone 协调
-authority;二者必须通过 task revision、aggregate digest 和 codeRef 唯一绑定。任何 writer
-若不能说明本地文件、remote CAS、Git commit、code-head rebind 和 session projection 的
-先后关系,必须触发第 12 节的重新对齐条件,不能继续沿用“既有 contract”作为证明。
-
-## 9. 验证矩阵
-
-### 9.1 单元和 contract
-
-- policy parser:1 可接受;0、负数、小数、未知正整数、缺失值和错误 component 均拒绝。
-- workflow create:未升级项目只写 1;升级项目新 `/man` 写 2;已有 workflow 的 policy provenance 不变。
-- Plan Coach:不同目标、无复杂度承担者、多个 recommendation、无 stop condition 均返回 `NEEDS_CLARIFICATION`;简单任务单方向通过。
-- Continuity `/man`、`/manteam` 和 Solo mode entry 的条件式 decision-readiness gate:清晰且可靠的请求直接继续,决策性歧义在 requirements finalize 或代码修改前停下并等待用户回答;不强制无意义提问。
-- stop/re-align:触发时返回 `NEEDS_REALIGNMENT + MANCODE_REFRAME_REQUIRED`,且 authority 的前后 digest 完全相同。
-- Scout/Domain Matrix:可选字段不进入 metadata;高风险 plan 可包含章节;普通任务不被强制增加文件。
-- digest:内容、marker、路径、换行、截断、用户托管区域变化分别得到预期结果;manifest echo 与磁盘不一致必为 stale。
-- manifest:V1/V2 都拒绝 content digest 字段;expected digest 只能由 renderer 和 managed target 重建。
-- compatibility:reader、writer、capability、adapter digest、policy parser 按规定顺序短路,且失败前没有 journal 或业务写。
-- reframe:每个拒绝条件都在第一步失败;每个 recovery action 幂等;中断后不出现部分 Step 2。
-
-### 9.2 集成和恢复
-
-- 五个平台生成、status、stale 编辑、dry-run、确认升级、升级后重新读取。
-- adapter upgrade 在每个 target 写入前、写入后和中断点恢复;共享 `AGENTS` target 不能被两个平台重复覆盖。
-- local transport 下的 Policy 2 create/plan/review/verification 与旧 workflow 并存。
-- 两个 clone 的 git-ref 兼容门、旧 writer 拒绝、receipt recovery,以及 deferred publish 和原子 mutation 后“提交 tracked 投影 → same-revision code-head rebind → 第二 clone pull/resume”的完整链路;所有 git-ref reframe 请求必须确认硬拒绝。
-- active child、open handoff、active solo assignment 的并发 race:先取得锁的一方决定,另一方得到 expected-revision 或明确 reframe error。
-
-### 9.3 真实宿主和跨平台
-
-发布候选必须在 Claude Code、Codex、Cursor、GitHub Copilot、ZCode、Kimi Code、Qoder 以及 Windows CMD/PowerShell/Git Bash 路径上验证:入口传播、session identity、adapter 文件、status/stale 诊断和升级命令。缺少真实宿主证据的平台只能标记 `not_applicable` 并阻止对应能力发布,不能用另一个宿主代替。
-
-## 10. 单版本 release gate
-
-### 10.1 实施工作包
-
-| 工作包 | 主要模块 | 必须新增的证据 | 完成定义 |
-| --- | --- | --- | --- |
-| A. advisory | `src/templates/agents/scout.ts`、Plan Coach template、`src/templates/skills/man.ts`、共享 adapter renderer | template snapshot、八类路由样例、简单任务单方向样例 | 所有 renderer 文案一致;advisory 不直接修改 metadata/schema |
-| B. stop/re-align diagnostic | Scout/Plan Coach template、context 输出 | 触发器 contract、authority before/after digest、重复调用测试 | 只返回 `NEEDS_REALIGNMENT + MANCODE_REFRAME_REQUIRED`;authority、step、requirements、plan、claim 不变 |
-| C. adapter digest/upgrade | `src/installers/v3-adapter.ts`、status/context callsite、operation recovery、CLI registration | 五平台 target fixture、stale 分类、dry-run、每个 crash point | compatibility 使用实际磁盘 digest;显式 upgrade 可 repair |
-| D. policy/version gate | workflow metadata parser、manifest parser、compatibility/resolver、workflow create | V1/V2 白名单、0.3.x + V2 reader/writer fixture、capability/minWriter matrix | 未知 policy/manifest 在写前拒绝;没有 fallback |
-| E. project Policy 2 upgrade | 新 project upgrade command/operation、manifest V2 writer、workflow create | V1→V2 dry-run/commit/repair、旧 workflow provenance、新 workflow default | 只有 V2 项目新建 `/man` 写 2;历史 metadata 无 diff |
-| F. atomic local reframe | 新 `reframe` context module、operation definition/recovery、archive store、claim/ledger writers | eligibility、并发、每步 crash、archive digest、task-head fence | 单 journal 全前/全后;0.4.0 local transport 发布,git-ref 一律硬拒绝 |
-
-每个工作包单独合并和评审。C、D 可以并行开发,E 依赖 C 和 D;F 与 E 可以分别完成,但二者都属于同一个 0.4.0 release gate,不能提前开启默认路径。
-
-### 10.2 0.4.0 gate
-
-以下保留 0.4.0 发布前记录。`[x]` 仅表示当时的实现和自动化证据;它不是
-0.4.2 的发布状态,也不能证明后来发布的 npm 提交已经通过相同 gate。
-
-- [x] 模板和文档 contract 通过;advisory 不直接执行 schema migration、policy 写入或自动 step 变更。
-- [x] 旧 layout-version-3 fixture、legacy fixture、已有 adapter 和历史 workflow 通过原有测试。
-- [x] 触发 stop/re-align 时只返回 `NEEDS_REALIGNMENT + MANCODE_REFRAME_REQUIRED`,authority 文件内容和 claims 不变。
-- [x] Scout/Plan Coach 新字段和规则覆盖正常、缺失证据、冲突 owner、单方向简单任务。
-- [x] Continuity mode entry 恢复条件式需求澄清:清晰需求不机械追问,决策性歧义必须在 finalize/实施前向用户提问并等待回答;五平台生成契约覆盖。
-- [x] adapter digest algorithm、status 分类、stale error、explicit upgrade command 和 recovery contract 完成。
-- [x] policy parser 白名单、writer capability、`minWriterVersion`/reader gate 和 0.3.x + V2 manifest 拒绝 contract 完成;本轮已增加真实发布版 0.3.18 CLI 的黑盒写入拒绝与 authority 全树字节不变证据,后续候选仍需重跑。
-- [x] project upgrade dry-run、确认、commit、repair、abort 和 provenance 完成;现有 workflow 未被批量重写,新 `/man` Policy 2 默认值有明确创建证据。
-- [x] local transport 的完整原子 reframe、recovery、archive retention,以及与 child create、handoff create/start、solo handoff start 的真实并发竞争通过;没有复用 scope-change,也没有部分 authority 或 eligibility 绕过路径。
-- [x] 已升级/未升级项目、旧/新 workflow、local/git-ref transport 的自动化兼容矩阵通过;git-ref reframe 稳定返回 `MANCODE_REFRAME_GIT_REF_UNSUPPORTED`。
-- [x] 5 个 adapter renderer、Windows path、line ending、用户托管区和每个 target 写前/写后中断恢复在 `4dc2e7e` 通过;后续候选仍需重跑 dist/Windows/recovery gate。
-- [x] 平台证据区分 `host_session_verified` 与 `explicit_session_verified`;显式路径验证两个 active、不同且 client 匹配的 session,只满足发布证据,不提升运行时宿主信任。
-- [x] release-check 从远端候选创建干净 checkout,自动运行完整门禁、双 clone、legacy、audit、pack、tarball CLI/module smoke,并输出提交绑定的 SHA-256 证据;脚本不包含 npm publish 或 dist-tag 操作。
-- [ ] Claude Code、Codex、Cursor、GitHub Copilot、ZCode、Kimi Code、Qoder 的最终候选真实宿主验收,以及 [`docs/release-acceptance.md`](./release-acceptance.md) 要求的跨 clone、legacy、Beta gate 和干净 checkout tarball 验收。
-- [x] 按开发集成要求将候选 `4dc2e7e` 推送到远程 `develop`,且 Quality 与 Windows gate 均通过;这不等同于 release gate 通过。
-- [ ] 完成剩余发布验收后才允许进入 npm 发布检查;任何条件失败都不得发布 npm。
-
-0.4.0 与 0.4.1 后来已经发布,但仓库内的未完成列表和外部 gate 证据没有在发布前闭合,
-且 0.4.1 的 npm `gitHead` 不是旧 release-check 所要求的 `origin/develop` 提交。该偏差
-不通过事后勾选消除;0.4.2 按 [`docs/release-acceptance.md`](./release-acceptance.md) 的
-main-candidate 契约重新建立可审计证据。
-
-## 11. 发布回滚与停止策略
-
-| 发现的问题 | 立即动作 | 禁止动作 | 恢复方式 |
-| --- | --- | --- | --- |
-| advisory 模板误导但无 authority 写 | 停止发布、修模板、重跑 snapshot | 不要求用户迁移 workflow | 发布前替换 adapter/模板;已有 authority 不变 |
-| adapter stale 或 renderer mismatch | 阻塞 mutation,提示显式 upgrade | 自动 `--force`、手工改 digest | upgrade dry-run → 确认 → journal repair |
-| Policy 2 parser/门禁错误 | 关闭 Policy 2 创建入口 | 把 2 降为 1 或修改旧 workflow | 修复 CLI 后重新读取;project marker 保持可审计 |
-| project upgrade 中断 | 标记 pending/repair,禁止普通写 | 直接删除半成品或手改 minWriter | `operation repair` 恢复 before/target 状态 |
-| reframe 中断或前置条件冲突 | 保留 operation journal,维持 blocked/repair_required | 手动写 Step 2、释放部分 claim | 修复原 operation;无法证明时人工处理后再重试 |
-| git-ref reframe 请求 | 稳定返回 `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` | 只在本 clone 先执行、以后同步 | 本计划不提供恢复路径;后续若要支持,必须另立协议设计与发布评审 |
-
-版本回滚只回滚代码入口和默认创建策略,不回写历史 policy、requirements、plan 或 task step。任何需要修改现有权威内容的“回滚”都必须成为另一个明确、journaled 的 migration,并经过独立评审。
-
-## 12. 实施顺序与停止/重新对齐条件
-
-A–F 是已经发布的 0.4.0 能力基线。0.4.2 的修复和发布按以下顺序重新建立证据:
-
-1. [x] 记录 0.4.1 的 git-ref publication 与发布候选偏差,不把历史 CI 当作当前证据。
-2. [x] 为原子 mutation 的 tracked 投影提交增加 same-revision、same-aggregate、owner-only、fast-forward code-head rebind,并加入第二 clone resume 回归测试。
-3. [x] 将 release-check 改为要求 candidate 同时等于本地 HEAD 与 `origin/main`,并从 main 创建干净 checkout。
-4. [ ] 在 `develop` 完成实现、测试和文档评审后合并到 `main`,形成唯一 0.4.2 candidate。
-5. [ ] 在该 main SHA 上通过 [`docs/release-acceptance.md`](./release-acceptance.md) 的 Quality/Windows、release-check、真实宿主、跨宿主恢复、Beta 和 tarball 检查。
-6. [ ] 从同一 main checkout 发布 0.4.2,验证 npm version/integrity/`gitHead`,再为同一 SHA 创建 `v0.4.2` tag 与 GitHub Release。
-
-任何阶段出现下列情况,都回到“证据和契约评审”,而不是继续编码:
-
-- 发现两个入口给同一任务不同的 owner、scope 或状态语义;
-- authority writer 与 derived copy 的责任无法唯一确定;
-- status、contract、policy 或完成门禁的意义需要改变;
-- digest 只反映版本常量、无法重建 expected bytes,或跨平台结果不稳定;
-- 旧 CLI 能读到新 policy 却没有可靠的 reader/writer/capability 拒绝;
-- operation 无法在任意中断点证明“全前或全后”;
-- 需求变化需要同时改 requirements、plan、claims、handoff 或 step,但当前 operation 没有覆盖它们。
-
-重新对齐完成的最低证据是:新的目标、候选 owner、source of truth、兼容影响、停止条件和唯一 recommendation 已被记录,并由相应 authority writer 重新确认。仅仅修改 Markdown 或手动调整 step 不算重新对齐。
-
-## 13. 0.4.0 已定稿的四个实现选择
-
-以下选择已由 compatibility contract 固定;发布前不得在缺少重新评审和对应证据时改变:
-
-1. **Public create 基线:** 用未升级项目的端到端 create contract 证明只写 Policy 1;不得把 CLI 选项、模板默认值或 builder 默认值中的任一项当成唯一证据。
-2. **Digest 的持久化位置:** 固定采用“renderer 重建 expected digest + local 非权威 cache”,不在 V1 或 V2 持久化 content digest。性能不足必须另立设计,不能阻塞后临时扩 schema。
-3. **升级命令的公开名称:** 以现有 `adapter status/upgrade` 命令注册、JSON 输出和 shell 退出码测试确定名称;文档和实现必须只保留一个正式入口。
-4. **Capability 的编码:** 默认由 CLI 内置 capability set 加 project `minWriterVersion` 双门控制,不新增可被旧 CLI 忽略的 manifest capability 字段;local reframe 与 git-ref hard reject 必须使用不同 capability 结果。
-
-这四项是已发布的兼容基线;0.4.2 不改变其语义。任何后续变更仍须重新通过对应
-contract 与 release gate。git-ref reframe 继续不在支持范围内。
-
-## 14. 远程分支与 npm 发布顺序
-
-0.4.2 及后续补丁统一使用“最终 main 提交发布”模型:
-
-1. 所有实现、修复和文档先在 `develop` 完成窄测试、完整自动化和评审。
-2. 将最终变更合并并推送到 `main`。该合并提交是唯一 release candidate;develop SHA、PR head SHA 和 main 的父提交都不能代替它。
-3. 等待该 main SHA 的 GitHub Quality 与 Windows required checks 成功。
-4. 在本地检出同一提交,运行 `npm run release:check -- --candidate <完整 SHA>`。脚本要求本地 HEAD 和 `origin/main` 都等于 candidate,从 main 创建干净 checkout,并确认检查期间 main 未变化。
-5. 使用 release-check 保留的 tarball 完成五平台真实宿主、跨宿主恢复和最终 Beta gate;所有证据必须绑定同一个 main SHA 与 package version。
-6. 全部门禁成功后才允许执行一次正式 npm 发布。随后核对 registry version、integrity 与 `gitHead`,确保仍指向 candidate。
-7. npm 核对成功后,为同一提交创建并推送版本 tag,发布 GitHub Release,并记录候选 SHA 与 tarball SHA-256。
-
-任何代码、依赖、构建配置、版本号或发布文档变化都会产生新的 main candidate,并使旧证据失效。检查期间禁止并发更新 main;但“合并到 main”本身是建立候选的必要步骤,不再把 main 永久冻结在旧版本。
-
-### 14.1 0.4.1 偏差与 0.4.2 处置
-
-- 0.4.1 的 npm `gitHead` 是 `8cc8b24` main 合并提交,旧 release-check 却要求 candidate 等于 `origin/develop` 的 `aaa8d6c`;因此已发布提交无法通过当时脚本的身份断言。
-- 0.4.1 的最终 Quality/Windows checks 已成功,但仓库验收文档仍把这些和其他 gate 列为未完成,且没有 0.4.1 tag/GitHub Release。CI 成功不能代替候选绑定与证据收口。
-- 0.4.2 不追溯修改 0.4.1 证据。它改用 main-candidate 模型、补齐 code-head rebind 回归,并要求 npm、tag 和 GitHub Release 全部绑定最终 main SHA。
diff --git a/docs/platform-adapters.md b/docs/platform-adapters.md
index 9632a7b..be9a740 100644
--- a/docs/platform-adapters.md
+++ b/docs/platform-adapters.md
@@ -25,6 +25,20 @@ mancode status
manifest 的 `managedAdapters` key 是项目登记的 required 平台集合。greenfield init 只登记所选平台;后续新增或修复平台必须通过带 active session 和显式确认的 adapter upgrade journal。`AGENTS.md` 和 Copilot instruction 文件中托管区外的用户内容必须原样保留。
+## 内容完整性与升级
+
+`adapter status` 每次都从当前 renderer 重建 expected managed bytes,并与磁盘上的
+actual managed bytes 比较。整文件 target 比较完整内容;嵌入式 target 只比较 mancode
+托管区。磁盘内容不先规范化换行,因此 CRLF 漂移、截断和手工编辑都能被识别。
+
+每个 required target 的状态为 `ready`、`missing`、`stale` 或 `unreadable`。只有全部
+required target 都是 `ready`,依赖 adapter 的 mutation 才能继续。manifest 只记录
+renderer/schema version 和 required inventory;content digest 是可重建结果,不能成为
+新的 manifest authority。
+
+adapter upgrade 先在 staging 中生成预览,用户确认后再通过 journaled operation 发布。
+中断必须由原 operation repair;升级不能修改 workflow policy、requirements、plan 或 step。
+
## Bootstrap 合约
每个平台都必须:
diff --git a/docs/release-acceptance.md b/docs/release-acceptance.md
deleted file mode 100644
index be3f978..0000000
--- a/docs/release-acceptance.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# 0.4.2 Continuity 发布验收
-
-自动化 contract 必须覆盖 Continuity runtime/schema、条件式需求澄清、Policy 2、project upgrade、local reframe、operation recovery、团队协调、git-ref publication/rebind、五个平台生成结果和 Windows smoke path。条件式需求澄清必须证明清晰请求不被机械提问阻塞,决策性歧义会在 requirements finalize 或实施前停下、提问并等待用户回答。以下证据完成前,不得发布 mancode 0.4.2 或执行 `npm publish`。
-
-## 唯一候选身份
-
-- `develop` 只用于开发集成;最终 release candidate 是已经合并并推送到 `origin/main` 的单个提交。
-- 本地 `HEAD`、`origin/main`、Quality/Windows checks、release-check、真实宿主证据、Beta gate、待发布 package version 和 npm `gitHead` 必须指向同一完整 SHA。
-- 候选建立后,release-check 会记录检查前后的 `origin/main`。检查期间发生任何 main 更新都会使候选失效;后续修复必须形成新的 main 提交并重新执行受影响的全部门禁。
-
-## 发布条件
-
-- 在最终 main 候选运行 `npm run release:check -- --candidate <完整提交 SHA>`;该命令必须从 `origin/main` 创建干净 checkout,运行 `npm ci`、`npm run prepublishOnly`、跨 clone、legacy、audit、pack 和安装 smoke,并输出绑定提交与 tarball SHA-256 的本地 JSON 证据。
-- release-check 先运行 `npm pack --dry-run`,再执行实际 `npm pack`,保留生成的 tarball 并完成 CLI/module smoke;npm beta/rc 不能替代该字节级验证。
-- GitHub Quality gate 与 Windows required check 必须在同一个 main 候选成功;Windows 覆盖 CMD、PowerShell 和 Git Bash。
-- Claude Code、Codex、Cursor、GitHub Copilot、ZCode、Kimi Code 和 Qoder 都完成真实双窗口 session 验证。每个平台可证明受信宿主 session,或证明两个真实显式 session 隔离;显式证据只满足发布验收,不授权运行时信任宿主 key。
-- 每个平台证明子命令传播;支持子 agent 的平台还需证明继承,或记录合法的 `not_applicable` 原因。缺失、伪造、错误 client、关闭或碰撞的显式 session 证据必须拒绝。
-- 完成跨真实宿主 resume、claim、handoff 和恢复路径。
-- release-check 中两个真实独立 clone 完成 git-ref pull、并发 CAS、handoff、receipt recovery、代码基线交接,以及原子 mutation 投影提交后的同 revision code-head rebind 和第二 clone resume。
-- release-check 中的真实 0.3.18 legacy fixture 完成 stage、activation、每个中断点恢复和严格条件下的 rollback;人工 smoke 不能替代 crash matrix。
-- 最终执行 `mancode context beta --release-candidate --json` 返回 `ready: true` 和空 blockers。
-- 上述条件全部成功后,才允许从该 main checkout 发布 release-check 验证过的候选版本;发布后必须核对 npm version、integrity 与 `gitHead`。
-- npm 验证成功后,在同一个 candidate SHA 创建 `v0.4.2` tag 和 GitHub Release,并记录 tarball SHA-256。tag 或 Release 不得指向另一个提交,也不能替代发布前门禁。
-
-## 发布顺序
-
-1. 在 `develop` 完成实现、文档和本地验证,通过评审后合并到 `main`。
-2. 推送最终 main 合并提交,记录完整 candidate SHA,并等待该提交的 Quality 与 Windows checks 成功。
-3. 在本地检出同一 main 提交,从 `origin/main` 运行 release-check。
-4. 使用 release-check 保留的候选 tarball 完成真实宿主 spike、跨宿主恢复和最终 Beta gate。
-5. 确认所有证据仍绑定同一个 main SHA 后执行唯一一次正式 npm 发布,并核对 registry metadata。
-6. 为同一 SHA 创建并推送 `v0.4.2` tag,发布 GitHub Release 并附上候选与 tarball digest。
-
-任何测试失败、main 提交变化、package version 变化或发布文档变化都会使已有验收失效。修复后必须形成新候选并重新验证;不得先发布 npm 再补证据。
-
-## 证据规则
-
-所有证据必须绑定同一个 `origin/main` commit、mancode version、操作系统和宿主版本。`develop` 提交、历史祖先提交、未推送提交或替代宿主结果只能用于调试,不能用于最终 Beta gate。
-
-session evidence 不保存原始 key、token、绝对业务路径或任务正文。屏幕截图和日志应脱敏,并保存在发布流程约定的本地证据目录,而不是长期开发文档中。
-
-## 当前未完成项
-
-- 将 0.4.2 实现、测试和文档合并为最终 `origin/main` candidate。
-- 在最终 main 候选上完成 Quality gate 与 Windows CMD、PowerShell、Git Bash required gate。
-- 在最终 main 候选上完成 release-check,包括自动双 clone git-ref、code-head rebind、legacy、tarball SHA-256、安装和 CLI/module smoke。
-- 全部登记平台在最终候选上的完整 session spike,以及跨真实宿主协作与恢复验收。
-- ZCode 项目级 skill 发现和 workspace command 路径确认。
-- Kimi Code 项目级 skill 发现(桌面端/CLI)与 Qoder `.qoder/commands/` 命令发现(IDE/CLI)的真实宿主确认。
-- 汇总全部证据后的最终 Beta gate。
-- npm registry version/integrity/`gitHead` 核对,以及绑定同一提交的 `v0.4.2` tag 和 GitHub Release。
-
-完成一项时更新本文件的未完成列表;不要创建新的平行验收计划。
diff --git a/package-lock.json b/package-lock.json
index 4fe070d..d812d98 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mancode",
- "version": "0.5.5",
+ "version": "0.5.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mancode",
- "version": "0.5.5",
+ "version": "0.5.6",
"license": "AGPL-3.0-only",
"dependencies": {
"commander": "^12.1.0",
@@ -24,7 +24,7 @@
"vitest": "^3.2.6"
},
"engines": {
- "node": ">=20"
+ "node": ">=22"
}
},
"node_modules/@ampproject/remapping": {
@@ -1418,16 +1418,16 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "5.0.7",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
- "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
- "node": "18 || 20 || >=22"
+ "node": "20 || >=22"
}
},
"node_modules/bundle-require": {
@@ -1763,9 +1763,9 @@
"license": "MIT"
},
"node_modules/glob/node_modules/brace-expansion": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz",
- "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
+ "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2059,9 +2059,9 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.15",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
- "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==",
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
"dev": true,
"funding": [
{
@@ -2181,9 +2181,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.15",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
- "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "version": "8.5.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
+ "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
"dev": true,
"funding": [
{
@@ -2201,7 +2201,7 @@
],
"license": "MIT",
"dependencies": {
- "nanoid": "^3.3.12",
+ "nanoid": "^3.3.17",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
diff --git a/package.json b/package.json
index 3ccd77c..1da0505 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mancode",
- "version": "0.5.5",
+ "version": "0.5.6",
"description": "AI coding agent workflow harness with mancode Continuity for cross-conversation tasks, decisions, verification, and team coordination.",
"type": "module",
"license": "AGPL-3.0-only",
@@ -37,7 +37,7 @@
"zcode"
],
"engines": {
- "node": ">=20"
+ "node": ">=22"
},
"bin": {
"mancode": "dist/cli.js"
@@ -67,7 +67,7 @@
"lint": "biome check src tests",
"typecheck": "tsc --noEmit",
"format": "biome format --write src tests",
- "prepublishOnly": "npm run lint && npm run typecheck && npm run build && npm run test:dist && npm test"
+ "prepublishOnly": "npm audit --audit-level=high && npm run lint && npm run typecheck && npm run build && npm run test:dist && npm run test:coverage"
},
"dependencies": {
"commander": "^12.1.0",
diff --git a/scripts/context-economy-baseline.json b/scripts/context-economy-baseline.json
deleted file mode 100644
index b7e2414..0000000
--- a/scripts/context-economy-baseline.json
+++ /dev/null
@@ -1,125 +0,0 @@
-{
- "schemaVersion": 1,
- "tokenizerId": "cl100k_base@tiktoken-0.7.0",
- "generatedAt": "2026-07-25T19:53:35.715Z",
- "totals": {
- "commandTokens": 25192,
- "artifactTokens": 415
- },
- "commands": [
- {
- "name": "init",
- "command": "mancode init --yes --empty --platform claude-code --lang en",
- "tokens": 63,
- "chars": 148
- },
- {
- "name": "status_brief",
- "command": "mancode status --brief --json",
- "tokens": 91,
- "chars": 270
- },
- {
- "name": "team_identity_create",
- "command": "mancode team identity create --name Economy Fixture --json",
- "tokens": 77,
- "chars": 197
- },
- {
- "name": "context_session_new",
- "command": "mancode context session new --client mancode-cli --json",
- "tokens": 194,
- "chars": 531
- },
- {
- "name": "workflow_create_man",
- "command": "mancode workflow create man Measure mancode CLI token economy. --session --client mancode-cli --json",
- "tokens": 1128,
- "chars": 3503
- },
- {
- "name": "workflow_requirements_finalize",
- "command": "mancode workflow requirements local: finalize --expected-revision 1 --file /var/folders/3s/lycwtrpj607_k0w_fwz6_2pm0000gp/T/mancode-economy-S1zghL/requirements.json --session --client mancode-cli --json",
- "tokens": 1823,
- "chars": 5776
- },
- {
- "name": "workflow_plan_revise",
- "command": "mancode workflow plan local: revise --expected-revision 2 --plan-decision governed_execution --file /var/folders/3s/lycwtrpj607_k0w_fwz6_2pm0000gp/T/mancode-economy-S1zghL/plan.md --session --client mancode-cli --json",
- "tokens": 1264,
- "chars": 3757
- },
- {
- "name": "context_show_orient",
- "command": "mancode context show --task local: --purpose orient --level task --session --client mancode-cli --json",
- "tokens": 1912,
- "chars": 6539
- },
- {
- "name": "context_show_plan",
- "command": "mancode context show --task local: --purpose plan --level task --session --client mancode-cli --json",
- "tokens": 2863,
- "chars": 9929
- },
- {
- "name": "context_show_implement",
- "command": "mancode context show --task local: --purpose implement --level task --session --client mancode-cli --json",
- "tokens": 2527,
- "chars": 8721
- },
- {
- "name": "context_show_review",
- "command": "mancode context show --task local: --purpose review --level task --session --client mancode-cli --json",
- "tokens": 2852,
- "chars": 9717
- },
- {
- "name": "context_show_verify",
- "command": "mancode context show --task local: --purpose verify --level task --session --client mancode-cli --json",
- "tokens": 2852,
- "chars": 9717
- },
- {
- "name": "context_show_handoff",
- "command": "mancode context show --task local: --purpose handoff --level task --session --client mancode-cli --json",
- "tokens": 3039,
- "chars": 10295
- },
- {
- "name": "context_show_review_full",
- "command": "mancode context show --task local: --purpose review --level full --session --client mancode-cli --json",
- "tokens": 1428,
- "chars": 4921
- },
- {
- "name": "workflow_review_apply",
- "command": "mancode workflow review local: apply --expected-revision 3 --file /var/folders/3s/lycwtrpj607_k0w_fwz6_2pm0000gp/T/mancode-economy-S1zghL/review-ledger.json --session --client mancode-cli --json",
- "tokens": 1418,
- "chars": 4286
- },
- {
- "name": "workflow_verify_apply",
- "command": "mancode workflow verify local: apply --expected-revision 4 --file /var/folders/3s/lycwtrpj607_k0w_fwz6_2pm0000gp/T/mancode-economy-S1zghL/verification-ledger.json --session --client mancode-cli --json",
- "tokens": 1506,
- "chars": 4539
- },
- {
- "name": "context_close",
- "command": "mancode context close --session --json",
- "tokens": 155,
- "chars": 422
- }
- ],
- "artifacts": [
- {
- "name": "requirements.json",
- "tokens": 394,
- "chars": 1634
- },
- {
- "name": "plan.md",
- "tokens": 21,
- "chars": 91
- }
- ]
-}
diff --git a/scripts/context-economy-report.mjs b/scripts/context-economy-report.mjs
deleted file mode 100644
index 0a41d56..0000000
--- a/scripts/context-economy-report.mjs
+++ /dev/null
@@ -1,639 +0,0 @@
-/**
- * Token-economy report for the mancode v3 CLI surface.
- *
- * Drives a full /man workflow against dist/cli.js in a temporary project,
- * counts cl100k_base tokens (CONTEXT_PACK_TOKENIZER_ID) for every command
- * receipt and for the agent-facing artifacts, and compares the result with
- * the committed baseline.
- *
- * Usage:
- * npm run build
- * node scripts/context-economy-report.mjs [--output ] [--check]
- *
- * --check compares against scripts/context-economy-baseline.json and exits
- * non-zero when any measurement drifts more than ±2%. The script is a manual
- * / pre-release gate; it is intentionally not wired into CI.
- */
-import { spawnSync } from 'node:child_process';
-import { randomBytes, createHash } from 'node:crypto';
-import {
- access,
- mkdtemp,
- readdir,
- readFile,
- rm,
- writeFile,
-} from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import path from 'node:path';
-import process from 'node:process';
-import { fileURLToPath } from 'node:url';
-import { getEncoding } from 'js-tiktoken';
-
-const sourceRoot = path.resolve(
- path.dirname(fileURLToPath(import.meta.url)),
- '..',
-);
-const cliPath = path.join(sourceRoot, 'dist', 'cli.js');
-const baselinePath = path.join(
- sourceRoot,
- 'scripts',
- 'context-economy-baseline.json',
-);
-const TOKENIZER_ID = 'cl100k_base@tiktoken-0.7.0';
-const TOLERANCE = 0.02;
-const ULID_ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
-const REQUIREMENT_DIMENSIONS = [
- 'platform',
- 'core_scope',
- 'technical_stack',
- 'data_and_persistence',
- 'performance',
- 'compatibility',
- 'security',
-];
-
-const options = parseOptions(process.argv.slice(2));
-if (options.help) {
- console.log(
- 'Usage: node scripts/context-economy-report.mjs [--output ] [--check]',
- );
- process.exit(0);
-}
-
-await access(cliPath).catch(() => {
- throw new Error('dist/cli.js is missing; run `npm run build` first');
-});
-
-const encoder = getEncoding('cl100k_base');
-const projectRoot = await mkdtemp(path.join(tmpdir(), 'mancode-economy-'));
-const commands = [];
-const artifacts = [];
-
-try {
- const init = measure('init', [
- 'init',
- '--yes',
- '--empty',
- '--platform',
- 'claude-code',
- '--lang',
- 'en',
- ]);
- assert(init.exitCode === 0, `init failed:\n${init.stdout}`);
-
- measureOk('status_brief', ['status', '--brief', '--json']);
- measureOk('team_identity_create', [
- 'team',
- 'identity',
- 'create',
- '--name',
- 'Economy Fixture',
- '--json',
- ]);
-
- const sessionReceipt = measureOk('context_session_new', [
- 'context',
- 'session',
- 'new',
- '--client',
- 'mancode-cli',
- '--json',
- ]);
- const sessionId = JSON.parse(sessionReceipt.stdout).session.sessionId;
- const sessionArgs = ['--session', sessionId, '--client', 'mancode-cli'];
-
- const createReceipt = measureOk('workflow_create_man', [
- 'workflow',
- 'create',
- 'man',
- 'Measure mancode CLI token economy.',
- ...sessionArgs,
- '--json',
- ]);
- const created = JSON.parse(createReceipt.stdout);
- const task = `${created.taskRef.namespace}:${created.taskRef.taskId}`;
-
- const requirementsPath = path.join(projectRoot, 'requirements.json');
- await writeFile(
- requirementsPath,
- `${JSON.stringify(semanticRequirementsFixture(), null, 2)}\n`,
- );
- await measureArtifact('requirements.json', requirementsPath);
-
- const finalizeReceipt = measureOk('workflow_requirements_finalize', [
- 'workflow',
- 'requirements',
- task,
- 'finalize',
- '--expected-revision',
- '1',
- '--file',
- requirementsPath,
- ...sessionArgs,
- '--json',
- ]);
- const finalized = JSON.parse(finalizeReceipt.stdout);
- const requirements = finalized.requirements;
-
- const planPath = path.join(projectRoot, 'plan.md');
- await writeFile(
- planPath,
- '# Token economy plan\n\n1. Measure every v3 receipt.\n2. Compare with the committed baseline.\n',
- );
- await measureArtifact('plan.md', planPath);
-
- const planReceipt = measureOk('workflow_plan_revise', [
- 'workflow',
- 'plan',
- task,
- 'revise',
- '--expected-revision',
- String(finalized.metadata.revision),
- '--plan-decision',
- 'governed_execution',
- '--file',
- planPath,
- ...sessionArgs,
- '--json',
- ]);
- const planned = JSON.parse(planReceipt.stdout);
- const planVersion = planned.metadata.governance.planVersion;
-
- for (const purpose of [
- 'orient',
- 'plan',
- 'implement',
- 'review',
- 'verify',
- 'handoff',
- ]) {
- measureOk(`context_show_${purpose}`, [
- 'context',
- 'show',
- '--task',
- task,
- '--purpose',
- purpose,
- '--level',
- 'task',
- ...sessionArgs,
- '--json',
- ]);
- }
-
- const fullPack = JSON.parse(
- measureOk('context_show_review_full', [
- 'context',
- 'show',
- '--task',
- task,
- '--purpose',
- 'review',
- '--level',
- 'full',
- ...sessionArgs,
- '--json',
- ]).stdout,
- );
- assert(fullPack.pack !== undefined, 'full context pack is missing');
- // The task starts with empty on-disk ledgers; the apply inputs derive from
- // them the same way the workflow fixtures do.
- const previousReview = JSON.parse(
- await readFile(await findTaskFile('review-ledger.json'), 'utf8'),
- );
- const previousVerification = JSON.parse(
- await readFile(await findTaskFile('verification-ledger.json'), 'utf8'),
- );
-
- const reviewPath = path.join(projectRoot, 'review-ledger.json');
- await writeFile(
- reviewPath,
- `${JSON.stringify(
- passedReview(previousReview, requirements.contentDigest, planVersion),
- null,
- 2,
- )}\n`,
- );
- const reviewReceipt = measureOk('workflow_review_apply', [
- 'workflow',
- 'review',
- task,
- 'apply',
- '--expected-revision',
- String(planned.metadata.revision),
- '--file',
- reviewPath,
- ...sessionArgs,
- '--json',
- ]);
- const reviewed = JSON.parse(reviewReceipt.stdout);
-
- const verificationPath = path.join(projectRoot, 'verification-ledger.json');
- await writeFile(
- verificationPath,
- `${JSON.stringify(
- passedVerification(
- previousVerification,
- requirements,
- planVersion,
- reviewed.review.remediationRound,
- ),
- null,
- 2,
- )}\n`,
- );
- measureOk('workflow_verify_apply', [
- 'workflow',
- 'verify',
- task,
- 'apply',
- '--expected-revision',
- String(reviewed.metadata.revision),
- '--file',
- verificationPath,
- ...sessionArgs,
- '--json',
- ]);
-
- measureOk('context_close', [
- 'context',
- 'close',
- '--session',
- sessionId,
- '--json',
- ]);
-
- const report = buildReport();
- printTable(report);
- if (options.output) {
- const outputPath = path.resolve(sourceRoot, options.output);
- await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`);
- console.log(`\nReport written to ${outputPath}`);
- }
- if (options.check) {
- const baseline = JSON.parse(await readFile(baselinePath, 'utf8'));
- const failures = compareWithBaseline(report, baseline);
- if (failures.length > 0) {
- console.error('\nBaseline check failed:');
- for (const failure of failures) console.error(` - ${failure}`);
- process.exitCode = 1;
- } else {
- console.log(
- `\nBaseline check passed (tolerance ±${TOLERANCE * 100}%): ${baselinePath}`,
- );
- }
- }
-} finally {
- await rm(projectRoot, { recursive: true, force: true });
-}
-
-function measure(name, args) {
- const result = spawnSync(process.execPath, [cliPath, ...args], {
- cwd: projectRoot,
- encoding: 'utf8',
- env: { ...process.env, MANCODE_SESSION_ID: undefined },
- });
- if (result.error) throw result.error;
- const stdout = result.stdout ?? '';
- const normalized = normalize(stdout);
- commands.push({
- name,
- command: `mancode ${args.join(' ')}`,
- exitCode: result.status ?? -1,
- tokens: countTokens(normalized),
- chars: normalized.length,
- });
- return { exitCode: result.status ?? -1, stdout, stderr: result.stderr ?? '' };
-}
-
-function measureOk(name, args) {
- const result = measure(name, args);
- assert(
- result.exitCode === 0,
- `${name} failed (${result.exitCode}):\n${result.stdout}\n${result.stderr}`,
- );
- return result;
-}
-
-async function measureArtifact(name, filePath) {
- const content = normalize(await readFile(filePath, 'utf8'));
- artifacts.push({
- name,
- tokens: countTokens(content),
- chars: content.length,
- });
-}
-
-/** Locates one authoritative task file under .mancode without assuming layout. */
-async function findTaskFile(fileName) {
- const matches = [];
- const queue = [path.join(projectRoot, '.mancode')];
- while (queue.length > 0) {
- const directory = queue.pop();
- const entries = await readdir(directory, { withFileTypes: true }).catch(
- () => [],
- );
- for (const entry of entries) {
- const entryPath = path.join(directory, entry.name);
- if (entry.isDirectory()) queue.push(entryPath);
- else if (entry.name === fileName) matches.push(entryPath);
- }
- }
- assert(
- matches.length === 1,
- `expected exactly one ${fileName} under .mancode, found ${matches.length}`,
- );
- return matches[0];
-}
-
-/**
- * Run-to-run jitter sources are replaced with stable placeholders before
- * counting tokens: the temporary project root, ULIDs, sha256 digests, and
- * ISO timestamps (fixed-length, but BPE token counts vary per value).
- */
-function normalize(text) {
- return text
- .split(projectRoot)
- .join('')
- .split(path.basename(projectRoot))
- .join('')
- .replace(/sha256:[0-9a-f]{64}/g, `sha256:${'0'.repeat(64)}`)
- .replace(/\b[0-9A-HJKMNP-TV-Z]{26}\b/g, '01ARZ3NDEKTSV4RRFFQ69G5FAV')
- .replace(
- /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z/g,
- '2026-01-01T00:00:00.000Z',
- );
-}
-
-function countTokens(text) {
- return encoder.encode(text).length;
-}
-
-function buildReport() {
- const commandTotal = commands.reduce((sum, entry) => sum + entry.tokens, 0);
- return {
- schemaVersion: 1,
- tokenizerId: TOKENIZER_ID,
- generatedAt: new Date().toISOString(),
- totals: {
- commandTokens: commandTotal,
- artifactTokens: artifacts.reduce((sum, entry) => sum + entry.tokens, 0),
- },
- commands: commands.map(({ name, command, tokens, chars }) => ({
- name,
- command: command.replace(/local:[0-7][0-9A-HJKMNP-TV-Z]{25}/g, 'local:').replace(/01[0-9A-HJKMNP-TV-Z]{24}/g, ''),
- tokens,
- chars,
- })),
- artifacts,
- };
-}
-
-function printTable(report) {
- const width = Math.max(...report.commands.map((entry) => entry.name.length));
- console.log(`Token economy report (${report.tokenizerId})`);
- console.log('-'.repeat(width + 20));
- for (const entry of report.commands) {
- console.log(
- `${entry.name.padEnd(width)} ${String(entry.tokens).padStart(7)} tokens`,
- );
- }
- console.log('-'.repeat(width + 20));
- console.log(
- `${'total (commands)'.padEnd(width)} ${String(report.totals.commandTokens).padStart(7)} tokens`,
- );
- for (const artifact of report.artifacts) {
- console.log(
- `${`artifact ${artifact.name}`.padEnd(width)} ${String(artifact.tokens).padStart(7)} tokens`,
- );
- }
-}
-
-function compareWithBaseline(report, baseline) {
- const failures = [];
- const baselineCommands = new Map(
- baseline.commands.map((entry) => [entry.name, entry]),
- );
- for (const entry of report.commands) {
- const reference = baselineCommands.get(entry.name);
- if (!reference) {
- failures.push(`command ${entry.name} missing from the baseline`);
- continue;
- }
- if (outsideTolerance(entry.tokens, reference.tokens)) {
- failures.push(
- `command ${entry.name}: ${entry.tokens} tokens vs baseline ${reference.tokens}`,
- );
- }
- }
- for (const reference of baseline.commands) {
- if (!report.commands.some((entry) => entry.name === reference.name)) {
- failures.push(`baseline command ${reference.name} was not measured`);
- }
- }
- if (outsideTolerance(report.totals.commandTokens, baseline.totals.commandTokens)) {
- failures.push(
- `command total: ${report.totals.commandTokens} tokens vs baseline ${baseline.totals.commandTokens}`,
- );
- }
- return failures;
-}
-
-function outsideTolerance(actual, expected) {
- if (expected === 0) return actual !== 0;
- return Math.abs(actual - expected) / expected > TOLERANCE;
-}
-
-function semanticRequirementsFixture() {
- return {
- version: 1,
- goal: 'Measure the token cost of every v3 CLI receipt.',
- confirmedScope: ['Execute the full man workflow against dist/cli.js'],
- excludedScope: ['Change any command behavior during measurement'],
- technicalDecisions: ['Count tokens with the cl100k_base encoding'],
- defaults: [],
- blockingUnknowns: [],
- coverage: REQUIREMENT_DIMENSIONS.map((dimension) => ({
- dimension,
- status: dimension === 'technical_stack' ? 'confirmed' : 'defaulted',
- rationale: `Considered ${dimension} for the measurement fixture.`,
- })),
- acceptanceCriteria: [
- {
- id: 'AC-1',
- description: 'Every workflow receipt is captured and tokenized.',
- required: true,
- method: 'automated',
- },
- ],
- };
-}
-
-function passedReview(previous, requirementsDigest, planVersion) {
- const draft = {
- ...previous,
- revision: previous.revision + 1,
- status: 'passed',
- requirementsDigest,
- planVersion,
- requiredDomains: ['quality'],
- domains: [{ domain: 'quality', status: 'passed', reportRef: null }],
- blockers: [],
- remediationRound: 0,
- skip: null,
- contentDigest: '',
- lastOperationId: ulid(),
- updatedAt: new Date().toISOString(),
- };
- return { ...draft, contentDigest: reviewLedgerDigest(draft) };
-}
-
-function passedVerification(previous, requirements, planVersion, remediationRound) {
- const criterion = requirements.acceptanceCriteria[0];
- assert(criterion !== undefined, 'finalized requirements are missing AC-1');
- const draft = {
- ...previous,
- revision: previous.revision + 1,
- status: 'passed',
- requirementsDigest: requirements.contentDigest,
- planVersion,
- remediationRound,
- checks: [
- {
- displayId: criterion.displayId,
- legacyId: criterion.legacyId,
- checkId: ulid(),
- criterionId: criterion.criterionId,
- required: criterion.required,
- verificationRequirement: criterion.verificationRequirement,
- automated: {
- evidenceId: ulid(),
- status: 'passed',
- summary: 'Token economy fixture verification passed.',
- command: 'npm test',
- exitCode: 0,
- artifactRef: null,
- confirmedByActorId: null,
- confirmationSource: null,
- updatedAt: new Date().toISOString(),
- },
- manual: null,
- },
- ],
- contentDigest: '',
- lastOperationId: ulid(),
- updatedAt: new Date().toISOString(),
- };
- return { ...draft, contentDigest: verificationLedgerDigest(draft) };
-}
-
-/** Mirrors src/context/review-ledger.ts reviewLedgerDigest. */
-function reviewLedgerDigest(ledger) {
- return digestCanonicalJson({
- schemaVersion: ledger.schemaVersion,
- canonicalizationVersion: ledger.canonicalizationVersion,
- taskRef: ledger.taskRef,
- status: ledger.status,
- depth: ledger.depth,
- requirementsDigest: ledger.requirementsDigest,
- planVersion: ledger.planVersion,
- requiredDomains: ledger.requiredDomains,
- domains: ledger.domains,
- blockers: ledger.blockers,
- remediationRound: ledger.remediationRound,
- skip: ledger.skip,
- legacySource: ledger.legacySource,
- });
-}
-
-/** Mirrors src/context/verification-ledger.ts verificationLedgerDigest. */
-function verificationLedgerDigest(ledger) {
- return digestCanonicalJson({
- schemaVersion: ledger.schemaVersion,
- canonicalizationVersion: ledger.canonicalizationVersion,
- taskRef: ledger.taskRef,
- status: ledger.status,
- requirementsDigest: ledger.requirementsDigest,
- planVersion: ledger.planVersion,
- remediationRound: ledger.remediationRound,
- checks: ledger.checks,
- legacySource: ledger.legacySource,
- });
-}
-
-/** RFC 8785-style canonical JSON (sorted keys), same as src/context/canonical.ts. */
-function digestCanonicalJson(value) {
- const canonical = canonicalize(value);
- return `sha256:${createHash('sha256').update(canonical, 'utf8').digest('hex')}`;
-}
-
-function canonicalize(value) {
- if (value === null) return 'null';
- if (typeof value === 'string' || typeof value === 'boolean') {
- return JSON.stringify(value);
- }
- if (typeof value === 'number') {
- assert(Number.isSafeInteger(value), 'canonical numbers must be safe integers');
- return JSON.stringify(value);
- }
- if (Array.isArray(value)) {
- return `[${value.map((item) => canonicalize(item)).join(',')}]`;
- }
- if (typeof value === 'object') {
- const keys = Object.keys(value).sort();
- return `{${keys
- .map((key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`)
- .join(',')}}`;
- }
- throw new Error('canonical JSON only accepts plain JSON values');
-}
-
-function ulid(now = Date.now()) {
- let time = '';
- let remaining = now;
- for (let index = 0; index < 10; index += 1) {
- time = ULID_ALPHABET[remaining % 32] + time;
- remaining = Math.floor(remaining / 32);
- }
- const bytes = randomBytes(10);
- let random = '';
- let bits = 0;
- let accumulator = 0;
- for (const byte of bytes) {
- accumulator = (accumulator << 8) | byte;
- bits += 8;
- while (bits >= 5) {
- random += ULID_ALPHABET[(accumulator >>> (bits - 5)) & 31];
- bits -= 5;
- }
- }
- return time + random;
-}
-
-function parseOptions(args) {
- const parsed = { output: null, check: false, help: false };
- for (let index = 0; index < args.length; index += 1) {
- const argument = args[index];
- if (argument === '--help') {
- parsed.help = true;
- continue;
- }
- if (argument === '--check') {
- parsed.check = true;
- continue;
- }
- if (argument !== '--output') {
- throw new Error(`unknown context-economy-report argument: ${argument}`);
- }
- const value = args[index + 1];
- assert(value !== undefined, '--output requires a value');
- parsed.output = value;
- index += 1;
- }
- return parsed;
-}
-
-function assert(condition, message) {
- if (!condition) throw new Error(message);
-}
diff --git a/scripts/release-check.mjs b/scripts/release-check.mjs
index 076ec8d..feb6942 100644
--- a/scripts/release-check.mjs
+++ b/scripts/release-check.mjs
@@ -112,11 +112,14 @@ try {
);
const audit = JSON.parse(
- runCaptured('npm', ['audit', '--omit=dev', '--json'], checkout),
+ runCaptured('npm', ['audit', '--audit-level=high', '--json'], checkout),
);
- const vulnerabilities = audit.metadata?.vulnerabilities?.total;
- assert(vulnerabilities === 0, 'production dependency audit is not clean');
- checks.push({ name: 'production_audit', status: 'passed' });
+ const vulnerabilities = audit.metadata?.vulnerabilities;
+ assert(
+ vulnerabilities?.high === 0 && vulnerabilities?.critical === 0,
+ 'dependency audit contains high or critical vulnerabilities',
+ );
+ checks.push({ name: 'dependency_audit', status: 'passed' });
const dryRun = parseSinglePackResult(
runCaptured('npm', ['pack', '--dry-run', '--json'], checkout),
diff --git a/src/cli.ts b/src/cli.ts
index 652854e..ed7a713 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -1,5 +1,7 @@
#!/usr/bin/env node
-import { Option, program } from 'commander';
+import { realpathSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { Command, Option } from 'commander';
import { adapterStatus, adapterUpgrade } from './commands/adapter.js';
import {
contextBeta,
@@ -66,1034 +68,1120 @@ import {
} from './commands/team.js';
import { uninstall } from './commands/uninstall.js';
import { version } from './commands/version.js';
+import { WORKFLOW_SUBCOMMANDS } from './commands/workflow-subcommands.js';
import { workflow } from './commands/workflow.js';
import { VERSION } from './version.js';
-program
- .name('mancode')
- .description(
- 'AI coding agent harness. Modes: solo, man, manba, manteam, manps.',
- )
- .version(VERSION);
-
-program
- .command('init')
- .description('Initialize mancode in the current project')
- .option('--force', 'Reinstall even if already initialized')
- .option('--yes', 'Skip all confirmations (CI mode)')
- .option('--team', 'Force enable team mode (MVP-2)')
- .option('--no-team', 'Force disable team mode (MVP-2)')
- .option('--style ', 'Specify aesthetic style (MVP-2)')
- .option('--platform ', 'Adapters: comma-separated names or all')
- .option('--empty', 'Initialize a safe empty directory as a generic project')
- .addOption(new Option('--v3').hideHelp())
- .option('--legacy', 'Use the legacy state.json initializer')
- .option('--lang ', 'Initialization language: zh-CN or en')
- .action(async (options) => {
- const code = await init(process.cwd(), {
- ...options,
- fromCli: true,
- interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
+export function createCliProgram(): Command {
+ const program = new Command();
+
+ program
+ .name('mancode')
+ .description(
+ 'AI coding agent harness. Modes: solo, man, manba, manteam, manps.',
+ )
+ .version(VERSION);
+
+ program
+ .command('init')
+ .description('Initialize mancode in the current project')
+ .option('--force', 'Reinstall even if already initialized')
+ .option('--yes', 'Skip all confirmations (CI mode)')
+ .option('--team', 'Force enable team mode')
+ .option('--no-team', 'Force disable team mode')
+ .option(
+ '--style ',
+ 'Legacy aesthetic style (only supported with mancode init --legacy)',
+ )
+ .option('--platform ', 'Adapters: comma-separated names or all')
+ .option('--empty', 'Initialize a safe empty directory as a generic project')
+ .addOption(new Option('--v3').hideHelp())
+ .option('--legacy', 'Use the legacy state.json initializer')
+ .option('--lang ', 'Initialization language: zh-CN or en')
+ .action(async (options) => {
+ const code = await init(process.cwd(), {
+ ...options,
+ fromCli: true,
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
+ });
+ process.exitCode = code;
});
- process.exitCode = code;
- });
-
-program
- .command('install [platform]')
- .description(
- 'Install platform adapter (claude-code, cursor, codex, copilot, zcode, kimi-code, qoder)',
- )
- .option('--force', 'Reinstall even if already installed')
- .option('--minimal', 'Minimal install (MVP-2)')
- .option(
- '--shadow',
- 'Stage a mancode bootstrap candidate without changing live files',
- )
- .option('--confirm', 'Confirm a journaled adapter install or repair')
- .option('--operation-id ', 'Operation ID returned by adapter dry-run')
- .option('--session ', 'mancode session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .action(async (platform, options) => {
- const code = await install(
- process.cwd(),
- platform ?? 'claude-code',
- options,
- );
- process.exitCode = code;
- });
-
-const adapterProgram = program
- .command('adapter')
- .description('Inspect and explicitly upgrade managed platform adapters');
-
-adapterProgram
- .command('status')
- .description('Inspect managed adapter content on disk')
- .option('--platform ', 'Inspect one platform adapter')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await adapterStatus(process.cwd(), options);
- });
-
-adapterProgram
- .command('upgrade')
- .description('Preview or repair managed adapter content')
- .option('--all', 'Upgrade all platform adapters')
- .option('--platform ', 'Upgrade one platform adapter')
- .option('--dry-run', 'Stage and report changes without writing live targets')
- .option('--confirm', 'Confirm the journaled adapter upgrade')
- .option('--operation-id ', 'Operation ID returned by adapter dry-run')
- .option('--session ', 'mancode session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await adapterUpgrade(process.cwd(), options);
- });
-
-program
- .command('status')
- .description('Show current mancode project status')
- .option('--json', 'Output as JSON (for scripts)')
- .option('--brief', 'Output compact mancode Continuity runtime status')
- .action(async (options) => {
- const code = await status(process.cwd(), options);
- process.exitCode = code;
- });
-
-const projectProgram = program
- .command('project')
- .description('Manage project-level mancode policy and compatibility');
-
-projectProgram
- .command('upgrade')
- .description('Upgrade project governance policy explicitly')
- .requiredOption('--policy ', 'Target planning policy version (2)')
- .option('--dry-run', 'Preview the upgrade without writing')
- .option('--operation-id ', 'Operation ID returned by project dry-run')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await projectUpgrade(process.cwd(), options);
- });
-
-program
- .command('list-platforms')
- .description('List available and installed mancode platform adapters')
- .action(async () => {
- const code = await listPlatforms(process.cwd());
- process.exitCode = code;
- });
-
-program
- .command('uninstall [platform]')
- .description('Remove platform adapter or all mancode artifacts')
- .option('--force', 'Skip confirmation message')
- .option('--all', 'Remove everything including .mancode/ directory')
- .action(async (platform, options) => {
- const code = await uninstall(process.cwd(), platform, options);
- process.exitCode = code;
- });
-
-program
- .command('workflow [args...]')
- .description('Manage mancode workflows')
- .option('--dry-run', 'Preview clean without deleting')
- .option('--older-than ', 'Clean workflows older than (e.g. 30d)')
- .option('--step ', 'Update workflow current step')
- .option('--status ', 'Update workflow status')
- .option(
- '--parent-task ',
- 'Parent /man or /manteam workflow for manba',
- )
- .option('--parent ', 'Parent TaskRef for a manba child')
- .option(
- '--participant ',
- 'Invite a joined team participant',
- collectOption,
- [],
- )
- .option('--visibility ', 'Task visibility: local or shared')
- .option('--coordination ', 'Task coordination: single or team')
- .option('--session ', 'mancode session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--expected-revision ', 'Expected task revision for mutations')
- .option('--checkpoint-id ', 'Checkpoint ID for a requirements reframe')
- .option('--child-revision ', 'Expected child task revision for merge')
- .option('--summary ', 'Privacy-screened child result summary')
- .option('--next-action ', 'Next parent action after a child merge')
- .option('--sync', 'Publish shared mutations through git-ref transport')
- .option(
- '--confirm-shared',
- 'Confirm that task metadata may enter shared mancode authority',
- )
- .option('--blocking-reason ', 'Explain why a workflow is blocked')
- .option('--outcome ', 'Set manba outcome when completing a task')
- .option('--plan-version ', 'Set the next man/manteam plan revision')
- .option(
- '--requirements-status ',
- 'Planning readiness: ready or needs_clarification',
- )
- .option(
- '--plan-decision ',
- 'Plan gate choice: plan_only or governed_execution',
- )
- .option('--to ', 'Workflow handoff target (solo)')
- .option('--complete', 'Complete an active solo handoff')
- .option(
- '--skipped ',
- 'Policy v2: clarification only; use workflow review skip for review',
- )
- .option('--review-depth ', 'Review depth: targeted or full')
- .option('--review-domain ', 'Review domain: quality or security')
- .option(
- '--report ',
- 'Relative Markdown report path for a review domain',
- )
- .option('--blockers ', 'Comma-separated blocker ids found by a review')
- .option(
- '--resolved ',
- 'Comma-separated blocker ids resolved in remediation',
- )
- .option(
- '--file ',
- 'Semantic requirements JSON, plan Markdown, or ledger input file',
- )
- .option(
- '--scope-file ',
- 'Plan implementation scope JSON {include,exclude,modules}',
- )
- .option('--acceptance ', 'Acceptance criterion id (for example AC-1)')
- .option('--method ', 'Verification method: automated or manual')
- .option('--result ', 'Verification result')
- .option('--evidence ', 'Verification evidence or user confirmation')
- .option('--command ', 'Command used for automated verification')
- .option('--exit-code ', 'Exit code from automated verification')
- .option('--evidence-file ', 'Existing verification report or artifact')
- .option('--reason ', 'Reason for an explicit review skip')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (subcommand, args, options) => {
- const code = await workflow(process.cwd(), subcommand, args ?? [], {
- ...options,
- participants:
- options.participant.length === 0 ? undefined : options.participant,
+
+ program
+ .command('install [platform]')
+ .description(
+ 'Install platform adapter (claude-code, cursor, codex, copilot, zcode, kimi-code, qoder)',
+ )
+ .option('--force', 'Reinstall even if already installed')
+ .option(
+ '--minimal',
+ 'Retained for legacy compatibility; Continuity bootstrap is already minimal',
+ )
+ .option(
+ '--shadow',
+ 'Stage a mancode bootstrap candidate without changing live files',
+ )
+ .option('--confirm', 'Confirm a journaled adapter install or repair')
+ .option('--operation-id ', 'Operation ID returned by adapter dry-run')
+ .option(
+ '--session ',
+ 'mancode session ID (otherwise MANCODE_SESSION_ID)',
+ )
+ .option('--client ', 'Client identity (default: mancode-cli)')
+ .action(async (platform, options) => {
+ const code = await install(
+ process.cwd(),
+ platform ?? 'claude-code',
+ options,
+ );
+ process.exitCode = code;
});
- process.exitCode = code;
- });
-
-const contextProgram = program
- .command('context')
- .description('Resolve mancode task context and manage explicit sessions');
-
-contextProgram
- .command('show')
- .description('Resolve one mancode Context Pack')
- .option('--task ', 'Explicit TaskRef')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--level ', 'bootstrap, task, or full')
- .option(
- '--purpose ',
- 'orient, plan, implement, review, verify, or handoff',
- )
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextShow(process.cwd(), options);
- });
-
-const contextSessionProgram = contextProgram
- .command('session')
- .description('Manage mancode session identities');
-
-contextSessionProgram
- .command('new')
- .description('Create an explicit bootstrap session')
- .requiredOption('--client ', 'Client identity')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextSessionNew(process.cwd(), options);
- });
-
-contextSessionProgram
- .command('show')
- .description('Show one explicit session without changing it')
- .requiredOption('--session ', 'Session ID')
- .option('--client ', 'Expected client identity')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextSessionShow(process.cwd(), options);
- });
-
-contextSessionProgram
- .command('spike')
- .description('Record real-host session evidence without persisting host keys')
- .requiredOption(
- '--platform ',
- 'claude-code, codex, cursor, copilot, zcode, kimi-code, or qoder',
- )
- .requiredOption('--session-mode ', 'Evidence path: host or explicit')
- .requiredOption(
- '--host-session-source ',
- 'hook_stdin, environment, api, or none for explicit sessions',
- )
- .requiredOption(
- '--command-propagation ',
- 'Real host child-command result: proven, not_proven, not_tested, or not_applicable',
- )
- .requiredOption(
- '--subagent-inheritance ',
- 'Real host child-agent result: proven, not_proven, not_tested, or not_applicable',
- )
- .option(
- '--subagent-inheritance-reason ',
- 'Required when child-agent inheritance is not applicable',
- )
- .option(
- '--hook-approval ',
- 'approved, unapproved, unknown, or not_applicable',
- )
- .requiredOption(
- '--host-version ',
- 'Installed host version used for the spike',
- )
- .requiredOption(
- '--release-candidate ',
- 'Immutable mancode release candidate or source commit identifier',
- )
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextSessionSpike(process.cwd(), options);
- });
-
-contextProgram
- .command('resume ')
- .description('Validate and bind the current session to a mancode TaskRef')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--sync', 'Publish shared mutations through git-ref transport')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (task, options) => {
- process.exitCode = await contextResume(process.cwd(), task, options);
- });
-
-contextProgram
- .command('close')
- .description('Close one explicit session without affecting other sessions')
- .requiredOption('--session ', 'Session ID')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextClose(process.cwd(), options);
- });
-
-contextProgram
- .command('doctor')
- .description('Inspect unfinished mancode operations or repair one explicitly')
- .option(
- '--repair ',
- 'Repair this operation with its original session',
- )
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextDoctor(process.cwd(), options);
- });
-
-contextProgram
- .command('diagnostics [action]')
- .description('Show or configure local aggregate diagnostics')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (action, options) => {
- process.exitCode = await contextDiagnostics(process.cwd(), action, options);
- });
-
-contextProgram
- .command('compact')
- .description('List and remove eligible mancode runtime retention candidates')
- .option('--task ', 'Compact checkpoints for one completed task')
- .option('--dry-run', 'Show the deletion list without changing files')
- .option('--apply-shared', 'Permit deletion for shared completed tasks')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextCompact(process.cwd(), options);
- });
-
-contextProgram
- .command('beta', { hidden: true })
- .description('Evaluate internal release-evidence gates')
- .requiredOption(
- '--release-candidate ',
- 'Release candidate that must match every platform evidence record',
- )
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextBeta(process.cwd(), options);
- });
-
-contextProgram
- .command('publish ')
- .description('Create a privacy-screened shared man successor')
- .requiredOption('--expected-revision ', 'Current local task revision')
- .requiredOption(
- '--confirm-shared',
- 'Confirm that the screened task authority may enter shared storage',
- )
- .option('--dry-run', 'Validate the publish preflight without writing')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (task, options) => {
- process.exitCode = await contextPublish(process.cwd(), task, options);
- });
-
-contextProgram
- .command('reconcile-task-head ')
- .description(
- 'Adopt a Git-sourced shared aggregate through an explicit fence CAS',
- )
- .requiredOption(
- '--expected-fence-revision ',
- 'Current shared task-head fence revision',
- )
- .requiredOption(
- '--from-git',
- 'Confirm the checked-out aggregate came from Git',
- )
- .option('--dry-run', 'Validate adoption without changing the task-head fence')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (task, options) => {
- process.exitCode = await contextReconcileTaskHead(
- process.cwd(),
- task,
- options,
- );
- });
-
-contextProgram
- .command('glossary ')
- .description('Manage the user-confirmed shared project glossary')
- .option('--term ', 'Glossary term (add, update, remove)')
- .option('--definition ', 'Term definition (add, update)')
- .option(
- '--alias ',
- 'Term alias; repeat for multiple aliases (add, update)',
- (value: string, previous: string[]) => [...previous, value],
- [] as string[],
- )
- .option('--task ', 'Source shared TaskRef (add, update)')
- .option(
- '--expected-revision ',
- 'Current glossary revision (0 for an empty glossary)',
- )
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (action, options) => {
- process.exitCode = await contextGlossary(process.cwd(), action, options);
- });
-
-const contextWorktreeProgram = contextProgram
- .command('worktree')
- .description('Register and inspect the current mancode checkout binding');
-
-contextWorktreeProgram
- .command('register')
- .description(
- 'Register this linked worktree before using mancode coordination',
- )
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await contextWorktreeRegister(process.cwd(), options);
- });
-
-const operationProgram = program
- .command('operation')
- .description('Inspect and recover durable mancode operations');
-
-operationProgram
- .command('show ')
- .description('Show one operation journal and its recovery disposition')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (operationId, options) => {
- process.exitCode = await operationShow(process.cwd(), operationId, options);
- });
-
-operationProgram
- .command('repair ')
- .description('Repair an operation using its original actor and session')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (operationId, options) => {
- process.exitCode = await operationRepair(
- process.cwd(),
- operationId,
- options,
- );
- });
-
-operationProgram
- .command('abort ')
- .description(
- 'Abort only an operation proven to have no visible business write',
- )
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (operationId, options) => {
- process.exitCode = await operationAbort(
- process.cwd(),
- operationId,
- options,
- );
- });
-
-const teamProgram = program
- .command('team')
- .description('Manage mancode local identity and local-team membership');
-
-teamProgram
- .command('status')
- .description('Show mancode team policy, transport, and local identity state')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await teamStatus(process.cwd(), options);
- });
-
-teamProgram
- .command('policy ')
- .description('Set the mancode team recommendation policy with a revision CAS')
- .requiredOption('--expected-revision ', 'Current team policy revision')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (policy, options) => {
- process.exitCode = await teamPolicy(process.cwd(), {
- ...options,
- policy,
+
+ const adapterProgram = program
+ .command('adapter')
+ .description('Inspect and explicitly upgrade managed platform adapters');
+
+ adapterProgram
+ .command('status')
+ .description('Inspect managed adapter content on disk')
+ .option('--platform ', 'Inspect one platform adapter')
+ .option('--json', 'Output as JSON (for scripts)')
+ .action(async (options) => {
+ process.exitCode = await adapterStatus(process.cwd(), options);
});
- });
-
-teamProgram
- .command('conflicts')
- .description(
- 'Inspect local claim conflicts and handoffs without mutating coordination',
- )
- .option('--task ', 'Narrow the report to one shared TaskRef')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await teamConflicts(process.cwd(), options);
- });
-
-const teamTransportProgram = teamProgram
- .command('transport')
- .description('Inspect and migrate the coordination authority');
-
-teamTransportProgram
- .command('status')
- .description('Show active coordination transport and freshness')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await teamTransportStatus(process.cwd(), options);
- });
-
-teamTransportProgram
- .command('set ')
- .description(
- 'Switch an empty coordination authority; otherwise use transport migrate',
- )
- .requiredOption(
- '--expected-config-revision ',
- 'Current project config revision',
- )
- .option(
- '--remote ',
- 'Git remote for a git-ref target (default: origin)',
- )
- .option('--dry-run', 'Validate the empty-authority switch without writing')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (mode, options) => {
- process.exitCode = await teamTransportSet(process.cwd(), {
- ...options,
- mode,
+
+ adapterProgram
+ .command('upgrade')
+ .description('Preview or repair managed adapter content')
+ .option('--all', 'Upgrade all platform adapters')
+ .option('--platform ', 'Upgrade one platform adapter')
+ .option(
+ '--dry-run',
+ 'Stage and report changes without writing live targets',
+ )
+ .option('--confirm', 'Confirm the journaled adapter upgrade')
+ .option('--operation-id ', 'Operation ID returned by adapter dry-run')
+ .option(
+ '--session ',
+ 'mancode session ID (otherwise MANCODE_SESSION_ID)',
+ )
+ .option('--client ', 'Client identity (default: mancode-cli)')
+ .option('--json', 'Output as JSON (for scripts)')
+ .action(async (options) => {
+ process.exitCode = await adapterUpgrade(process.cwd(), options);
});
- });
-
-teamTransportProgram
- .command('migrate')
- .description('Journal a single-authority local/git-ref transport switch')
- .requiredOption('--to ', 'Target authority: local or git-ref')
- .requiredOption(
- '--expected-config-revision ',
- 'Current project config revision',
- )
- .option(
- '--remote ',
- 'Git remote for a git-ref target (default: origin)',
- )
- .option('--dry-run', 'Validate and preview without writing authority state')
- .option('--confirm', 'Explicitly confirm the authority migration')
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await teamTransportMigrate(process.cwd(), options);
- });
-
-teamTransportProgram
- .command('recover ')
- .description('Repair forward or safely abort a transport migration')
- .requiredOption('--to ', 'Original target authority: local or git-ref')
- .option('--remote ', 'Original Git remote for a git-ref target')
- .option('--abort', 'Abort only before the target authority is established')
- .option('--session ', 'Original migration session ID')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (operationId, options) => {
- process.exitCode = await teamTransportRecover(
- process.cwd(),
- operationId,
- options,
- );
- });
-
-const teamSyncProgram = teamProgram
- .command('sync')
- .description('Explicitly synchronize the git-ref coordination authority');
-
-teamSyncProgram
- .command('pull')
- .description('Fetch, validate, and cache refs/mancode/team')
- .option('--task ', 'Narrow output to one shared TaskRef')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (options) => {
- process.exitCode = await teamSyncPull(process.cwd(), options);
- });
-
-teamSyncProgram
- .command('push ')
- .description('Publish one task bundle through a fresh ownership fence CAS')
- .requiredOption(
- '--expected-task-revision ',
- 'Current shared task revision',
- )
- .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
- .option('--client ', 'Client identity (default: mancode-cli)')
- .option('--json', 'Output as JSON (for scripts)')
- .action(async (task, options) => {
- process.exitCode = await teamSyncPush(process.cwd(), {
- ...options,
- task,
+
+ program
+ .command('status')
+ .description('Show current mancode project status')
+ .option('--json', 'Output as JSON (for scripts)')
+ .option('--brief', 'Output compact mancode Continuity runtime status')
+ .action(async (options) => {
+ const code = await status(process.cwd(), options);
+ process.exitCode = code;
+ });
+
+ const projectProgram = program
+ .command('project')
+ .description('Manage project-level mancode policy and compatibility');
+
+ projectProgram
+ .command('upgrade')
+ .description('Upgrade project governance policy explicitly')
+ .requiredOption('--policy ', 'Target planning policy version (2)')
+ .option('--dry-run', 'Preview the upgrade without writing')
+ .option('--operation-id ', 'Operation ID returned by project dry-run')
+ .option('--session ', 'Session ID (otherwise MANCODE_SESSION_ID)')
+ .option('--client ', 'Client identity (default: mancode-cli)')
+ .option('--json', 'Output as JSON (for scripts)')
+ .action(async (options) => {
+ process.exitCode = await projectUpgrade(process.cwd(), options);
+ });
+
+ program
+ .command('list-platforms')
+ .description('List available and installed mancode platform adapters')
+ .action(async () => {
+ const code = await listPlatforms(process.cwd());
+ process.exitCode = code;
+ });
+
+ program
+ .command('uninstall [platform]')
+ .description('Remove platform adapter or all mancode artifacts')
+ .option('--force', 'Skip confirmation message')
+ .option('--all', 'Remove everything including .mancode/ directory')
+ .action(async (platform, options) => {
+ const code = await uninstall(process.cwd(), platform, options);
+ process.exitCode = code;
+ });
+
+ program
+ .command('workflow [args...]')
+ .description('Manage mancode workflows')
+ .addHelpText(
+ 'after',
+ `\nPublic Continuity subcommands:\n ${WORKFLOW_SUBCOMMANDS.join(', ')}\n`,
+ )
+ .option('--dry-run', 'Preview clean without deleting')
+ .option('--older-than ', 'Clean workflows older than (e.g. 30d)')
+ .option('--step ', 'Update workflow current step')
+ .option('--status ', 'Update workflow status')
+ .option(
+ '--parent-task ',
+ 'Parent /man or /manteam workflow for manba',
+ )
+ .option('--parent ', 'Parent TaskRef for a manba child')
+ .option(
+ '--participant ',
+ 'Invite a joined team participant',
+ collectOption,
+ [],
+ )
+ .option('--visibility ', 'Task visibility: local or shared')
+ .option(
+ '--coordination ',
+ 'Task coordination: single or team',
+ )
+ .option(
+ '--session