cmdr-mcp 0.1.1 → 0.3.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.3.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")`. Claude/ZCode then arm `listener.arm.command` with its indicated native tool. 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
+ Codex wakes through app-server proxy or the `codex queue` fallback. Claude uses Monitor and ZCode uses background Bash completion through the built-in `cmdr standby watch`; re-arm after task termination. 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
 
@@ -157,6 +160,6 @@ npm run verify:zcode # optional: requires the locally installed ZCode desktop
157
160
 
158
161
  For development, `claude --plugin-dir ./plugins/cmdr` loads the plugin directly. Installed hosts use cached copies: reinstall/refresh after changing a plugin. Version numbers come from `package.json`; after same-version changes, restart the daemon explicitly. Generated bundles and third-party license notices are ignored by Git and included in the npm package.
159
162
 
160
- v1 is single-machine, single-user, Unix-socket-only. There is no network listener, remote transport, automatic Agent launching or executor-to-executor messaging. Host GUI interaction and live model behavior are distinct from the automated runtime checks; see the [verification record](docs/implementation.md).
163
+ v1 is single-machine, single-user, Unix-socket-only. There is no network listener, remote transport or executor-to-executor messaging. Agent session creation is outside the current scope. Host GUI interaction and live model behavior are distinct from the automated runtime checks; see the [verification record](docs/implementation.md).
161
164
 
162
165
  [MIT](LICENSE)
