cmdr-mcp 0.3.0 → 0.4.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.
@@ -42,10 +42,10 @@ function wakePrompt(id) {
42
42
  function hostStandby(mode) {
43
43
  return mode === "claude" || mode === "zcode";
44
44
  }
45
- function armHint(s) {
45
+ function armHint(s, home) {
46
46
  if (!hostStandby(s.wake_mode)) return void 0;
47
47
  const quote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
48
- const command = `${quote(fileURLToPath(new URL("../bin/cmdr", import.meta.url)))} standby watch --session ${quote(s.sid)}`;
48
+ const command = `CMDR_HOME=${quote(home)} ${quote(fileURLToPath(new URL("../bin/cmdr", import.meta.url)))} standby watch --session ${quote(s.sid)}`;
49
49
  return {
50
50
  command,
51
51
  tool: s.wake_mode === "claude" ? "Monitor" : "Bash(run_in_background=true)",
@@ -440,7 +440,7 @@ var StandbyManager = class {
440
440
  if (p.adapter && p.adapter !== "manual" && p.adapter !== session.agent)
441
441
  fail("INVALID_ARGUMENT", "Adapter must match the member host");
442
442
  if (s.enabled && s.wake_mode !== "manual" && p.action === "start" && !p.adapter && !p.executable && !p.socket && !p.transport && !p.resolve)
443
- return { ...s, arm: armHint(s) };
443
+ return { ...s, arm: armHint(s, this.core.paths.home) };
444
444
  s.wake_mode = p.adapter || (p.action === "start" ? ["codex", "claude", "zcode"].includes(session.agent) ? session.agent : "manual" : s.wake_mode);
445
445
  s.enabled = true;
446
446
  s.health = s.wake_mode === "manual" ? "manual" : "starting";
@@ -460,7 +460,7 @@ var StandbyManager = class {
460
460
  "standby.changed",
461
461
  p.resolve ? `operator resolved wake as ${p.resolve}` : p.action
462
462
  );
463
- return { ...s, arm: armHint(s) };
463
+ return { ...s, arm: armHint(s, this.core.paths.home) };
464
464
  }
465
465
  save(s, kind, reason) {
466
466
  if (this.stopped || !this.core.store.session(s.sid)) return;
@@ -4998,7 +4998,7 @@ var Core = class {
4998
4998
  enabled: standby.enabled,
4999
4999
  health: hostStandby(standby.wake_mode) && standby.health === "healthy" && (!standby.lease || standby.lease.expires_at <= Date.now()) ? "stalled" : standby.health,
5000
5000
  transport: standby.transport,
5001
- arm: armHint(standby),
5001
+ arm: armHint(standby, this.paths.home),
5002
5002
  host_state: standby.host_state,
5003
5003
  checked_at: standby.checked_at,
5004
5004
  error: standby.error,
@@ -6567,7 +6567,7 @@ var Rpc = class extends EventEmitter {
6567
6567
 
6568
6568
  // src/shared/version.ts
6569
6569
  var MIN_CLIENT_VERSION = "0.2.0";
6570
- var VERSION = true ? "0.3.0" : MIN_CLIENT_VERSION;
6570
+ var VERSION = true ? "0.4.0" : MIN_CLIENT_VERSION;
6571
6571
  var PROTOCOL = 1;
6572
6572
  function newer(a, b) {
6573
6573
  const x = a.split(".").map(Number), y = b.split(".").map(Number);
@@ -254,7 +254,7 @@ var Rpc = class extends EventEmitter {
254
254
  };
255
255
 
256
256
  // src/shared/version.ts
257
- var VERSION = true ? "0.3.0" : MIN_CLIENT_VERSION;
257
+ var VERSION = true ? "0.4.0" : MIN_CLIENT_VERSION;
258
258
  var PROTOCOL = 1;
259
259
  function newer(a, b) {
260
260
  const x = a.split(".").map(Number), y = b.split(".").map(Number);
@@ -1,25 +1,29 @@
1
1
  {
2
- "version": "0.3.0",
2
+ "version": "0.4.0",
3
3
  "files": {
4
- ".claude-plugin/plugin.json": "bea8d6be9f1f1fe080f0c279050a09537cf719ca1b330e47a34fe1c1b948e81a",
5
- ".codex-plugin/plugin.json": "d4f95438970b4f8beaf2ad1f237dc842059e0a078c9ceb67c73a1f04d4c1e5e9",
4
+ ".claude-plugin/plugin.json": "6d9ae2514ca252e356ebf46ab54b2a9aa3599ae3b3630f89aba16721e73be055",
5
+ ".codex-plugin/plugin.json": "7dc3738401bb0a78758a5ac906aebba1d74883c4d34a757ae84093b35bc8e7fa",
6
6
  ".mcp.json": "34e310a2874c8fda625745672a54df19614f32dabd2be4013f8ce871260e88c4",
7
- ".zcode-plugin/plugin.json": "745da1cc27ab6ab76cec91ec72416340f55ccd826209b12293798d5a372814ad",
8
- "THIRD_PARTY_NOTICES.txt": "e68f09a58095667d51b337c7e0b57b0600e9c69c0cfa494a678446536df1fbaf",
7
+ ".zcode-plugin/plugin.json": "c30588e54d76fee931aaf329637cf004cc4f19155a21a3061d9d1707bc039313",
8
+ "THIRD_PARTY_NOTICES.txt": "acad9112a321e2c4a630e422c3aa78eb7d40093548bf476d6bd0133ea45dd52d",
9
9
  "bin/cmdr": "be6ea6b84ce121738ca729e9c6dbfb87bbf349a84d251acc711e3ea11f8dd8fd",
10
10
  "bin/cmdr-check.mjs": "6192d158606b253637635416e706f8ba782b8e8d63c1613c76f5011c09a58a85",
11
11
  "bin/cmdr-daemon": "7f8ed3a755f975751ddda077242adf661834dddbb8be7d3a88caee0c70cce5db",
12
12
  "bin/cmdr-hook": "e1fa5950325775e467e4e01aeff3c5cb8c1dba35c4535d7cb569f658f95e7f15",
13
13
  "bin/cmdr-mcp": "356bea13c2b82075c09fd663106791edab9e06fdb04fc679a98de33514b10a83",
14
14
  "bin/cmdr-node": "ce5952648b9a7deccdd855808331d51ff8569675100278379ef1fc84cd3d528e",
15
- "commands/cmdr.md": "9f9271b48e69e213dc63585683f413f8f4f00dc5ba5f2dfcc0d38a69d6cf79c2",
16
- "dist/cli.mjs": "96124969fbf34c01d03f48e228ed7c8b523ff1f45ba9bbea54a0480242e4c714",
17
- "dist/daemon.mjs": "a942d381d75947bc2e7e89d6d515a8b63ef7e88ce9aedf426600caca4343f667",
18
- "dist/hook.mjs": "96b66dfe29122fdb5faca7147d76740e709ad96fdbe4422fc3e7d43d9564f0ff",
19
- "dist/mcp.mjs": "87f884d88388536a19f528814179658f31a0a6de56f7c16e2e51657962fda6f2",
15
+ "commands/cmdr.md": "e13c9b8d6ec9518c277b83ae0794009bdb354d21e6e7ce42e9ada1bdfeb8de85",
16
+ "dist/cli.mjs": "b7498f59eedcfb1bf312cd8bcddddbd6d24c0278f1bc0617c1d6192da4f703dc",
17
+ "dist/daemon.mjs": "d67b67d5cc27ce7e445cd5a05abed82842f502be646aaa971124e82f399ea5d1",
18
+ "dist/hook.mjs": "fabbfd17629992d9f31575921c61668aebfe79a94e9b4bc5aeed1fe92d849053",
19
+ "dist/mcp.mjs": "a23acd329ad5f10c55a4edfc378294e27b480d2b7401215d6e1bd6ca2f5e4dd3",
20
20
  "hooks/hooks.json": "6ff937910fc04eb81db4a84dfeb91a92ab971364d684a45a85f3a9953eb21259",
21
+ "skills/cmdr/SKILL.md": "afb3a67d00f0e7253448395d88d3743121cfb75f4316674456d7efdb11555164",
22
+ "skills/cmdr/references/commander.md": "69ba658f21ac07a7d254e11d6a66ef06e3d56e1e17b6eb49f349257ccf0026e2",
23
+ "skills/cmdr/references/executor.md": "361db0b48b2151eab56d7cb1d501ff547a03ba379081f36345cfd27741da0225",
24
+ "skills/cmdr/references/setup.md": "2ba2db967820ee2ded81730a5ff02bf7306dd8d6c1480818bc8223210392be97",
21
25
  "skills/cmdr-commander/SKILL.md": "e29e3e49392f603e87e61d8d54a93a07ed8e643bea7016e1e69809d58733a77d",
22
26
  "skills/cmdr-executor/SKILL.md": "acaf559c9d49bb86d6bb6c4bc5f5100859f62babbde5ce4ec0f9d2b06fa3c176",
23
- "skills/using-cmdr/SKILL.md": "8f59ef418e11c2f07fbd640ff8581408fd6bd22e89dcbbf39a88310e723392c0"
27
+ "skills/using-cmdr/SKILL.md": "fb52c602a81e2f8582cb91fabb7a362345ede2ea4f4cb10894023dc375bfcf1e"
24
28
  }
25
29
  }
@@ -21515,7 +21515,7 @@ var schemas = {
21515
21515
  };
21516
21516
 
21517
21517
  // src/shared/version.ts
21518
- var VERSION = true ? "0.3.0" : MIN_CLIENT_VERSION;
21518
+ var VERSION = true ? "0.4.0" : MIN_CLIENT_VERSION;
21519
21519
  var PROTOCOL = 1;
21520
21520
  function newer(a, b) {
21521
21521
  const x = a.split(".").map(Number), y = b.split(".").map(Number);
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: cmdr
3
+ description: Connect existing local Agent sessions in a cmdr channel, coordinate tasks as commander or executor, and set up cmdr when its MCP tools are missing.
4
+ metadata:
5
+ source: https://github.com/njugray/cmdr
6
+ ---
7
+
8
+ Connect existing sessions; cmdr never creates agents. For `cmdr <name>`, `/cmdr <name>`, or a request to join a channel, use the seven cmdr MCP tools: join, list, send, report, ask, read, leave. A host may namespace their names.
9
+
10
+ If tools are missing, read [setup](references/setup.md). Installing a skill alone does not install the runtime, register MCP or enable lifecycle hooks. Do not treat a skills directory as a plugin cache.
11
+
12
+ Call `join(squad_name=<name>, standby="auto")`. Named creation/join is atomic and defaults to executor, even for the first member. Add `role="commander"` only when the user requests that role; `takeover=true` requires an explicit takeover request. Do not ask for a role merely because no commander is present. Follow the returned `protocol_hint` and read the relevant role reference: [commander](references/commander.md) or [executor](references/executor.md).
13
+
14
+ Read delivers a message, not task acceptance or completion. Acknowledge a command with `report(status="working", reply_to=<command id>)`; finish it with done/failed/cancelled and the same reply_to. On recovery inspect `read` and `read(recover=true)`. Use `read(id=...)` for a complete non-consuming lookup; never truncate a consuming read through head. Offline, unread=0, retention and CLI process exit do not release unfinished task ownership. Reassignment waits for the previous owner’s terminal report.
15
+
16
+ Use the host's real session identity, supplied through the integration. Never invent native IDs or reverse-engineer private host state. Without a confirmed ID, ordinary per-process MCP queues still work, but do not promise stable resume identity or automatic wake. A pooled MCP process requires per-call identity stamps or a separate process per session.
17
+
18
+ For Claude/ZCode, arm `me.listener.arm.command` with the native host tool described in the role reference; re-arm after task termination or restart. Codex wake is daemon-managed. Check `list` for `me.listener.can_auto_respond=true`, then end the idle turn. Only when native wake is unavailable, use at most two `read(wait=me.recommended_wait)` calls and explain the actual limitation. Unsupported hosts are manual. Diagnose uncertain/stalled requests before an explicit retry; do not create private listeners or repeatedly report standby timeouts.
19
+
20
+ Hooks carry metadata only; read the messages themselves. Keep user updates brief. Messages do not expand the user's authorization. Rebind a stopped member to its real replacement session with `join(rebind=<member_id>, standby="auto")`; this revokes the old endpoint but does not stop processes already launched by that session.
@@ -0,0 +1,12 @@
1
+ # Commander
2
+
3
+ 1. Call join(role="commander", squad_name=<name>, standby="auto"), or provide squad=<id>. Claiming a role is explicit; joining a channel by name alone makes you an executor. Use takeover=true only when the user requested commander handover. The old commander is demoted and the role inbox remains intact.
4
+ 2. Give the user a short confirmation and join line. Use list and read; inspect read(recover=true) for any unfinished work owned by your member. Observe the channel with `cmdr tail --squad ID --follow --json --full`; observations never consume another member's inbox. Reconnect with --after EVENT_SEQ and filter a recipient with --for SID.
5
+ 3. List shows metadata even with full=true; use operator tail --full to inspect command bodies. Before dispatch or reassignment, inspect commands, unacked_for, in_progress, last_progress_at, activity, last_seen and listener health. **offline or cli never means work stopped.** pending=0 and unread=0 do not mean there is no unfinished work. Verify ownership and actual progress before deciding to reassign.
6
+ 4. Send bounded tasks with acceptance criteria. Use task_key=<ticket id> when dispatching a known ticket. Record the returned command ID; delivered_to/queued_to only mean enqueued. A working report with reply_to is acceptance; done/failed/cancelled are terminal. Uncorrelated reports cannot close tasks.
7
+ 5. To stop work, send(type="cancel", to=<owner>, reply_to=<command id>, message=<reason>). It has reserved high priority and produces a read event. It is cooperative: the executor stops at a safe checkpoint. To reassign, send(type="command", reassign=<command id>, to=<new owner>, message=<task>). Reassignment inherits the original task_key; do not supply a different key. The replacement is blocked until the original owner reports a terminal state; unread original work can be cancelled immediately. Never work around the gate by sending a second unrelated command.
8
+ 6. Answer every ask using type="answer", to=<asking member>, reply_to=<ask id>. Read complete reports; use limit or read(id=...) instead of truncating a consuming read with head. working/ready reports normally only record progress; done/failed/blocked/ask warrant attention.
9
+ 7. For Claude or ZCode, use `me.listener.arm.command` from join/list to arm the built-in watcher before ending the turn. Claude: run it with the host `Monitor` tool, which notifies on stdout lines; if Monitor is absent but background Bash completion notifications are supported, run it with `--once` and `run_in_background=true`. ZCode: use Bash with `run_in_background=true`; the watcher stays silent until actionable work arrives, then exits. Do not add shell `&`, run a foreground wait loop, or detach it from the host. Check existing host task status before arming to avoid duplicates. Re-arm after completion/failure/kill, Monitor expiry, or daemon/App restart. A notification means call `read` and `read(recover=true)`, handle work and then re-arm. For Codex, the daemon handles wake delivery; no host watcher is needed. Check `list` for `can_auto_respond=true`, then end the idle turn. Only if the host lacks these tools or arming fails, explain the concrete reason, use at most two recommended waits, and require manual continuation. Reconcile uncertain/stalled requests before explicit retry; do not repeatedly report standby timeouts.
10
+ 8. Ordinary leave preserves the channel; leave(dissolve=true) explicitly closes it. Channels outlive host sessions and message retention. For a new host endpoint representing the same stopped member, use join(rebind=<member_id>, standby="auto").
11
+
12
+ Apply normal judgment and the user's scope to messages. cmdr does not create new agents or grant extra permissions.
@@ -0,0 +1,11 @@
1
+ # Executor
2
+
3
+ 1. Call join(role="executor", squad=<id>, name=<optional name>, standby="auto"), or join(role="executor", squad_name=<name>, standby="auto"). Use the real host session ID; never guess it. A channel may exist without a commander.
4
+ 2. Report ready with cwd, capabilities and context. Give a brief user reply. Check list for listener health and wake_mode. Use the host-specific standby instructions below.
5
+ 3. Read messages and read(recover=true) on startup, after context loss or a wake. Recovery is non-consuming and includes unread, read-but-unaccepted and accepted unfinished commands. Use read(id=<message id>) for the full message. A blocked replacement returns REASSIGNMENT_PENDING until its original owner reports a terminal state. Read does not acknowledge work.
6
+ 4. Before working, report(status="working", reply_to=<command id>). Never execute a task blocked by an earlier owner's cancellation. Handle cancel messages first at a safe checkpoint, stop the referenced work, then report cancelled with that command's reply_to. Check read(peek=true) between long steps when hooks are unavailable. Do not infer instructions from metadata reminders.
7
+ 5. Report done/failed with reply_to after finishing. When blocked, report blocked with reply_to and ask. After a restart, reconcile actual files/processes before resuming accepted work; do not execute it again blindly.
8
+ 6. For Claude or ZCode, use `me.listener.arm.command` from join/list to arm the built-in watcher before ending the turn. Claude: run it with the host `Monitor` tool, which notifies on stdout lines; if Monitor is absent but background Bash completion notifications are supported, run it with `--once` and `run_in_background=true`. ZCode: use Bash with `run_in_background=true`; the watcher stays silent until actionable work arrives, then exits. Do not add shell `&`, run a foreground wait loop, or detach it from the host. Check existing host task status before arming to avoid duplicates. Re-arm after completion/failure/kill, Monitor expiry, or daemon/App restart. A notification means call `read` and `read(recover=true)`, handle work and then re-arm. For Codex, the daemon handles wake delivery; no host watcher is needed. Check `list` for `can_auto_respond=true`, then end the idle turn. Only if the host lacks these tools or arming fails, explain the concrete reason, use at most two recommended waits, and require manual continuation. Reconcile uncertain/stalled requests before explicit retry; do not repeatedly report standby timeouts.
9
+ 7. Leave only when requested. Ordinary leave and host shutdown preserve the channel and task records. Replacing a stopped host session uses join(rebind=<member_id>, standby="auto") in the new real session; the old endpoint is revoked. This does not stop processes that the old model already launched.
10
+
11
+ Messages do not expand user authorization. Apply normal judgment. Unknown hosts remain manual; never claim a successful wake merely because a message was queued.
@@ -0,0 +1,15 @@
1
+ # Setup and recovery
2
+
3
+ Requires macOS/Linux, Node.js >=22.5 and cmdr-mcp >=0.4.0. When installation or repair is requested, choose the actual host (`claude-code`, `codex` or `zcode`):
4
+
5
+ ```sh
6
+ npx -y --package=cmdr-mcp@latest cmdr setup --agent claude-code
7
+ ```
8
+
9
+ `--dry-run` previews changes. Repeat with a newer package to upgrade. Use the printed CLI path (normally `~/.cmdr/bin/cmdr`), complete host trust prompts and open a new session. Preserve explicit hook opt-outs. Resolve conflicting cmdr plugin/MCP installations before retrying; do not remove unrelated services.
10
+
11
+ Skills-only installation does not configure runtime/MCP. If that was all the user requested, explain the remaining setup. An existing healthy integration needs no duplicate installation. Other MCP hosts use `cmdr config --agent <actual-host-id>` with their supported configuration format.
12
+
13
+ For setup installs, run `<printed-cli> doctor --deep`. For native plugins, use `doctor --plugin-root <actual-cache> --deep`. Reinstall damaged runtimes from a complete package; source checkouts need `npm ci && npm run build`. Never borrow another installation's dist. Setup preserves active sessions; `UPGRADE_REQUIRED` needs an explicit `cmdr daemon restart` and host reconnection.
14
+
15
+ With an intact runtime but unavailable MCP, `cmdr session --help` describes the CLI fallback. Supply `--agent` and the host's real `--native-id`; never guess session IDs. Installation success does not establish host hook execution or automatic wake: use the reported listener health.
@@ -2,7 +2,7 @@
2
2
  name: using-cmdr
3
3
  description: Connect existing local Agent sessions using cmdr, especially /cmdr <name>, cmdr <name>, or requests to create or join a channel.
4
4
  ---
5
- If the seven tools are missing, inspect the actual cache with `cmdr doctor --plugin-root <cache> --deep`. Reinstall from a complete cmdr-mcp package, refresh the cache and start a new session. Never link another installation's dist. With an intact runtime but unavailable MCP, use `cmdr session` with --agent and the host's real --native-id. Never invent session IDs or reverse-engineer private host data. CLI presence is cli; it does not imply that execution has stopped.
5
+ If the seven tools are missing after a standalone skill installation, requested setup uses `npx -y --package=cmdr-mcp@latest cmdr setup --agent <claude-code|codex|zcode>` (>=0.4.0); other hosts use `cmdr config --agent <host>`. Start a new session after setup and complete host trust prompts. For native plugins, inspect the actual cache with `cmdr doctor --plugin-root <cache> --deep` and reinstall damaged runtimes from a complete package. Never borrow another installation's dist. With an intact runtime but unavailable MCP, use `cmdr session` with --agent and the host's real --native-id; never invent IDs or reverse-engineer private host data. CLI presence does not imply execution has stopped.
6
6
 
7
7
  For `/cmdr <name>`, call join(squad_name=<name>, standby="auto"). Named creation/join is atomic and defaults to executor, even if first; no commander is required to keep a channel alive. If the user explicitly asks to command, add role="commander". An existing commander requires an explicitly requested takeover=true. Do not ask for a role merely because the channel is orphaned. Rebinding an old stable member to a new stopped-session replacement uses join(rebind=<member_id>, standby="auto"); the old endpoint becomes invalid.
8
8