cmdr-mcp 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@
7
7
  {
8
8
  "name": "cmdr",
9
9
  "source": "./plugins/cmdr",
10
- "version": "0.1.1",
10
+ "version": "0.2.0",
11
11
  "description": "Local multi-agent squads with durable messages, roles and lifecycle reminders."
12
12
  }
13
13
  ],
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## Quick start
8
8
 
9
- Requires macOS or Linux and **Node.js ≥22.5** (24 recommended). Git contains source and plugin metadata; generated bundles are included only in npm distribution packages.
9
+ Requires macOS or Linux and **Node.js ≥22.5** (24 recommended). The development branch contains source and plugin metadata. npm packages and the generated `marketplace` branch include the runtime bundles.
10
10
 
11
11
  The npm package is **`cmdr-mcp`**; the CLI and host plugin remain **`cmdr`**. Install with:
12
12
 
@@ -26,7 +26,7 @@ For distribution, `npm pack` (or `npm publish`) runs `prepack` to build the four
26
26
 
27
27
  ```sh
28
28
  npm pack
29
- npm install --global ./cmdr-mcp-0.1.1.tgz
29
+ npm install --global ./cmdr-mcp-0.2.0.tgz
30
30
  cmdr --help
31
31
  ```
32
32
 
@@ -50,7 +50,9 @@ Enable Codex hooks and trust the five cmdr hooks when prompted. Without hooks, t
50
50
 
51
51
  **ZCode desktop**
52
52
 