@@ -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"`,再按 `listener.arm` 和 `list` 的健康状态操作。Codex 由 daemon 自动探测 proxy,并在不可用时尝试 `codex queue`;Claude 使用原生 Monitor,ZCode 使用 `run_in_background=true` 的后台 Bash,两者都运行内置 `cmdr standby watch`。宿主 watcher 真正挂载后才显示 `can_auto_respond=true`,此时可结束空闲回合;任务完成、失败、到期或宿主重启后重新挂载。只有不支持原生通知或挂载失败时,才退回两次有限轮询并说明需人工续接。完整操作与边界见[长期协作](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. Claude/ZCode first arm listener.arm.command with the indicated native tool. With a healthy
39
+ listener, end the idle turn; when native wake is unavailable 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,8 @@ 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.
81
+
82
+ ## Automatic wake
83
+
84
+ Codex supports proxy and queue compatibility paths. Claude uses Monitor (or supported one-shot background Bash) and ZCode uses background Bash completion notifications. Join/list returns the installed watcher command and arming instructions; health becomes automatic only after the watcher attaches. Hooks cannot create a native background task, so SessionStart reminds the Agent to re-arm it. Unknown MCP hosts remain manual. See [automatic standby](long-running-collaboration.md#automatic-standby).
@@ -1,5 +1,7 @@
1
1
  # cmdr 设计方案(v1)
2
2
 
3
+ > 历史设计存档。本轮自动唤醒以[长期协作](long-running-collaboration.md#automatic-standby)和[实现记录](implementation.md)为准:已移除禁止主动唤醒、所有非 Codex 宿主一律 manual、要求模型循环待命 40 轮等旧限制;新建 Agent 会话不在本轮范围内。下文的原型记录不代表当前实现。
4
+
3
5
  > **cmdr**(Commander):让同一台机器上的多个 Claude Code / Codex 会话组成"小队",通过 MCP 工具互相通信。指挥官下发命令、回答询问,执行方报到、汇报、询问;服务端为每个会话维护一个带优先级的消息队列,并通过 hooks 在合适的时机提醒 Agent 读取。
4
6
  >
5
7
  > **当前实现状态(2026-09-08)**:本仓库已从仅含文档的分支实现 v1 源码、插件与测试,并按新增需求支持 ZCode 桌面端和任意 MCP Agent 接入。本文保留既有设计及原型试用记录;其中历史 v0.1.x 的完成日期、版本号与实测结论不是本次代码的验证凭据。本次具体交付、差异、38 个自动化用例和 ZCode 本机运行时验证见 [实现与验证记录](implementation.md),新增宿主契约见 [Agent 接入指南](agent-integration.md)。
@@ -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.3.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,49 @@ 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. Codex uses proxy/queue and Claude/ZCode use native notification watchers. 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. That 0.2.0 proxy-only implementation did not parse private host state; the queue compatibility path below intentionally replaces that restriction. 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.
90
+
91
+ ## 0.3.0 automatic wake iteration — issues #7, #8 and #9
92
+
93
+ This iteration is isolated on `feat/host-auto-wake`, based directly on `main` (`5368e52`). Standalone setup/skills installation remains on its separate branch. The reported host mechanisms are implemented as follows:
94
+
95
+ - [#7 Codex queue feedback](https://github.com/njugray/cmdr/issues/7): the previous proxy-only assumption is removed. Auto mode checks the existing proxy, then queue capability. Its read-only state_5/rollout compatibility reader is explicitly version-coupled, scans complete records incrementally and prevents idle inference from partial writes. Delivery stays with the installed queue CLI. Pending requests pin their transport; actual user-message markers reconcile lost responses after restart. Node >=22.12 is required for the fallback's read-only SQLite option; earlier supported Node versions can still use proxy.
96
+ - [#8 Claude Monitor feedback](https://github.com/njugray/cmdr/issues/8): native Monitor runs the built-in watcher. Actionable filtering is shared with adapters and tail. Follow defaults to now; explicit replay cursors remain available. Role-inbox events, direct info and current unfinished work are included; ready/working reports and quiet broadcast info are excluded.
97
+ - [#9 ZCode background completion feedback](https://github.com/njugray/cmdr/issues/9): native background Bash runs the same watcher in one-shot mode. It remains silent until actionable work, then exits and relies on the host's completion notification. Unlike the supplied consuming-read PoC, the shipped watcher observes metadata; the awakened Agent performs read/acceptance. It has a daemon lease, duplicate protection, startup snapshot, expiry and disconnect handling. Join/list/skills and SessionStart now tell the model to arm/re-arm; the previous blanket manual classification and ban on host-side listening are removed.
98
+
99
+ The [follow-up correction to #8](https://github.com/njugray/cmdr/issues/8#issuecomment-5712342765) identifies report filtering on omitted `data.status` as the cause of missed notifications in the original recipe, rather than a stalled subscription. The shared wake policy now uses the daemon-computed `attn` flag for reports. Default live events and replay both carry `data=null`; `--full` retains the original data. Regression coverage checks all six report statuses with and without data, matching live/replay output, and consecutive actionable reports on the same subscription. No periodic reconnect workaround is added.
100
+
101
+ The [PR #10 review](https://github.com/njugray/cmdr/pull/10#discussion_r4035173370) also identified repeated one-shot wakes when a blocked executor re-arms with an already accepted command. Attach now records accepted commands without pending cancellation as already seen. They remain owned and recoverable; unread messages, unaccepted work and pending cancellation still notify. Process regressions cover ZCode and Claude's one-shot fallback through blocked → re-arm → daemon restart → answer → cancellation, including unread answers at attach and cancellation whose message has already been read.
102
+
103
+ New ZCode session creation is deferred by user decision. The app-server prototype, `cmdr zcode create` / `admin.zcode.create` entry points, owned runtime state and dedicated tests have been removed. No CDP desktop adapter is included. Automatic wake for existing Codex, Claude and ZCode sessions remains. Seven public MCP tools, ownership/report semantics, cancellation and generic host IDs remain intact.
104
+
105
+ **Source-research correction (2026-09-17):** `ZCODE_STORAGE_DIR` does not isolate the session database; the removed prototype and the earlier verification script did not explicitly set `ZCODE_SESSION_DB_PATH`. Earlier descriptions of fully isolated owned storage were too broad. The retained plugin/MCP verification script now explicitly sets a temporary session database and checks that the runtime opened it. A persisted session can be discovered through shared storage when a fresh desktop workspace runtime seeds the task index, but visibility is not ownership transfer. Empty create/read/close does not prove persistence or cross-process recovery. See [ZCode desktop session visibility research](zcode-desktop-session-visibility.md) for source evidence, no-model experiments and the decision to defer creation.
106
+
107
+ **Desktop entry probe (2026-09-17):** an unmodified ZCode 3.11.2 release launched with an explicit loopback CDP endpoint and disposable desktop/runtime databases accepted external Node calls through its Renderer service proxy to the desktop Host's `createTask`. Two real IDs were returned; `listTasks` and `task_created` events reflected the creations, and the visible sidebar grew from one entry to two without a reload. Workspace runtime PID/generation remained unchanged. This is a verified, opt-in, version-coupled route, not a default public task API or an implemented cmdr desktop adapter. No model turn or cloud remote-control pairing was exercised.
108
+
109
+ Verification of the independent branch on 2026-09-17 (macOS, Node 24.16.0):
110
+
111
+ - `npm run check`: **106 tests passed across 12 files**, plus formatting, strict typing, build and offline package/seven-tool discovery. The standalone installation tests belong to the separate setup branch and are not included here.
112
+ - New tests cover proxy→queue selection, conservative busy/partial-record checks, stable request reconciliation, no duplicate submission across daemon restart, host watcher silence/duplicates/re-arming, non-consuming output, role-inbox filtering, manual registration upgrade and broadcast/direct info. The cold-start queue test waits for adapter readiness instead of relying on the test runner's default one-second polling deadline.
113
+ - `npm run verify:zcode`: the installed desktop runtime validated the plugin and cache, discovered 1 command / 3 skills / 4 hooks / 1 MCP server and connected seven tools after source removal. The runtime opened the explicitly configured temporary session database. The script does not create sessions or send model requests.
114
+ - The rebuilt CLI exposes the watcher, omits both standalone setup and new-session creation, and rejects `zcode create` without starting a daemon.
115
+ - Local Codex CLI 0.153.4 exposes queue --thread/--message. The issue's historical end-to-end queue success is retained as field evidence; this iteration did not re-submit into a user's real desktop thread. Claude Monitor and ZCode background-task re-invocation likewise have the issue authors' live PoC evidence; automated watcher tests do not claim a new live-model GUI verification.
116
+
117
+ Outstanding host acceptance is the real idle→notification→read→working→done loop in refreshed Codex, Claude and ZCode sessions, including a busy-turn backlog and watcher re-arm after native task expiry. Use a disposable channel/workspace and inspect tail/list for acceptance; tool/CLI availability alone is not the success criterion. No normal ~/.cmdr state, installed plugin cache or host trust settings were changed during verification.
118
+
119
+ Release preparation for 0.3.0 synchronizes npm and host manifests and injects the package version into Vitest, matching the production build so process tests validate the released version rather than the minimum compatible client version. The release is prepared from merged PR #10 in a clean worktree.
@@ -0,0 +1,138 @@
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
+ ## Automatic standby
57
+
58
+ `join(standby="auto")` requires a confirmed native identity and channel membership. Inspect `list` afterwards. A successful join registers intent; `can_auto_respond=true` requires a healthy delivery adapter or a live host watcher. Unknown hosts remain manual.
59
+
60
+ | Host | Wake mechanism | What the Agent must do |
61
+ | --- | --- | --- |
62
+ | Codex | Daemon attaches through app-server proxy; falls back to `codex queue` when proxy is unavailable | Join with auto, check health, end the idle turn |
63
+ | Claude Code | Native Monitor emits a notification for each watcher output line | Run `listener.arm.command` with Monitor; re-arm on expiry/exit |
64
+ | ZCode desktop | Native background Bash re-invokes its session when the watcher exits | Run `listener.arm.command` with `run_in_background=true`; re-arm after each notification |
65
+
66
+ All paths share the same actionable policy: command, cancel, ask, answer, system, terminal/blocked reports, attention-marked info and direct info. working/ready reports and broadcast info without attention are quiet. Commands gated by reassignment remain blocked. Observation does not consume messages or accept tasks. Every wake must be followed by `read` and `read(recover=true)`, cancellation handling, and correlated working/terminal reports.
67
+
68
+ Report attention comes from the daemon's `attn` flag, computed at enqueue time. Default live and replayed events both omit `message.data`; do not filter those events by `data.status`. Use the built-in `--actionable` filter. `--full` includes the original data when needed. A quiet long-lived subscription does not itself indicate a stalled connection; periodic reconnects are unnecessary.
69
+
70
+ ```sh
71
+ cmdr standby start --session SID
72
+ cmdr standby status --session SID
73
+ cmdr standby stop --session SID
74
+ cmdr standby resume --session SID
75
+ ```
76
+
77
+ ### Codex: proxy and queue
78
+
79
+ The proxy path connects `codex app-server proxy` to the already running host. It uses thread/read, thread/resume, thread/queue/list, thread/queue/add, thread/queue/start and thread/turns/list. A host that exposes these methods and the control socket can accept a stable client message ID and start that exact queued item. An unloaded thread is resumed in that same host. See the [official app-server reference](https://learn.chatgpt.com/docs/app-server) for the transport and state APIs; experimental queue shapes are checked against the installed CLI, not inferred from this reference.
80
+
81
+ A missing socket now triggers a capability check for `codex queue --thread ID --message TEXT`. The queue path submits a metadata-only wake to the existing thread, without model, sandbox, approval or remote overrides. It does not explicitly launch a second app-server or call exec/resume to create a competing session. The CLI's internal transport remains host-owned.
82
+
83
+ The compatibility state reader requires Node >=22.12 (Node 24 recommended), because earlier node:sqlite versions lack the readOnly option. It opens `$CODEX_HOME/state_5.sqlite` read-only, resolves the exact thread's rollout_path and incrementally reads complete JSONL records. task_started means busy; task_complete/turn_aborted means idle. It scans the whole existing log once rather than a fixed tail window. Missing records, incompatible schema and unknown state prevent submission and produce concrete errors. This is a version-coupled fallback, not a stable public state API. The check-to-submit race is not atomic; the queue CLI must arbitrate a concurrent user turn.
84
+
85
+ ```sh
86
+ # Automatic selection (default)
87
+ cmdr standby start --session codex:REAL_ID --transport auto
88
+ # Force a known path when diagnosing host capabilities
89
+ cmdr standby start --session codex:REAL_ID --transport queue --executable /absolute/path/to/codex
90
+ cmdr standby start --session codex:REAL_ID --transport proxy --socket /absolute/path/to/control.sock
91
+ ```
92
+
93
+ Wake requests are persisted before delivery: requested → accepted → observed. An unresolved request pins its transport across restarts. Proxy reconciliation searches queue/history by client ID; queue reconciliation recognizes the stable `[cmdr wake UUID]` prefix only in user messages in the rollout. Queue exit 0 confirms submission but provides no queued item ID. Timeout/nonzero exit is uncertain, since delivery may already have happened. No cross-transport or automatic blind replay occurs. Accepted wakes with no progress become stalled. After inspecting the host and actual work:
94
+
95
+ ```sh
96
+ cmdr standby resume --session SID --resolve accepted
97
+ cmdr standby resume --session SID --resolve retry
98
+ ```
99
+
100
+ `retry` explicitly permits a new submission; it does not establish that the earlier one failed. Busy sessions coalesce backlog. Host acceptance remains separate from the command owner's working report.
101
+
102
+ ### Claude and ZCode: native host watchers
103
+
104
+ Join/list returns `listener.arm` with an absolute installed command, the native host tool and re-arm instructions. The standard command is:
105
+
106
+ ```sh
107
+ cmdr standby watch --session claude:REAL_ID
108
+ cmdr standby watch --session zcode:REAL_ID
109
+ ```
110
+
111
+ Claude uses its **Monitor tool**, not foreground Bash or shell `&`. Each stdout line becomes a native notification, queued into an active turn or opening an idle turn. The reporter's Monitor has a 30-minute lifetime; re-arm when the host reports expiry/exit. If Monitor is absent but the host supports background Bash completion notifications, use `--once` with `run_in_background=true`. If neither mechanism exists, explicitly select manual.
112
+
113
+ ZCode uses **Bash with run_in_background=true**. Its native task survives the current turn and automatically re-invokes the session on completed/failed/killed. The built-in watcher remains silent during idle periods and exits after printing actionable metadata. It never consumes inbox messages, so a lost output notification still leaves the work available for recovery. On notification: inspect task output, read/recover, handle work, and re-arm. An immediate backlog produces an immediate notification; drain/reconcile it before re-arming.
114
+
115
+ The command subscribes before inspecting current work, covering startup races, unread messages and read-but-unaccepted commands. At attach, accepted commands without pending cancellation are treated as already known: a blocked executor can re-arm and wait for an answer without repeatedly waking on its own unfinished task. Ownership and `read(recover=true)` remain unchanged; reconcile accepted work on startup or after context loss before arming. Unread answers, new commands and pending cancellation still notify, including cancellation requested after attach.
116
+
117
+ It renews a 90-second daemon lease every 30 seconds. Exactly one lease owns a member; duplicate watchers are rejected. Only an attached live watcher is healthy. Disconnect removes its lease; a lost heartbeat expires it. A daemon restart closes the command so the host can notify and re-arm. App termination removes the native task; SessionStart reminds the Agent to inspect and re-arm it. A healthy lease establishes that the watcher is running, not that an individual model turn has already started.
118
+
119
+ Check the host task status before re-arming. Stop disables the lease; its process exits at the next event/heartbeat, which itself may produce one last native notification. Skills do not impose the old two-wait limit when a native watcher is available. Bounded manual polling remains only for unsupported tools or failed arming. No repeating cron/model heartbeat is needed, and no PermissionRequest auto-approval is installed.
120
+
121
+ ## Lifecycle observation
122
+
123
+ ```sh
124
+ cmdr tail --squad CHANNEL_ID --follow --json --full
125
+ cmdr tail --for MEMBER_SID --after 123 --follow --json --full
126
+ ```
127
+
128
+ 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.
129
+
130
+ Without --after, --follow starts at the current event cursor. `--after now` makes that explicit; non-follow tail still shows recent history. Use `--actionable --for SID --format line` for concise metadata-only wake lines, or --json for structured events. The built-in watcher additionally checks current/recoverable work and tracks health, so prefer it for native host notifications.
131
+
132
+ 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.
133
+
134
+ ## Upgrade and verification boundary
135
+
136
+ 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.
137
+
138
+ 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 model wake/report cycles 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.3.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.3.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.3.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.3.0.tgz --access public --registry https://registry.npmjs.org/
40
40
  ```
41
41
 
42
- 此命令会公开发布 `0.1.1` 并使用默认的 `latest` 标签。相同包名和版本不能重复发布;后续修改需要提升版本并重新构建验证。发布使用 tarball,以保持上传内容与已检查产物一致。
42
+ 此命令会公开发布 `0.3.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.3.0 name version dist.integrity --registry https://registry.npmjs.org/
48
+ npm install --global cmdr-mcp@0.3.0 --registry https://registry.npmjs.org/
49
49
  cmdr --help
50
50
  ```
51
51
 
52
- 按照 [安装说明](README.zh-CN.md#安装) 注册安装后的包根目录。已安装宿主有插件缓存,升级后需要刷新或重装;同版本测试代码变动需要重启对应测试 daemon。
52
+ 按照 [安装说明](README.zh-CN.md#安装) 注册安装后的包根目录。升级后刷新或重装宿主插件缓存,重启 MCP 连接,并使用新版本 CLI 执行 `cmdr daemon restart`;该命令先做一致性预检,再替换旧 daemon。随后重新检查监听状态,Claude/ZCode 按 `listener.arm` 重新挂载 watcher。不要仅替换 npm 包后继续使用旧缓存和旧 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 地址作为成品分发源。