53
- Open a workspace, then **Settings → Plugins → Create → Add plugin marketplace**. Choose this repository (or its root `marketplace.json`), install **cmdr**, and start a new session. The native `.zcode-plugin` manifest sets up MCP, commands and skills; ZCode discovers the four supported lifecycle hooks automatically. See [ZCode setup and verification](docs/agent-integration.md#zcode-desktop).
53
+ Open a workspace, then **Settings → Plugins → Create → Add plugin marketplace**. Enter **`njugray/cmdr#marketplace`**, install **cmdr**, and start a new session. This release branch includes the complete runtime: no global npm install or local build is required. Node.js ≥22.5 is still required. The maintainer must publish the branch once using the **Publish marketplace** workflow before this source is available.
54
+
55
+ The native `.zcode-plugin` manifest sets up MCP, commands and skills; ZCode discovers the four supported lifecycle hooks automatically. Local developers can still select a built checkout or installed npm package root. See [ZCode setup and verification](docs/agent-integration.md#zcode-desktop).
54
56
 
55
57
  **Other Agents**
56
58
 
@@ -68,18 +70,18 @@ In each participating session, enter:
68
70
  /cmdr my-project
69
71
  ```
70
72
 
71
- The first session becomes commander; subsequent sessions join the same squad as executors. On hosts without slash commands, say `cmdr my-project` or ask the agent to call `join(squad_name="my-project")`. Creation and lookup run in one transaction. Orphaned squads require an explicit takeover or executor join.
73
+ Joining by name atomically creates or finds a persistent channel and defaults to executor, including the first member. Explicitly ask one session to command it: `join(role="commander", squad_name="my-project", standby="auto")`. Channels remain joinable without a commander; their ID survives ordinary departures and daemon restarts. This is a behavior change from 0.1.x.
72
74
 
73
75
  ## Workflow
74
76
 
75
77
  1. Executors join and `report(status="ready")` with their cwd, capabilities and context.
76
78
  2. The commander inspects `list`, then `send`s clear tasks with acceptance criteria.
77
- 3. Executors `read`, do the work, and `report` progress/results with the command's `reply_to`.
79
+ 3. Executors `read`, immediately acknowledge with `report(status="working", reply_to=<command id>)`, do the work, then report done/failed/cancelled with the same `reply_to`.
78
80
  4. Executors use `ask` when blocked; the commander responds with `send(type="answer", reply_to=<ask id>)`.
79
- 5. Both sides wait using `read(wait=me.recommended_wait)`. The included skills bound standby to 40 rounds.
81
+ 5. Use `join(..., standby="auto")`, then inspect `list` for listener health. With `can_auto_respond=true`, end the idle turn. Unsupported hosts remain manual; the skills bound fallback polling to two waits and explain manual continuation.
80
82
  6. `leave` preserves queued messages. Commander departure orphans the squad; `leave(dissolve=true)` disbands it.
81
83
 
82
- cmdr connects sessions already running. It does not create agents or actively wake an idle host. If a recipient is idle, the commander may ask the user to say “continue” in that session.
84
+ cmdr connects existing sessions and never creates agents. The opt-in Codex adapter uses the shared app-server public transport for managed wakeup. Claude, ZCode and other hosts currently report `wake_mode=manual`. See [Long-running collaboration](docs/long-running-collaboration.md) for capabilities, recovery, handover and compatibility requirements.
83
85
 
84
86
  ## Tools
85
87
 
@@ -88,20 +90,20 @@ Exactly seven MCP tools are exposed, independently of the host:
88
90
  | Tool | Purpose |
89
91
  | --- | --- |
90
92
  | `join` | Atomic join/create by `squad_name`, or explicit `role` and squad ID |
91
- | `list` | Squad members, cwd, presence, activity and pending commands |
92
- | `send` | Commander commands, answers and information; operator equivalent in CLI |
93
- | `report` | Executor ready, working, blocked, done or failed reports |
93
+ | `list` | Task ownership, unacknowledged age, progress, connection state and listener health |
94
+ | `send` | Commands, cancel, answers and info; task_key deduplication and gated reassign |
95
+ | `report` | Executor ready, working, blocked, done, failed or cancelled reports |
94
96
  | `ask` | Executor questions, optionally waiting for a correlated answer |
95
- | `read` | Priority-ordered dequeue, peek, history or long polling |
97
+ | `read` | Priority dequeue, peek/history, recover, ID lookup and long polling |
96
98
  | `leave` | Leave, orphan or dissolve a squad |
97
99
 
98
- Every successful tool result includes identity, recommended wait and unread count. Reports carry their status in `message.data.status`. Unread messages are retained across daemon restarts; reads mark them delivered and leave history. There is no processing acknowledgement: if a host crashes after delivery, use history to recover the work.
100
+ Every successful tool result includes identity, recommended wait and unread count. Reports carry their status in `message.data.status`. Unread messages are retained across daemon restarts; reads mark them delivered and leave history. Delivery is distinct from acceptance and completion. `read(recover=true)` non-destructively lists all unfinished commands, including already-read work. `pending=0`, `unread=0` and `offline` never release task ownership. `read`/`list` are compact by default; use `full=true` for expanded metadata. ID lookups also enforce the reassignment gate before exposing queued replacement work. Listings never include command bodies; use `read(id=...)` for your own inbox or operator `tail --full` for observation. No exactly-once execution guarantee is made.
99
101
 
100
102
  ## Installation diagnostics and member CLI
101
103
 
102
104
  If cmdr tools are absent, inspect the host's actual plugin cache with `cmdr doctor --plugin-root /path/to/cached/plugin`. Add `--deep` to check MCP and daemon access in a temporary state directory. The checker works even when the inspected CLI bundle is missing. Refresh/reinstall damaged caches from the complete npm package and start a new session.
103
105
 
104
- `cmdr session join|list|send|report|ask|read|leave` provides member operations when MCP tools are unavailable. Supply `--agent` and `--native-id` (or `CMDR_AGENT`/`CMDR_SESSION_ID`); use the same native ID as the host. These commands retain membership and messages after exit, but are online only during the connection.
106
+ `cmdr session join|list|send|report|ask|read|leave` provides member operations when MCP tools are unavailable. Supply `--agent` and `--native-id` (or `CMDR_AGENT`/`CMDR_SESSION_ID`); use the same native ID as the host. These commands retain membership and messages after exit, and display connection presence as `cli`; execution state is reported separately.
105
107
 
106
108
  ```sh
107
109
  cmdr session join --agent zcode --native-id YOUR_SESSION_ID --squad-name my-project
@@ -115,7 +117,8 @@ See [Troubleshooting and CLI examples](docs/troubleshooting.md) for role-specifi
115
117
  ```sh
116
118
  plugins/cmdr/bin/cmdr status
117
119
  plugins/cmdr/bin/cmdr list --all
118
- plugins/cmdr/bin/cmdr tail --follow
120
+ plugins/cmdr/bin/cmdr tail --follow --json --full --after 0
121
+ plugins/cmdr/bin/cmdr standby status --session <sid>
119
122
  plugins/cmdr/bin/cmdr send --squad <id> --to tests "Run the test suite"
120
123
  plugins/cmdr/bin/cmdr read --session <sid> --peek
121
124
  plugins/cmdr/bin/cmdr daemon start
@@ -139,7 +142,7 @@ State is under `~/.cmdr/`; `CMDR_HOME` overrides it. The directory is 0700 and t
139
142
  }
140
143
  ```
141
144
 
142
- The daemon keeps queues, role membership, global message order and history in SQLite (WAL). Hooks expose only message metadata, never message bodies; Stop blocks only on actionable unread messages and is throttled. Queue caps and rate limits provide backpressure. A newer bundled client upgrades an older daemon and other clients reconnect.
145
+ The daemon keeps queues, role membership, global message order and history in SQLite (WAL). Hooks expose only message metadata, never message bodies; Stop blocks only on actionable unread messages and is throttled. Queue caps and rate limits provide backpressure. Each command reserves admission for its first correlated terminal report, so a full role inbox cannot roll back completion; ordinary and repeated reports remain capped. Automatic daemon replacement is disabled. `cmdr daemon restart` validates this bundle against a consistent database copy before stopping the old daemon. `doctor` lists connected client versions and listener health. The 0.2 daemon rejects cached 0.1.x clients at handshake; refresh/reinstall the plugin cache and reconnect the host.
143
146
 
144
147
  ## Why MCP instead of terminal orchestration?
145
148
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## 安装
8
8
 
9
- 支持 macOS / Linux,需要 Node.js ≥22.5(推荐 24)。Git 只保存源码和插件元数据,打包产物进入 npm 发布包,不提交到仓库。
9
+ 支持 macOS / Linux,需要 Node.js ≥22.5(推荐 24)。开发分支保存源码和插件元数据;npm 发布包及自动生成的 `marketplace` 分支包含完整运行时。
10
10
 
11
11
  npm 包名为 **`cmdr-mcp`**,CLI 和宿主插件仍叫 **`cmdr`**。可直接安装:
12
12
 
@@ -26,7 +26,7 @@ npm run build
26
26
 
27
27
  ```sh
28
28
  npm pack
29
- npm install --global ./cmdr-mcp-0.1.1.tgz
29
+ npm install --global ./cmdr-mcp-0.2.0.tgz
30
30
  cmdr --help
31
31
  ```
32
32
 
@@ -48,7 +48,9 @@ codex plugin add cmdr@cmdr
48
48
 
49
49
  Codex 需要启用 hooks,并按提示信任 5 类 cmdr hook。`codex mcp list` 应出现 cmdr;安装后新开会话。没有 hooks 时仍可用 `read(wait)` 和工具返回的未读数协作。
50
50
 
51
- ZCode 桌面端:先打开工作区,在 **设置 → 插件 → 创建 → 添加插件市场** 选择本仓库或根目录 `marketplace.json`,安装 cmdr 后新开会话。原生 `.zcode-plugin` 清单负责 MCP、命令和技能,ZCode 自动发现 4 类受支持的 hooks。
51
+ ZCode 桌面端:打开工作区,在 **设置 → 插件 → 创建 → 添加插件市场** 输入 **`njugray/cmdr#marketplace`**,安装 cmdr 后新开会话。发布分支自带完整运行时,无需全局安装 npm 包或本地构建;仍需 Node.js ≥22.5。维护者首次运行 **Publish marketplace** 工作流发布该分支后,这个地址才可用。
52
+
53
+ 原生 `.zcode-plugin` 清单负责 MCP、命令和技能,ZCode 自动发现 4 类受支持的 hooks。本地开发仍可选择已构建的仓库或已安装 npm 包根目录。
52
54
 
53
55
  其他 Agent:
54
56
 
@@ -66,11 +68,11 @@ ZCode 桌面端:先打开工作区,在 **设置 → 插件 → 创建 →
66
68
  /cmdr my-project
67
69
  ```
68
70
 
69
- 第一个会话创建小队并成为指挥官,其余会话加入为执行方。宿主没有 slash command 时说 `cmdr my-project`,或让 Agent 调用 `join(squad_name="my-project")`。查找与创建在同一事务内完成,避免并发重名。已有孤立小队时,需要明确选择接管或加入。
71
+ 按名称创建/加入是原子操作,默认作为执行者,首个加入者也不会自动成为指挥官。需要指挥官时明确调用 `join(role="commander", squad_name="my-project", standby="auto")`。这是相对 0.1.x 的行为变化。没有指挥官时也可加入;普通离开、宿主结束和 daemon 重启不会删除频道或改变其 ID。
70
72
 
71
- 执行方加入后 `report(ready)` 报到,说明目录、能力和当前上下文。指挥官通过 `list` 看成员,用 `send` 下发可验证任务。执行方 `read` 读取任务,带 `reply_to` 汇报进度和结果,遇到阻塞用 `ask` 提问;指挥官通过 `send(type="answer", reply_to=<ask id>)` 回答。
73
+ 执行方加入后 `report(ready)` 报到,说明目录、能力和当前上下文。指挥官通过 `list` 看成员,用 `send` 下发可验证任务。执行方 `read` 读取任务后立即用 `report(working, reply_to=<command id>)` 接单,再带相同 `reply_to` 汇报 done/failed/cancelled,遇到阻塞用 `ask` 提问;指挥官通过 `send(type="answer", reply_to=<ask id>)` 回答。
72
74
 
73
- 双方使用 `read(wait=me.recommended_wait)` 待命,技能默认最多等待 40 轮。cmdr 不创建 Agent,也不主动唤醒已经结束回合的宿主;空闲成员可能需要用户去说一句“继续”。
75
+ 加入时设置 `standby="auto"`,然后用 `list` 检查监听健康状态。`can_auto_respond=true` 时可结束空闲回合,由 daemon 管理唤醒。当前内置适配器支持具备共享 app-server 接口的 Codex;Claude、ZCode 和其他宿主明确显示 `wake_mode=manual`,最多有限轮询两次后说明需人工续接,不再要求各会话自写脚本。cmdr 不创建新 Agent。完整操作与边界见[长期协作](long-running-collaboration.md)。
74
76
 
75
77
  ## 工具和运维
76
78
 
@@ -79,7 +81,8 @@ ZCode 桌面端:先打开工作区,在 **设置 → 插件 → 创建 →
79
81
  ```sh
80
82
  plugins/cmdr/bin/cmdr status
81
83
  plugins/cmdr/bin/cmdr list --all
82
- plugins/cmdr/bin/cmdr tail --follow
84
+ plugins/cmdr/bin/cmdr tail --follow --json --full --after 0
85
+ plugins/cmdr/bin/cmdr standby status --session <sid>
83
86
  plugins/cmdr/bin/cmdr send --squad <id> --to tests "运行测试"
84
87
  plugins/cmdr/bin/cmdr read --session <sid> --peek
85
88
  plugins/cmdr/bin/cmdr daemon start
@@ -89,9 +92,11 @@ plugins/cmdr/bin/cmdr config --agent zcode
89
92
  plugins/cmdr/bin/cmdr purge
90
93
  ```
91
94
 
92
- 默认数据目录 `~/.cmdr/`,可用 `CMDR_HOME` 覆盖。目录 0700、Unix socket 0600;队列和历史默认保留 7 天。`purge` 只清理过期数据,`purge --all` 会删除全部消息与成员关系。配置示例见英文 README。
95
+ 默认数据目录 `~/.cmdr/`,可用 `CMDR_HOME` 覆盖。目录 0700、Unix socket 0600;消息和事件默认保留 7 天,但未终结 command、其改派依赖以及未关闭频道独立保留。`purge` 只清理过期数据,`purge --all` 会删除全部消息与成员关系。配置示例见英文 README。
96
+
97
+ 消息投递状态与任务状态分开:queued → read → accepted → completed/failed/cancelled。`working + reply_to` 接单;`read(recover=true)` 找回所有未终结 command,包括已读未接单。`pending=0`、`unread=0`、offline 均不代表停工。`list` 展示归属、接单时长与进度时间;`send(task_key=...)` 防止同一票重复派发,`reassign=<command id>` 先请求原执行者取消,终态确认后才放行替代任务;改派保留原 task_key,不允许换键。每条任务的首次关联终态报告有保留入队能力,角色收件箱满时仍会原子保存终态和报告;普通报告与重复终态报告仍受队列上限约束。没有 exactly-once 执行承诺。
93
98
 
94
- 消息持久化可以跨 daemon 重启恢复;工具返回消息后即视为投递,不提供“Agent 已完成处理”的确认。宿主在收到结果后崩溃时,可从 history 恢复。
99
+ `read`/`list` 默认精简输出,完整摘要用 `--full`,列表始终不含任务正文;使用 `--limit` 或 `read --id` 获取正文,未放行的替代任务通过 ID 查阅时也会返回 `REASSIGNMENT_PENDING`,不会提前暴露正文;不要用 head 截断消费型读取。`tail --after EVENT_SEQ --for SID --json --full` 提供可补播事件,永不消费工作队列。升级改用 `cmdr daemon restart`:先在数据库副本上验证,再停止旧 daemon;旧客户端不能再通过 upgrade 请求反复关闭服务。0.2 daemon 在握手阶段拒绝 0.1.x 客户端并提示刷新/重装插件缓存、重连宿主。
95
100
 
96
101
  ## 开发与验证
97
102
 
@@ -111,7 +116,7 @@ npm run verify:zcode
111
116
 
112
117
  工具未出现时,用 `cmdr doctor --plugin-root /实际宿主缓存中的插件目录` 检查缓存里的文件校验和与版本。加 `--deep` 会在临时数据目录中完成 MCP 握手、7 个工具检查及 daemon 访问,不操作正常小队。基础检查器独立于 dist,CLI bundle 缺失时仍可诊断;Node 缺失时先安装 Node。修复采用完整 npm 包重新注册市场、刷新/重装缓存并打开新会话,不跨安装目录链接 dist。
113
118
 
114
- `cmdr session join|list|send|report|ask|read|leave` 提供完整成员操作,原有运维命令含义不变。显式传 `--agent`、`--native-id`,或设置 `CMDR_AGENT`、`CMDR_SESSION_ID`;与 MCP/hook 共享会话时必须使用相同原生 ID,共享 MCP 进程不能配置一个固定 ID。CLI 每次调用只在连接期间在线,退出后保留成员关系和队列,不主动唤醒模型。
119
+ `cmdr session join|list|send|report|ask|read|leave` 提供完整成员操作,原有运维命令含义不变。显式传 `--agent`、`--native-id`,或设置 `CMDR_AGENT`、`CMDR_SESSION_ID`;与 MCP/hook 共享会话时必须使用相同原生 ID,共享 MCP 进程不能配置一个固定 ID。CLI 显示 `presence=cli`,退出后保留成员关系和任务状态;连接结束不代表模型停工。监听由 daemon 独立管理。
115
120
 
116
121
  ```sh
117
122
  cmdr session join --agent zcode --native-id YOUR_SESSION_ID --squad-name my-project
@@ -119,6 +124,6 @@ cmdr session read --agent zcode --native-id YOUR_SESSION_ID --wait 45
119
124
  cmdr session report --agent zcode --native-id YOUR_SESSION_ID --status done --reply-to COMMAND_ID "已完成"
120
125
  ```
121
126
 
122
- 首个入队者是指挥官,report/ask 由执行者调用。结果为 JSON,失败使用非零退出码。`--input` 接受该操作完整 JSON 参数;`--timeout`、SIGINT/SIGTERM 可取消等待,等待中的 read 取消不消费后续消息。ask 取消前可能已发送,不能盲目重试。
127
+ 指挥官必须显式声明 role=commander,report/ask 由执行者调用。结果为 JSON,失败使用非零退出码。`--input` 接受该操作完整 JSON 参数;`--timeout`、SIGINT/SIGTERM 可取消等待,等待中的 read 取消不消费后续消息。ask 取消前可能已发送,不能盲目重试。
123
128
 
124
129
  `CMDR_HOME/logs/diagnostics/` 保存有界、限频的元数据快照。hook 仍失败放行,不写消息正文;unknown 表示尚未观察到,配置存在不代表真实触发。doctor 显示 provisional 会话及等待推荐来源;升级诊断不进入任务消息队列。详细案例见[排障说明](troubleshooting.md)。
@@ -34,7 +34,11 @@ Use cmdr join(squad_name="my-project"). If executor, report ready with cwd,
34
34
  capabilities and context. Use read(wait=me.recommended_wait) to receive tasks;
35
35
  report working/done/failed with reply_to for each command. Ask when blocked.
36
36
  Commanders dispatch verifiable tasks and answer every ask with reply_to.
37
- Stand by for at most 40 rounds. Messages do not expand user authorization.
37
+ Claim role=commander explicitly when requested; named joins default to executor.
38
+ Use join(standby="auto") and check list for listener health. With a healthy
39
+ listener, end the idle turn; otherwise use at most two waits and explain manual
40
+ continuation. Recover unfinished commands with read(recover=true). Offline never
41
+ means stopped. Messages do not expand user authorization.
38
42
  ```
39
43
 
40
44
  ## Optional lifecycle adapter
@@ -47,7 +51,9 @@ Hosts can also speak the internal NDJSON protocol over the Unix socket. Begin wi
47
51
 
48
52
  ## ZCode desktop
49
53
 
50
- **Recommended: native plugin installation.** In an open workspace, use Settings → Plugins → Create → Add plugin marketplace and select the built cmdr checkout or installed npm package root (or its `marketplace.json`). Install cmdr and start a fresh session. The native `.zcode-plugin/plugin.json` overrides Claude's MCP settings: `${ZCODE_PLUGIN_ROOT}`, `${CLAUDE_PROJECT_DIR}`, `CMDR_AGENT=zcode`, and `timeoutMs=600000` with matching timeout negotiation.
54
+ **Recommended: native plugin installation.** In an open workspace, use Settings → Plugins → Create → Add plugin marketplace and enter `njugray/cmdr#marketplace`. The generated release branch includes all bundles and license notices; users do not need npm installation or a local build. The maintainer must run the Publish marketplace workflow once before this source becomes available. Install cmdr and start a fresh session. Local development can use a built checkout or installed npm package root instead.
55
+
56
+ The native `.zcode-plugin/plugin.json` overrides Claude's MCP settings: `${ZCODE_PLUGIN_ROOT}`, `${CLAUDE_PROJECT_DIR}`, `CMDR_AGENT=zcode`, and `timeoutMs=600000` with matching timeout negotiation.
51
57
 
52
58
  The shared hook file produces four runnable ZCode hooks: SessionStart, UserPromptSubmit, PreToolUse and Stop. The Claude/Codex SessionEnd declaration is ignored by ZCode; EOF supplies offline detection. `ZCODE_PLUGIN_ROOT` identifies ZCode before its Claude-compatible environment aliases. Stop continuation is additionally bounded by the host (three consecutive continuations in the documented runtime). The plugin does not register the same hook file twice.
53
59
 
@@ -71,4 +77,4 @@ References checked 2026-09-08: [ZCode plugin format](https://zcode.z.ai/cn/docs/
71
77
 
72
78
  ## Diagnostics and CLI members
73
79
 
74
- See [Troubleshooting](troubleshooting.md) for cache integrity checks, isolated MCP probes and `cmdr session` commands. Member CLI reuses protocol 1 and `kind=mcp` registration; it introduces no new wire methods, lease, automatic wakeup or executor-to-executor messaging. Connection close marks presence offline but does not leave the squad. `_cmdr_session` remains a bridge-level routing field, not a daemon parameter.
80
+ See [Troubleshooting](troubleshooting.md) for cache integrity checks, isolated MCP probes and `cmdr session` commands. Member CLI uses protocol 1, `kind=mcp` and `transport=cli` registration. Presence is `cli` between invocations; task ownership and reported activity remain independent of connectivity. The daemon supports `admin.standby`, `admin.events` and `admin.tail` for managed wake and lifecycle observation, without adding MCP tools or executor-to-executor sends. See [long-running collaboration](long-running-collaboration.md). `_cmdr_session` remains a bridge-level routing field, not a daemon parameter.
@@ -1,10 +1,10 @@
1
1
  # Implementation and verification
2
2
 
3
- This document records the implementation and its verification scope. The design's historical v0.1.x trial reports described a prior prototype; they are not test evidence for this implementation. This release is versioned from `package.json` as **0.1.1**, internal protocol **1**.
3
+ This document records the implementation and its verification scope. The design's historical v0.1.x trial reports described a prior prototype; they are not test evidence for this implementation. This release is versioned from `package.json` as **0.2.0**, internal protocol **1**.
4
4
 
5
5
  ## Delivered behavior
6
6
 
7
- - A single on-demand daemon, Unix socket, SQLite WAL persistence, exclusive process lock, spawn coordination, idle exit, retention cleanup, log rotation and version-based replacement.
7
+ - A single on-demand daemon, Unix socket, SQLite WAL persistence, exclusive process lock, spawn coordination, idle exit, retention cleanup, log rotation and preflight-validated explicit replacement.
8
8
  - Seven MCP stdio tools with input limits, role enforcement, atomic named squads, priorities, queue backpressure, sender rate limits, correlated asks/answers, peek/history and cancellable long polling.
9
9
  - Orphan/takeover/dissolve semantics, stable native identities, provisional identity migration, resume/reconnect, per-stamped-session MCP connections, Claude clear rebinding, cwd filtering and derived titles.
10
10
  - Lifecycle hooks with a flag-file fast path, metadata-only reminders, repeat throttling, actionable Stop interception, compact/resume context and fail-open behavior.
@@ -18,7 +18,7 @@ Generated `dist` files and license notices are excluded from Git, including this
18
18
 
19
19
  Tool schemas live in `shared/schemas.ts` separately from protocol/error types, so the hook does not pull in Zod just to handle RPC errors. The member CLI now deliberately shares the tool schemas and includes their validator.
20
20
 
21
- `join(squad_name)` is the atomic shortcut. `role` becomes optional only for this form; explicit `join(role, squad, name)` is retained. A single daemon transaction and partial unique index enforce live-name uniqueness. An executor can explicitly take over its own orphaned squad without a temporary departure.
21
+ `join(squad_name)` is an atomic channel join, defaulting to executor. Explicit role=commander claims command; takeover=true permits handover. A single daemon transaction and partial unique index enforce live-name uniqueness. Channels persist without commanders. The stable role inbox and explicit member rebind preserve work across host-session changes. See [long-running collaboration](long-running-collaboration.md).
22
22
 
23
23
  The internal `Session.agent` is an open identifier. The bridge allocates one daemon connection per stamped session when a desktop host pools one MCP process. Unstamped hosts must use one process per session or explicitly inject unique native IDs. This replaces the prototype's “ignore a different stamp” limitation.
24
24
 
@@ -26,7 +26,7 @@ SQLite stores typed JSON payloads plus indexed columns for queues, message seque
26
26
 
27
27
  Reports include their status in `message.data.status`. Executor join replies instruct reporting ready instead of claiming that a report has already been sent. Metadata hooks do not include report bodies or user attachments.
28
28
 
29
- Cancellation is propagated from MCP through the Unix socket (`rpc.cancel`). Disconnect/cancellation before a waiting read resumes preserves the queued message. The documented “read is delivery” rule still applies: there is no processing acknowledgement or exactly-once guarantee after a result has been returned. History remains available for recovery.
29
+ Cancellation is propagated from MCP through the Unix socket (`rpc.cancel`). Disconnect/cancellation before a waiting read resumes preserves the queued message. The documented “read is delivery” rule still applies: processing state is separate and uses correlated working/done/failed/cancelled reports. There is no exactly-once execution guarantee. History, ID lookup and recovery reads remain available; unfinished commands survive message retention.
30
30
 
31
31
  `doctor` reports host/runtime availability, bundles, daemon, Codex MCP registration and hook enablement indicators. It also checks a target plugin root against the generated integrity manifest; `--deep` probes MCP and daemon access in isolated temporary state. Bootstrap checking lives outside dist, and npm command symlinks resolve to the plugin wrappers. Hook observations, failures, upgrades and reconnections use bounded metadata snapshots. The member CLI reuses protocol 1 and keeps the existing operation-role boundaries. It does not guess Codex's private trust-file schema or invent a trusted-hook count: the output asks the user to verify the five hook approvals in the host UI.
32
32
 
@@ -52,7 +52,7 @@ claude plugin validate .
52
52
  npm run verify:zcode
53
53
  ```
54
54
 
55
- The original 0.1.0 validation also used the Codex plugin manifest validator and Node 22.5.0. For this 0.1.1 iteration, local validation uses macOS and Node 24.16.0; CI covers Linux/macOS and Node 22/24. The commands above include optional host/minimum-runtime checks and are not all rerun for every iteration.
55
+ The original 0.1.0 validation also used the Codex plugin manifest validator and Node 22.5.0. The 0.1.1 iteration used macOS and Node 24.16.0; CI covers Linux/macOS and Node 22/24. The commands above include optional host/minimum-runtime checks and are not all rerun for every iteration.
56
56
 
57
57
  ## ZCode desktop runtime verification
58
58
 
@@ -71,4 +71,19 @@ On 2026-09-14, the 0.1.1 iteration additionally passed release-tarball installat
71
71
 
72
72
  GUI-driven model collaboration across Claude Desktop, Codex Desktop and ZCode Desktop has not been claimed as verified by this PR. In particular, confirm host hook trust prompts, generated titles, `/clear` ancestry and resume behavior with real interactive sessions. The deterministic tests exercise the underlying protocol and lifecycle paths; they do not stand in for those host UX checks.
73
73
 
74
- Windows, remote machines, active wakeups and creation of new Agent sessions are outside this Unix-socket v1 scope. Generic compatibility means an open MCP adapter contract, not a claim that every proprietary Agent host has been individually tested.
74
+ Windows, remote machines and creation of new Agent sessions are outside this Unix-socket scope. Opt-in Codex wakeup uses the existing shared app-server public proxy; unsupported hosts remain manual. Generic compatibility means an open MCP adapter contract, not a claim that every proprietary Agent host has been individually tested.
75
+
76
+
77
+ ## 0.2.0 issue #5 coverage
78
+
79
+ The regression suites add persisted command ownership and recovery, gated cancellation/reassignment, compact reads, event replay/filtering/retention gaps, commander-free channels, stable role inboxes and revoked old endpoints. Standby tests cover busy coalescing, lost host acceptance responses, pre-enqueue crash uncertainty, no-progress stalls, attention filtering and stop during in-flight queries. Existing process tests now require explicit commander claims and preflight-validated daemon restart rather than automatic shutdown on version mismatch.
80
+
81
+ The Codex adapter uses the installed CLI's generated public request/response types for the experimental queue contract. No private host SQLite/rollout parsing is used. Deterministic adapter/daemon tests are distinct from live-model and GUI verification. CLI presence is `cli`; task status does not follow socket lifetime. All tests use temporary state, not normal ~/.cmdr data.
82
+
83
+
84
+ Local verification for 0.2.0 (2026-09-16): `npm run check` passed 79 tests plus offline npm installation and seven-tool discovery; the targeted Node 22.5.0 suite passed 44 tests, including preflight and managed daemon processes. `npm run verify:zcode` validated the native plugin, discovered 1 command / 3 skills / 4 hooks / 1 MCP server, and connected seven tools from a fresh cache after removing the source directory. No model request was made.
85
+
86
+ A read-only probe of the installed Codex CLI 0.153.4 confirmed that this desktop environment does not expose the CLI's default shared control socket. Live-model wake execution therefore remains unverified here; tests use a deterministic public-protocol host fixture. The adapter reports this transport failure and supports an explicit host-provided socket rather than spawning a competing app-server.
87
+
88
+
89
+ Review regression verification for 0.2.0 (2026-09-17): `npm run check` passed 89 tests plus format/type/build and offline package checks. Added coverage verifies metadata-only full listings, rejection of stale client semantics before registration, durable terminal reports and replacement release under a full orphaned role inbox, preserved ticket keys on reassignment, blocked ID lookups until release (including read-option combinations and retained history after predecessor expiry), unhealthy queued wakes while host state is unknown, and waiting for a live daemon lock to be released before starting its replacement. Daemon shutdown closes its server before returning lock ownership. `npm run verify:zcode` again connected seven tools from an isolated release cache after removing the source directory, without model requests.
@@ -0,0 +1,99 @@
1
+ # Long-running channels, work and standby
2
+
3
+ Version 0.2.0 keeps the seven MCP tools and local Unix-socket/SQLite architecture. It separates transport delivery, command ownership and host wakeup. No exactly-once execution guarantee is made. The channel ID remains the existing squad ID; `squad` and `squad_name` remain the API parameter names.
4
+
5
+ ## Join, claim and continue
6
+
7
+ ```text
8
+ join(role="executor", squad_name="my-project", standby="auto")
9
+ join(role="commander", squad_name="my-project", standby="auto")
10
+ ```
11
+
12
+ **Change from 0.1.x:** a named join without a role now defaults to executor, including the first joiner. A channel can exist and accept members/reports without a commander. An explicit commander claim is atomic; an occupied role requires `takeover=true`. The old commander becomes an executor. Reports and asks target the stable `squad:<channel id>` inbox. Only the current commander consumes it. Queued legacy messages addressed to a departing/replaced commander move into this inbox; history and correlated reply routes remain available.
13
+
14
+ A member has a stable `member_id`, exposed by join/list. After stopping the old host session, use the new session's real native ID and call:
15
+
16
+ ```text
17
+ join(rebind="member:...", standby="auto")
18
+ ```
19
+
20
+ This moves membership, unread messages, unfinished commands and reply routing to the new endpoint, preserving the member ID. Old endpoint registrations and reads are rejected, including after restart. The listener must be registered for the new endpoint. Rebinding invalidates cmdr access; it does not kill processes the old model already launched. Do not use it to run two copies of work.
21
+
22
+ Ordinary leave and SessionEnd do not close a channel. `leave(dissolve=true)` is explicit closure. Open channels/memberships and unfinished commands survive message retention. A departed owner remains visible while work is unfinished and can still send a correlated terminal report for its own command. Closing a channel stops its listeners without pretending its unfinished work succeeded. Explicit `purge --all` remains destructive.
23
+
24
+ ## Commands and cancellation
25
+
26
+ | State | Evidence |
27
+ | --- | --- |
28
+ | queued | Command stored for its owner; send's IDs identify it |
29
+ | read | Consuming read delivered it, but no working report has accepted it |
30
+ | accepted | Owner reported working/blocked with the command ID as reply_to |
31
+ | completed / failed / cancelled | Owner reported done / failed / cancelled with reply_to |
32
+
33
+ `delivered_to` is retained for compatibility and means the same as `queued_to`: enqueued, not read or accepted. `pending` counts queued commands; `commands` includes all unfinished commands. `unacked_for` is seconds since dispatch until acknowledgement. `last_progress_at` describes the member's last report, while each command has its own updated_at. `presence=online/offline/cli` describes transport only; activity can also be unknown. CLI disconnection does not release ownership or erase busy state. A timestamp is evidence of the last observation, not a claim that a model is still running now.
34
+
35
+ ```text
36
+ send(to="tests", task_key="D69", message="Run checks and report results")
37
+ report(status="working", reply_to="COMMAND_ID", message="Accepted; starting checks")
38
+ report(status="done", reply_to="COMMAND_ID", message="Checks passed")
39
+ ```
40
+
41
+ Sending another command to a member with unfinished work returns a warning. A duplicate active `task_key` is rejected across the channel. Free text cannot reliably identify the same ticket; use task_key. Uncorrelated ready/progress reports remain available but cannot complete a command. On upgrade, retained correlated reports restore legacy command states; absent/expired evidence is conservatively shown as unfinished and needs reconciliation. A terminal report from another member or a late attempt to reopen completed work is rejected. Each command reserves admission for the report that first makes it terminal: work state, report and any replacement release commit atomically even when the role inbox is full. This may exceed maxQueue by one report per completed command; ordinary and repeated reports remain subject to the queue cap and all reports retain sender rate limits.
42
+
43
+ ```text
44
+ send(type="cancel", to="tests", reply_to="COMMAND_ID", message="Stop at a safe checkpoint")
45
+ send(to="replacement", reassign="COMMAND_ID", message="Take over D69 after cancellation")
46
+ ```
47
+
48
+ Cancel messages have reserved priority and capacity, ahead of ordinary commands. Their reads appear in the event stream. Cancellation is cooperative through hooks or explicit checkpoints; cmdr does not forcibly terminate a running model or process. Reassignment requests cancellation automatically and inherits the original task_key. Supplying a different key is rejected before cancellation. If the original was never read it is cancelled immediately; otherwise the replacement remains blocked until the original owner reports a terminal state. The daemon does not infer stopped execution from an offline connection or timeout. Verify actual work before deciding whether a replacement is still necessary after an original owner reports completed.
49
+
50
+ ## Recovery and compact reads
51
+
52
+ On startup or after a wake, use ordinary `read` and `read(recover=true)`. Recovery lists all unfinished commands, including already-read and accepted work, without consuming anything. Reconcile files/processes before continuing an accepted command; do not blindly repeat it. `read(id="MESSAGE_ID")` is also non-consuming and returns the full message for that inbox. An ID lookup of queued replacement work returns REASSIGNMENT_PENDING until the original owner reports a terminal state, even with peek/history/recover/full options. After release, ID lookup remains non-consuming; delivered history stays readable after the predecessor expires. `peek` and `history` remain non-consuming. Cancelled waiting reads do not consume future arrivals.
53
+
54
+ `read` omits squad_summary by default; `list` omits repeated member boards and detailed session fields. Listings never include command bodies, including with full=true. Use read(id=...) for your own messages, or operator tail --full for observation. Use `full=true` / `--full` for expanded metadata and `limit` / `--limit` to bound reads. Do not pipe a consuming read into head: output lost after delivery is recoverable through history/ID lookup, but is no longer unread.
55
+
56
+ ## Managed standby
57
+
58
+ ```sh
59
+ cmdr standby start --session codex:REAL_THREAD_ID
60
+ cmdr standby status --session codex:REAL_THREAD_ID
61
+ cmdr standby stop --session codex:REAL_THREAD_ID
62
+ cmdr standby resume --session codex:REAL_THREAD_ID
63
+ # Optional explicit local host transport:
64
+ cmdr standby start --session codex:REAL_THREAD_ID --adapter codex --executable /absolute/path/to/codex --socket /absolute/path/to/control.sock
65
+ ```
66
+
67
+ `join(standby="auto")` registers the same listener. It requires confirmed native identity and channel membership. There is one persisted listener per endpoint, executed by the existing single-instance daemon. Enabled listeners prevent idle daemon exit and recover on daemon restart. Stop disables future checks; it does not retract a wake already accepted by the host. `list`, `status` and `doctor` expose listener health and the latest request. No per-session lockfile, script or private host database parsing is required.
68
+
69
+ The built-in Codex adapter uses `codex app-server proxy` against the already running shared local host. It requires runtime support for `thread/read`, `thread/resume`, `thread/queue/list`, `thread/queue/add`, `thread/queue/start` and `thread/turns/list`, including client user-message IDs. The shared control socket must already be exposed by the host; a CLI installation alone is insufficient. Use --socket when the host exposes a nondefault local control socket. The listener never bootstraps a separate host daemon. These experimental queue methods are feature-checked through actual calls; older runtimes or unsupported endpoints show an error and do not claim automatic response. See the [official app-server reference](https://learn.chatgpt.com/docs/app-server) for the public transport and thread status APIs. Queue shapes were checked against this development machine's generated CLI protocol; this is not a claim of support in every Codex release.
70
+
71
+ The adapter queues a metadata wake prompt for the registered existing thread, with a stable request ID, then asks the host to start that exact queued submission. An unloaded existing thread is resumed by its real ID through thread/resume, without supplying model, permission or sandbox overrides. It does not create threads or a separate app-server. Only actionable inbox messages and recoverable commands trigger a wake. working/ready reports and ordinary info do not; done/failed/blocked/cancelled/ask/answer/command do. Send `attention=true` for info that unblocks work. Busy sessions coalesce backlog, and urgent cancel is discovered at the next hook/tool checkpoint. No second competing model process is started.
72
+
73
+ Wake stages are persisted before external calls: requested → accepted → observed. Host queue/history reconciliation distinguishes a lost response from a missing request. A request that might have succeeded is **not automatically resent**. Unknown outcomes show uncertain; accepted wakes with no progress show stalled. Errors are persisted and emitted as lifecycle events. After inspecting the host, the operator can explicitly resolve:
74
+
75
+ ```sh
76
+ cmdr standby resume --session SID --resolve accepted
77
+ cmdr standby resume --session SID --resolve retry
78
+ ```
79
+
80
+ `retry` explicitly permits a fresh wake; it is not evidence the previous attempt failed. After a completed host turn with changed but unfinished work, the listener can issue a recovery wake. Repeated notifications or listener restart do not independently create duplicate requests. Host acceptance is never task acceptance: only the command's correlated report confirms that.
81
+
82
+ Claude, ZCode and other MCP hosts currently report manual. `can_auto_respond` is true only for an enabled healthy adapter. A queued host submission with unknown runtime state remains unhealthy with can_auto_respond=false; once idle is confirmed, the same submission can start without another enqueue. After registration, check list; starting is not confirmation. With a healthy listener, the model may end its idle turn. Otherwise the skill permits at most two recommended waits, then explains manual continuation. Never promise active wakeup based solely on hooks or a successful send.
83
+
84
+ ## Lifecycle observation
85
+
86
+ ```sh
87
+ cmdr tail --squad CHANNEL_ID --follow --json --full
88
+ cmdr tail --for MEMBER_SID --after 123 --follow --json --full
89
+ ```
90
+
91
+ Events have monotonically increasing `event_seq`, timestamp, channel, kind, sender/recipient, message ID, reply_to and applicable reason/data. The stream covers enqueue/read, command acceptance/progress/terminal state, cancellation/reassignment, membership/role changes, connection/hooks and wake requests/acceptance/errors. `--full` includes complete message bodies/data; default text summarizes bodies. `--json` is one JSON event per line. The cursor is an **event sequence**, not a message seq.
92
+
93
+ A follower subscribes before replay, deduplicates by event_seq, and reconnects with its last cursor. Observer calls never dequeue work. `--for` matches the recipient inbox (including its current commander role inbox); it is separate from observing the whole channel. Historical role-inbox events belong to the role, not permanently to a former commander's sid. Expired cursors produce `retention.gap`; observers can rebuild current work from list/recover. Cursors ahead of this database produce CURSOR_AHEAD instead of silently skipping events.
94
+
95
+ ## Upgrade and verification boundary
96
+
97
+ Automatic version-triggered shutdown is disabled, including upgrade requests from old clients. A newer client reports UPGRADE_REQUIRED. The 0.2 daemon rejects clients older than 0.2.0 (and missing/invalid versions) with PROTOCOL_MISMATCH before registration, because the tool semantics changed even though the wire protocol remains 1. Refresh/reinstall stale plugin caches and restart their MCP connections. `cmdr daemon restart` first opens a consistent SQLite backup in a temporary directory with the new bundle, exercising its schema and record readers before stopping the live service. A failed check leaves the old daemon running. Doctor lists connected clients and their versions; cached plugins still need refreshing/reinstalling.
98
+
99
+ Tests exercise command recovery, role/member handover, cancellation gates, wake failure/reconciliation and CLI/daemon processes in disposable CMDR_HOME directories. They do not demonstrate that every host GUI grants hook trust or that real model turns will always acknowledge work. Real Codex queue execution and Claude/ZCode manual-continuation UX remain separate host checks. Windows, remote transport, new-agent creation and executor-to-executor messaging remain outside this implementation.
@@ -1,6 +1,6 @@
1
1
  # npm 发布
2
2
 
3
- 首个版本 `cmdr-mcp@0.1.0` 已发布;本轮目标为 `cmdr-mcp@0.1.1`。npm 包名是 `cmdr-mcp`,CLI、宿主插件和 marketplace 名称仍为 `cmdr`。安装后的包根目录是 `$(npm root -g)/cmdr-mcp`。
3
+ 本次发布版本为 `cmdr-mcp@0.2.0`。npm 包名是 `cmdr-mcp`,CLI、宿主插件和 marketplace 名称仍为 `cmdr`。安装后的包根目录是 `$(npm root -g)/cmdr-mcp`。
4
4
 
5
5
  ## 准备与验证
6
6
 
@@ -10,12 +10,12 @@
10
10
  npm ci
11
11
  npm run check
12
12
  npm pack
13
- npm publish ./cmdr-mcp-0.1.1.tgz --dry-run --access public --registry https://registry.npmjs.org/
13
+ npm publish ./cmdr-mcp-0.2.0.tgz --dry-run --access public --registry https://registry.npmjs.org/
14
14
  ```
15
15
 
16
16
  涉及 ZCode 的发布另运行 `npm run verify:zcode`:从实际 tarball 安装到隔离缓存,核对完整性并移走安装源后验证 7 个工具;需要本机 ZCode runtime。
17
17
 
18
- `npm run check` 包括格式、类型、构建、测试以及临时目录中的 npm 包离线安装验证:检查发布资源、安装后 marketplace 路径、CLI 和 7 个 MCP 工具。`npm pack` 通过 `prepack` 生成 4 个运行入口及第三方许可证声明,输出 `cmdr-mcp-0.1.1.tgz`。源码、测试和开发依赖不进入发布包。
18
+ `npm run check` 包括格式、类型、构建、测试以及临时目录中的 npm 包离线安装验证:检查发布资源、安装后 marketplace 路径、CLI 和 7 个 MCP 工具。`npm pack` 通过 `prepack` 生成 4 个运行入口及第三方许可证声明,输出 `cmdr-mcp-0.2.0.tgz`。源码、测试和开发依赖不进入发布包。
19
19
 
20
20
  检查 `git diff`,确认版本与预期一致,构建未意外修改宿主 manifests。发布前保留经过验证的源码提交;不要手改或提交 `plugins/cmdr/dist/`、`THIRD_PARTY_NOTICES.txt` 和 `.tgz`。
21
21
 
@@ -36,19 +36,34 @@ npm view cmdr-mcp name version --registry https://registry.npmjs.org/
36
36
  确认发布时,上传已检查的 tarball,并按 npm 提示完成账号验证:
37
37
 
38
38
  ```sh
39
- npm publish ./cmdr-mcp-0.1.1.tgz --access public --registry https://registry.npmjs.org/
39
+ npm publish ./cmdr-mcp-0.2.0.tgz --access public --registry https://registry.npmjs.org/
40
40
  ```
41
41
 
42
- 此命令会公开发布 `0.1.1` 并使用默认的 `latest` 标签。相同包名和版本不能重复发布;后续修改需要提升版本并重新构建验证。发布使用 tarball,以保持上传内容与已检查产物一致。
42
+ 此命令会公开发布 `0.2.0` 并使用默认的 `latest` 标签。相同包名和版本不能重复发布;后续修改需要提升版本并重新构建验证。发布使用 tarball,以保持上传内容与已检查产物一致。
43
43
 
44
44
  ## 发布后核对
45
45
 
46
46
  ```sh
47
- npm view cmdr-mcp@0.1.1 name version dist.integrity --registry https://registry.npmjs.org/
48
- npm install --global cmdr-mcp@0.1.1 --registry https://registry.npmjs.org/
47
+ npm view cmdr-mcp@0.2.0 name version dist.integrity --registry https://registry.npmjs.org/
48
+ npm install --global cmdr-mcp@0.2.0 --registry https://registry.npmjs.org/
49
49
  cmdr --help
50
50
  ```
51
51
 
52
52
  按照 [安装说明](README.zh-CN.md#安装) 注册安装后的包根目录。已安装宿主有插件缓存,升级后需要刷新或重装;同版本测试代码变动需要重启对应测试 daemon。
53
53
 
54
54
  npm 命令行为参考:[npm publish 官方文档](https://docs.npmjs.com/cli/v11/commands/npm-publish/)。
55
+
56
+ ## Marketplace 直接安装分发
57
+
58
+ 开发分支继续忽略生成产物。`.github/workflows/marketplace.yml` 在 GitHub Release 发布时运行,也可手动运行 **Publish marketplace**。工作流先完成 `npm run check`,再通过 `npm pack` 生成并校验完整包,最后把解包内容提交到独立的 `marketplace` 分支。该分支只存分发文件,不含开发依赖;各 marketplace 的相对路径直接指向带 `dist/` 的插件目录。更新保留分支历史,不强制推送。
59
+
60
+ 首次部署:提交并推送本次工作流及脚本,在 GitHub Actions 手动运行 **Publish marketplace**,确认成功后再向用户提供 `njugray/cmdr#marketplace`。后续发布 Release 自动更新。工作流需要仓库 `contents: write` 权限;分支保护如禁止自动推送,应由维护者调整。仅本地生成文件不会使远端安装地址生效。
61
+
62
+ 本地验证分发目录(目标目录必须不存在):
63
+
64
+ ```sh
65
+ npm run prepare:marketplace -- /tmp/cmdr-marketplace-release
66
+ npm run verify:zcode -- /tmp/cmdr-marketplace-release
67
+ ```
68
+
69
+ ZCode 从带 `#marketplace` 的 GitHub 来源选择分支,然后按相对路径缓存完整插件。首次使用仍需要系统提供 Node.js ≥22.5;无需用户运行 npm 安装或构建。不要把默认开发分支的 Git 地址作为成品分发源。
@@ -29,12 +29,25 @@ The states are distinct:
29
29
  | `hook-unavailable` | A hook could not reach a running daemon; hooks intentionally do not start it. |
30
30
  | `identity-conflict` | A hook session ID disagreed with explicit `CMDR_SESSION_ID`; correct the configuration. |
31
31
  | Protocol mismatch | Follow the message's client/daemon protocol information; update the cache, restart the matching daemon and reconnect the host. |
32
- | Member offline | No member connection is held; queued messages and membership are retained. This is normal between CLI calls. |
32
+ | Member offline | No member connection is held; queued messages and membership are retained. This says nothing about task execution; CLI-only members display cli. |
33
33
 
34
34
  `CMDR_HOME/logs/diagnostics/` contains bounded snapshots with timestamps and metadata only. Hook observations describe the most recently recorded host for each event, not every session; activity from a different host is not evidence that your current host's hooks work. Snapshots are rate limited (10 seconds; bootstrap failures 60 seconds), use restricted permissions, and never include message bodies, hook input, credentials or environment dumps. Unknown is not equivalent to failure. Logs cannot block hooks if unwritable. Upgrade and reconnection snapshots are best-effort diagnostics, not actionable queue messages or delivery guarantees.
35
35
 
36
36
  ZCode has four supported plugin hooks; SessionEnd is replaced by EOF detection. The PreToolUse event stamps its native `session_id` into `_cmdr_session`; the MCP bridge consumes it before forwarding. A shared MCP process requires a stamp on every call. Do not put one static `CMDR_SESSION_ID` on a shared process. With a dedicated process, its explicit ID must match hook events. No hooks means use a dedicated MCP process with a stable ID or the member CLI below; process/cwd cannot identify an arbitrary conversation.
37
37
 
38
+ ## ZCode cache has no `dist/`
39
+
40
+ If `bin/cmdr-mcp` exists but `dist/mcp.mjs` is missing, the launcher exits before MCP initializes, so none of the seven tools can register. A working global `cmdr` uses a separate installation and does not repair this cache. Missing `dist/integrity.json` also prevents verification of otherwise present manifests; this alone does not prove those manifests were modified. Hooks fail open and record a rate-limited `bootstrap-runtime` diagnostic when possible, so a quiet hook does not establish a healthy installation.
41
+
42
+ Check the registered marketplace source first. An unbuilt Git checkout contains manifests and launchers but no generated runtime. The missing files alone cannot distinguish an unbuilt source from an incomplete cache copy.
43
+
44
+ 1. In ZCode's marketplace settings, replace the source with `njugray/cmdr#marketplace` (available after the maintainer publishes that branch). This source includes the runtime.
45
+ 2. Refresh/reinstall cmdr. Reinstalling from the same unbuilt source will reproduce the failure. For offline/local installation, use the complete installed npm package root or a built checkout.
46
+ 3. Run `cmdr doctor --plugin-root /actual/zcode/cache/plugin --deep` against the resulting cache. Resolve static installation failures before expecting a successful deep probe.
47
+ 4. Start a fresh ZCode session and confirm the cmdr tools appear. Do not link another installation's `dist/` into the cache or restart an unrelated shared daemon to repair missing plugin files.
48
+
49
+ The repository's `npm run verify:zcode` exercises installation from an npm tarball in temporary storage, checks cache integrity, and verifies seven MCP tools after removing the source directory. It does not inspect or repair an existing user's cache.
50
+
38
51
  ## Member CLI fallback
39
52
 
40
53
  `cmdr session` provides the seven member operations using the same schemas, role checks and reply routing as MCP. It requires an actual stable native ID; never invent one to impersonate a different session. For CLI-only use, the operator may deliberately assign and consistently reuse a unique ID for that independent member.
@@ -48,7 +61,7 @@ cmdr session report --agent zcode --native-id YOUR_SESSION_ID --status done --re
48
61
  cmdr session leave --agent zcode --native-id YOUR_SESSION_ID
49
62
  ```
50
63
 
51
- The first joiner is commander; report/ask require an executor. The commander uses:
64
+ Named joins default to executor; report/ask require that role. Explicitly claim command with `join --role commander --squad-name my-project`. The commander uses:
52
65
 
53
66
  ```sh
54
67
  cmdr session list --agent zcode --native-id COMMANDER_ID
@@ -60,4 +73,16 @@ cmdr session send --agent zcode --native-id COMMANDER_ID --to MEMBER_SID --type
60
73
 
61
74
  Every command writes a JSON result, or a JSON error on stderr with a nonzero exit code. `--timeout` bounds the operation (default wait+10 seconds, maximum 3600 seconds); SIGINT/SIGTERM cancel it. A cancelled waiting read does not consume later arrivals. A cancelled ask may already have been sent: requests are never automatically replayed, and a lost response is not proof that the mutation failed. Inspect history before manually retrying.
62
75
 
63
- Short-lived commands are online only while connected. They do not leave squads on exit, keep a background process alive, wake a model, or claim task success when reading a message. Existing operator `cmdr send/read/list` commands retain their previous meaning. This CLI fallback still requires an intact runtime; it cannot compensate for all bundles being missing.
76
+ Short-lived commands display cli and retain task ownership after exit. They do not leave channels or imply success on read. Enable daemon-managed standby separately or through join --standby auto; unsupported hosts remain manual. Existing operator `cmdr send/read/list` commands retain their previous meaning. This CLI fallback still requires an intact runtime; it cannot compensate for all bundles being missing.
77
+
78
+
79
+ ## Long-running collaboration diagnostics
80
+
81
+ - Use `list` to inspect `commands`, `unacked_for` (seconds since dispatch until acceptance), `last_progress_at`, `hook_seen_at` and listener health. Do not reassign based on presence alone. Even list --full omits command bodies; use your own read --id or operator tail --full for those.
82
+ - Use `read --recover` for unfinished work and `read --id MESSAGE_ID` for a non-consuming full lookup. `--full` restores the expanded squad summary. Consuming read output should not be piped to head.
83
+ - `standby status --session SID` exposes the current wake ID and requested/accepted/observed/uncertain state. `stalled` means host acceptance did not produce progress. Check the host before `standby resume --session SID --resolve retry` (explicitly permits a new request) or `--resolve accepted` (retain the existing request). A missing lookup result is not proof that an earlier request failed. A queued submission with host_state=unknown remains unhealthy until runtime state can be verified; host queue acceptance alone does not prove that the listener can run a turn.
84
+ - `tail --follow --after EVENT_SEQ --for SID --json --full` replays and follows lifecycle events without reading work. `retention.gap` means the cursor predates retained events. Start a new cursor with `--after 0` only after checking CMDR_HOME if CURSOR_AHEAD is reported.
85
+ - `UPGRADE_REQUIRED` leaves the old daemon running. Run `cmdr daemon restart` from the new intact installation; it first validates a consistent database copy. If preflight fails, the old daemon is not stopped. `doctor` includes connected client versions; update old caches before reconnecting them. The 0.2 daemon rejects pre-0.2.0 clients with PROTOCOL_MISMATCH and a plugin-cache update hint, even when their wire protocol number matches.
86
+ - Missing runtime or Node now produces one stderr line from the fail-open hook wrapper as well as the bounded diagnostic snapshot.
87
+
88
+ See [long-running collaboration](long-running-collaboration.md) for adapter requirements and recovery examples.
package/marketplace.json CHANGED
@@ -4,7 +4,7 @@
4
4
  {
5
5
  "name": "cmdr",
6
6
  "source": "./plugins/cmdr",
7
- "version": "0.1.1",
7
+ "version": "0.2.0",
8
8
  "description": "Local multi-agent squads with durable messages, roles and lifecycle reminders."
9
9
  }
10
10
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdr-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "Local multi-agent squads for Claude Code, Codex, ZCode and any MCP host",
6
6
  "engines": {
@@ -13,6 +13,7 @@
13
13
  "check": "npm run format:check && npm run typecheck && npm run build && npm test && npm run verify:package",
14
14
  "format": "prettier --write src tests scripts plugins/cmdr/bin/*.mjs package.json tsconfig.json .prettierrc.json vitest.config.ts",
15
15
  "format:check": "prettier --check src tests scripts plugins/cmdr/bin/*.mjs package.json tsconfig.json .prettierrc.json vitest.config.ts",
16
+ "prepare:marketplace": "node scripts/prepare-marketplace.mjs",
16
17
  "verify:zcode": "node scripts/verify-zcode.mjs",
17
18
  "prepack": "npm run build",
18
19
  "verify:package": "node scripts/verify-package.mjs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdr",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Local multi-agent squads with durable messages, roles and lifecycle reminders.",
5
5
  "author": {
6
6
  "name": "njugray"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdr",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Local multi-agent squads with durable messages, roles and lifecycle reminders.",
5
5
  "author": {
6
6
  "name": "njugray"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdr",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Local multi-agent squads with durable messages, roles and lifecycle reminders.",
5
5
  "author": {
6
6
  "name": "njugray"