cmdr-mcp 0.4.0 → 0.5.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.
Files changed (33) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +29 -6
  3. package/docs/README.zh-CN.md +29 -6
  4. package/docs/agent-integration.md +2 -2
  5. package/docs/dashboard-plan.md +327 -0
  6. package/docs/dashboard.md +101 -0
  7. package/docs/implementation.md +25 -4
  8. package/docs/publishing.md +10 -8
  9. package/docs/setup.md +1 -1
  10. package/docs/troubleshooting.md +2 -2
  11. package/marketplace.json +1 -1
  12. package/package.json +9 -1
  13. package/plugins/cmdr/.claude-plugin/plugin.json +1 -1
  14. package/plugins/cmdr/.codex-plugin/plugin.json +1 -1
  15. package/plugins/cmdr/.zcode-plugin/plugin.json +1 -1
  16. package/plugins/cmdr/README.md +3 -1
  17. package/plugins/cmdr/THIRD_PARTY_NOTICES.txt +130 -0
  18. package/plugins/cmdr/bin/cmdr-check.mjs +3 -0
  19. package/plugins/cmdr/commands/cmdr.md +2 -0
  20. package/plugins/cmdr/dist/cli.mjs +121 -31
  21. package/plugins/cmdr/dist/daemon.mjs +4729 -137
  22. package/plugins/cmdr/dist/dashboard/app.css +1 -0
  23. package/plugins/cmdr/dist/dashboard/app.js +10 -0
  24. package/plugins/cmdr/dist/dashboard/index.html +13 -0
  25. package/plugins/cmdr/dist/hook.mjs +2 -2
  26. package/plugins/cmdr/dist/integrity.json +20 -17
  27. package/plugins/cmdr/dist/mcp.mjs +140 -64
  28. package/plugins/cmdr/skills/cmdr/SKILL.md +3 -1
  29. package/plugins/cmdr/skills/cmdr/references/commander.md +2 -0
  30. package/plugins/cmdr/skills/cmdr/references/executor.md +2 -0
  31. package/plugins/cmdr/skills/cmdr-commander/SKILL.md +2 -0
  32. package/plugins/cmdr/skills/cmdr-executor/SKILL.md +2 -0
  33. package/plugins/cmdr/skills/using-cmdr/SKILL.md +2 -2
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>cmdr</title>
7
+ <link rel="stylesheet" href="/app.css" />
8
+ <script type="module" src="/app.js"></script>
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ </body>
13
+ </html>
@@ -85,7 +85,7 @@ function observedHook(event, agent) {
85
85
  import { existsSync } from "node:fs";
86
86
 
87
87
  // src/shared/env.ts
88
- var cmdrTool = /(?:^|[_:])cmdr(?:__|:)(list|join|report|leave|ask|send|read)$/;
88
+ var cmdrTool = /(?:^|[_:])cmdr(?:__|:)(list|join|report|leave|ask|send|read|task|artifact)$/;
89
89
  function detectAgent(env = process.env, hook) {
90
90
  if (env.CMDR_AGENT && /^[a-z][a-z0-9_-]{0,63}$/.test(env.CMDR_AGENT)) return env.CMDR_AGENT;
91
91
  if (env.ZCODE_PLUGIN_ROOT || env.ZCODE_PLUGIN_ID) return "zcode";
@@ -254,7 +254,7 @@ var Rpc = class extends EventEmitter {
254
254
  };
255
255
 
256
256
  // src/shared/version.ts
257
- var VERSION = true ? "0.4.0" : MIN_CLIENT_VERSION;
257
+ var VERSION = true ? "0.5.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,29 +1,32 @@
1
1
  {
2
- "version": "0.4.0",
2
+ "version": "0.5.0",
3
3
  "files": {
4
- ".claude-plugin/plugin.json": "6d9ae2514ca252e356ebf46ab54b2a9aa3599ae3b3630f89aba16721e73be055",
5
- ".codex-plugin/plugin.json": "7dc3738401bb0a78758a5ac906aebba1d74883c4d34a757ae84093b35bc8e7fa",
4
+ ".claude-plugin/plugin.json": "535aafc34ca6d592a4a9561c32f61a92935b21c8db404a9d9f4e76adb64deff2",
5
+ ".codex-plugin/plugin.json": "99a07fd4edeaa98a198c5ae3b3b4b7269971d18a0aefb42f1ec2dba6d407f038",
6
6
  ".mcp.json": "34e310a2874c8fda625745672a54df19614f32dabd2be4013f8ce871260e88c4",
7
- ".zcode-plugin/plugin.json": "c30588e54d76fee931aaf329637cf004cc4f19155a21a3061d9d1707bc039313",
8
- "THIRD_PARTY_NOTICES.txt": "acad9112a321e2c4a630e422c3aa78eb7d40093548bf476d6bd0133ea45dd52d",
7
+ ".zcode-plugin/plugin.json": "ab0d963f66c8a07c90377eb7a60e10ef468dc2f1534390cd258cc33b71c2c2e5",
8
+ "THIRD_PARTY_NOTICES.txt": "061121858596143e1ec0609aeee0d45ec839e53f05a4b7c23a48ec7df33194fc",
9
9
  "bin/cmdr": "be6ea6b84ce121738ca729e9c6dbfb87bbf349a84d251acc711e3ea11f8dd8fd",
10
- "bin/cmdr-check.mjs": "6192d158606b253637635416e706f8ba782b8e8d63c1613c76f5011c09a58a85",
10
+ "bin/cmdr-check.mjs": "0b991c7a705031dd9482c543f3b25b8a7f7dfe38d7363690eb21cfa80fae315f",
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": "e13c9b8d6ec9518c277b83ae0794009bdb354d21e6e7ce42e9ada1bdfeb8de85",
16
- "dist/cli.mjs": "b7498f59eedcfb1bf312cd8bcddddbd6d24c0278f1bc0617c1d6192da4f703dc",
17
- "dist/daemon.mjs": "d67b67d5cc27ce7e445cd5a05abed82842f502be646aaa971124e82f399ea5d1",
18
- "dist/hook.mjs": "fabbfd17629992d9f31575921c61668aebfe79a94e9b4bc5aeed1fe92d849053",
19
- "dist/mcp.mjs": "a23acd329ad5f10c55a4edfc378294e27b480d2b7401215d6e1bd6ca2f5e4dd3",
15
+ "commands/cmdr.md": "f63569564b7218fbaf873275548d648cf0cbc56b730b6993cbf63c48a176ae2d",
16
+ "dist/cli.mjs": "f2c359666be764591ec886b971aa92efb2418ce896067c302bccd8daf686ee5c",
17
+ "dist/daemon.mjs": "382de9c4ccd22fb54e2ec8ba528a622e8ef557f9ed46b15f1cebab6c8b3b28db",
18
+ "dist/dashboard/app.css": "58d74d9a98c39bef501a53f2530a99906d2fbb8ef5a619ff7a8ee432005d65d3",
19
+ "dist/dashboard/app.js": "c3549fce634931de741df6883e63e246969eedfedd8af4e81e7afe0687a10d1e",
20
+ "dist/dashboard/index.html": "670b1a05ca906b352ed5d8f53d2adc1a9ad5bb937e758a09ae200752f4e25356",
21
+ "dist/hook.mjs": "e7aba7f143ef390f58932491d8a4b973488abb8a970eb787ae2252eb08f86b3e",
22
+ "dist/mcp.mjs": "2f9935f3090f355f7bcd69d9eee7598c32e9cef0af6f60bd7c4081832a97ffe5",
20
23
  "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/SKILL.md": "40ae18c875eb7973c36b041e65976b150675f31375eef04271b21faeea2576aa",
25
+ "skills/cmdr/references/commander.md": "addc597a95a6314d07610915d831aa002833b80f82554269d9ba4895b659b65d",
26
+ "skills/cmdr/references/executor.md": "d52b315c2129fbd9e6dd31bd04e73b08bcdb9eb8d9dd3b47eccce62f65a63d6e",
24
27
  "skills/cmdr/references/setup.md": "2ba2db967820ee2ded81730a5ff02bf7306dd8d6c1480818bc8223210392be97",
25
- "skills/cmdr-commander/SKILL.md": "e29e3e49392f603e87e61d8d54a93a07ed8e643bea7016e1e69809d58733a77d",
26
- "skills/cmdr-executor/SKILL.md": "acaf559c9d49bb86d6bb6c4bc5f5100859f62babbde5ce4ec0f9d2b06fa3c176",
27
- "skills/using-cmdr/SKILL.md": "fb52c602a81e2f8582cb91fabb7a362345ede2ea4f4cb10894023dc375bfcf1e"
28
+ "skills/cmdr-commander/SKILL.md": "5475dbc603f2ddd2e28c1ad8bf2cdee790f751e5d1476d0f49c3dc0930093b2d",
29
+ "skills/cmdr-executor/SKILL.md": "d53b0da281bcc9e4919efdd943a7b18eaec8a3da35424ba8e38b8c2cb536643e",
30
+ "skills/using-cmdr/SKILL.md": "70156e942eab0656be3bc39f084bdb05c6d3182c73f86a6d32f9f1d6fb6ed174"
28
31
  }
29
32
  }
@@ -2232,10 +2232,10 @@ var require_resolve = __commonJS({
2232
2232
  }
2233
2233
  return count;
2234
2234
  }
2235
- function getFullPath(resolver, id = "", normalize) {
2235
+ function getFullPath(resolver, id2 = "", normalize) {
2236
2236
  if (normalize !== false)
2237
- id = normalizeId(id);
2238
- const p = resolver.parse(id);
2237
+ id2 = normalizeId(id2);
2238
+ const p = resolver.parse(id2);
2239
2239
  return _getFullPath(resolver, p);
2240
2240
  }
2241
2241
  exports.getFullPath = getFullPath;
@@ -2245,13 +2245,13 @@ var require_resolve = __commonJS({
2245
2245
  }
2246
2246
  exports._getFullPath = _getFullPath;
2247
2247
  var TRAILING_SLASH_HASH = /#\/?$/;
2248
- function normalizeId(id) {
2249
- return id ? id.replace(TRAILING_SLASH_HASH, "") : "";
2248
+ function normalizeId(id2) {
2249
+ return id2 ? id2.replace(TRAILING_SLASH_HASH, "") : "";
2250
2250
  }
2251
2251
  exports.normalizeId = normalizeId;
2252
- function resolveUrl(resolver, baseId, id) {
2253
- id = normalizeId(id);
2254
- return resolver.resolve(baseId, id);
2252
+ function resolveUrl(resolver, baseId, id2) {
2253
+ id2 = normalizeId(id2);
2254
+ return resolver.resolve(baseId, id2);
2255
2255
  }
2256
2256
  exports.resolveUrl = resolveUrl;
2257
2257
  var ANCHOR = /^[a-z_][-a-z0-9._]*$/i;
@@ -3021,8 +3021,8 @@ var require_compile = __commonJS({
3021
3021
  if (Object.keys(root.schema).length > 0 && refPath === baseId) {
3022
3022
  return getJsonPointer.call(this, p, root);
3023
3023
  }
3024
- const id = (0, resolve_1.normalizeId)(refPath);
3025
- const schOrRef = this.refs[id] || this.schemas[id];
3024
+ const id2 = (0, resolve_1.normalizeId)(refPath);
3025
+ const schOrRef = this.refs[id2] || this.schemas[id2];
3026
3026
  if (typeof schOrRef == "string") {
3027
3027
  const sch = resolveSchema.call(this, root, schOrRef);
3028
3028
  if (typeof (sch === null || sch === void 0 ? void 0 : sch.schema) !== "object")
@@ -3033,7 +3033,7 @@ var require_compile = __commonJS({
3033
3033
  return;
3034
3034
  if (!schOrRef.validate)
3035
3035
  compileSchema.call(this, schOrRef);
3036
- if (id === (0, resolve_1.normalizeId)(ref)) {
3036
+ if (id2 === (0, resolve_1.normalizeId)(ref)) {
3037
3037
  const { schema } = schOrRef;
3038
3038
  const { schemaId } = this.opts;
3039
3039
  const schId = schema[schemaId];
@@ -4459,15 +4459,15 @@ var require_core = __commonJS({
4459
4459
  this.addSchema(sch, void 0, _meta, _validateSchema);
4460
4460
  return this;
4461
4461
  }
4462
- let id;
4462
+ let id2;
4463
4463
  if (typeof schema === "object") {
4464
4464
  const { schemaId } = this.opts;
4465
- id = schema[schemaId];
4466
- if (id !== void 0 && typeof id != "string") {
4465
+ id2 = schema[schemaId];
4466
+ if (id2 !== void 0 && typeof id2 != "string") {
4467
4467
  throw new Error(`schema ${schemaId} must be string`);
4468
4468
  }
4469
4469
  }
4470
- key = (0, resolve_1.normalizeId)(key || id);
4470
+ key = (0, resolve_1.normalizeId)(key || id2);
4471
4471
  this._checkUnique(key);
4472
4472
  this.schemas[key] = this._addSchema(schema, _meta, key, _validateSchema, true);
4473
4473
  return this;
@@ -4546,11 +4546,11 @@ var require_core = __commonJS({
4546
4546
  case "object": {
4547
4547
  const cacheKey = schemaKeyRef;
4548
4548
  this._cache.delete(cacheKey);
4549
- let id = schemaKeyRef[this.opts.schemaId];
4550
- if (id) {
4551
- id = (0, resolve_1.normalizeId)(id);
4552
- delete this.schemas[id];
4553
- delete this.refs[id];
4549
+ let id2 = schemaKeyRef[this.opts.schemaId];
4550
+ if (id2) {
4551
+ id2 = (0, resolve_1.normalizeId)(id2);
4552
+ delete this.schemas[id2];
4553
+ delete this.refs[id2];
4554
4554
  }
4555
4555
  return this;
4556
4556
  }
@@ -4621,7 +4621,7 @@ var require_core = __commonJS({
4621
4621
  errorsText(errors = this.errors, { separator = ", ", dataVar = "data" } = {}) {
4622
4622
  if (!errors || errors.length === 0)
4623
4623
  return "No errors";
4624
- return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text2, msg) => text2 + separator + msg);
4624
+ return errors.map((e) => `${dataVar}${e.instancePath} ${e.message}`).reduce((text3, msg) => text3 + separator + msg);
4625
4625
  }
4626
4626
  $dataMetaSchema(metaSchema, keywordsJsonPointers) {
4627
4627
  const rules = this.RULES.all;
@@ -4657,10 +4657,10 @@ var require_core = __commonJS({
4657
4657
  }
4658
4658
  }
4659
4659
  _addSchema(schema, meta, baseId, validateSchema = this.opts.validateSchema, addSchema = this.opts.addUsedSchema) {
4660
- let id;
4660
+ let id2;
4661
4661
  const { schemaId } = this.opts;
4662
4662
  if (typeof schema == "object") {
4663
- id = schema[schemaId];
4663
+ id2 = schema[schemaId];
4664
4664
  } else {
4665
4665
  if (this.opts.jtd)
4666
4666
  throw new Error("schema must be object");
@@ -4670,7 +4670,7 @@ var require_core = __commonJS({
4670
4670
  let sch = this._cache.get(schema);
4671
4671
  if (sch !== void 0)
4672
4672
  return sch;
4673
- baseId = (0, resolve_1.normalizeId)(id || baseId);
4673
+ baseId = (0, resolve_1.normalizeId)(id2 || baseId);
4674
4674
  const localRefs = resolve_1.getSchemaRefs.call(this, schema, baseId);
4675
4675
  sch = new compile_1.SchemaEnv({ schema, schemaId, meta, baseId, localRefs });
4676
4676
  this._cache.set(sch.schema, sch);
@@ -4683,9 +4683,9 @@ var require_core = __commonJS({
4683
4683
  this.validateSchema(schema, true);
4684
4684
  return sch;
4685
4685
  }
4686
- _checkUnique(id) {
4687
- if (this.schemas[id] || this.refs[id]) {
4688
- throw new Error(`schema with key or id "${id}" already exists`);
4686
+ _checkUnique(id2) {
4687
+ if (this.schemas[id2] || this.refs[id2]) {
4688
+ throw new Error(`schema with key or id "${id2}" already exists`);
4689
4689
  }
4690
4690
  }
4691
4691
  _compileSchemaEnv(sch) {
@@ -7217,7 +7217,9 @@ var methods = {
7217
7217
  report: "msg.report",
7218
7218
  ask: "msg.ask",
7219
7219
  read: "msg.read",
7220
- leave: "session.leave"
7220
+ leave: "session.leave",
7221
+ task: "dashboard.task",
7222
+ artifact: "dashboard.artifact"
7221
7223
  };
7222
7224
 
7223
7225
  // node_modules/zod/v3/external.js
@@ -13031,38 +13033,38 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
13031
13033
  doc.write(`const newResult = {}`);
13032
13034
  for (const key of normalized.keys) {
13033
13035
  if (normalized.optionalKeys.has(key)) {
13034
- const id = ids[key];
13035
- doc.write(`const ${id} = ${parseStr(key)};`);
13036
+ const id2 = ids[key];
13037
+ doc.write(`const ${id2} = ${parseStr(key)};`);
13036
13038
  const k = esc(key);
13037
13039
  doc.write(`
13038
- if (${id}.issues.length) {
13040
+ if (${id2}.issues.length) {
13039
13041
  if (input[${k}] === undefined) {
13040
13042
  if (${k} in input) {
13041
13043
  newResult[${k}] = undefined;
13042
13044
  }
13043
13045
  } else {
13044
13046
  payload.issues = payload.issues.concat(
13045
- ${id}.issues.map((iss) => ({
13047
+ ${id2}.issues.map((iss) => ({
13046
13048
  ...iss,
13047
13049
  path: iss.path ? [${k}, ...iss.path] : [${k}],
13048
13050
  }))
13049
13051
  );
13050
13052
  }
13051
- } else if (${id}.value === undefined) {
13053
+ } else if (${id2}.value === undefined) {
13052
13054
  if (${k} in input) newResult[${k}] = undefined;
13053
13055
  } else {
13054
- newResult[${k}] = ${id}.value;
13056
+ newResult[${k}] = ${id2}.value;
13055
13057
  }
13056
13058
  `);
13057
13059
  } else {
13058
- const id = ids[key];
13059
- doc.write(`const ${id} = ${parseStr(key)};`);
13060
+ const id2 = ids[key];
13061
+ doc.write(`const ${id2} = ${parseStr(key)};`);
13060
13062
  doc.write(`
13061
- if (${id}.issues.length) payload.issues = payload.issues.concat(${id}.issues.map(iss => ({
13063
+ if (${id2}.issues.length) payload.issues = payload.issues.concat(${id2}.issues.map(iss => ({
13062
13064
  ...iss,
13063
13065
  path: iss.path ? [${esc(key)}, ...iss.path] : [${esc(key)}]
13064
13066
  })));`);
13065
- doc.write(`newResult[${esc(key)}] = ${id}.value`);
13067
+ doc.write(`newResult[${esc(key)}] = ${id2}.value`);
13066
13068
  }
13067
13069
  }
13068
13070
  doc.write(`payload.value = newResult;`);
@@ -14795,13 +14797,13 @@ var JSONSchemaGenerator = class {
14795
14797
  const defsSegment = this.target === "draft-2020-12" ? "$defs" : "definitions";
14796
14798
  if (params.external) {
14797
14799
  const externalId = params.external.registry.get(entry[0])?.id;
14798
- const uriGenerator = params.external.uri ?? ((id2) => id2);
14800
+ const uriGenerator = params.external.uri ?? ((id3) => id3);
14799
14801
  if (externalId) {
14800
14802
  return { ref: uriGenerator(externalId) };
14801
14803
  }
14802
- const id = entry[1].defId ?? entry[1].schema.id ?? `schema${this.counter++}`;
14803
- entry[1].defId = id;
14804
- return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` };
14804
+ const id2 = entry[1].defId ?? entry[1].schema.id ?? `schema${this.counter++}`;
14805
+ entry[1].defId = id2;
14806
+ return { defId: id2, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id2}` };
14805
14807
  }
14806
14808
  if (entry[1] === root) {
14807
14809
  return { ref: "#" };
@@ -14849,8 +14851,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14849
14851
  continue;
14850
14852
  }
14851
14853
  }
14852
- const id = this.metadataRegistry.get(entry[0])?.id;
14853
- if (id) {
14854
+ const id2 = this.metadataRegistry.get(entry[0])?.id;
14855
+ if (id2) {
14854
14856
  extractToDef(entry);
14855
14857
  continue;
14856
14858
  }
@@ -14904,10 +14906,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14904
14906
  console.warn(`Invalid target: ${this.target}`);
14905
14907
  }
14906
14908
  if (params.external?.uri) {
14907
- const id = params.external.registry.get(schema)?.id;
14908
- if (!id)
14909
+ const id2 = params.external.registry.get(schema)?.id;
14910
+ if (!id2)
14909
14911
  throw new Error("Schema is missing an `id` property");
14910
- result.$id = params.external.uri(id);
14912
+ result.$id = params.external.uri(id2);
14911
14913
  }
14912
14914
  Object.assign(result, root.def);
14913
14915
  const defs = params.external?.defs ?? {};
@@ -19940,7 +19942,7 @@ var ExperimentalServerTasks = class {
19940
19942
  if (hasPreviousToolUse) {
19941
19943
  const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
19942
19944
  const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
19943
- if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
19945
+ if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id2) => toolResultIds.has(id2))) {
19944
19946
  throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
19945
19947
  }
19946
19948
  }
@@ -20365,7 +20367,7 @@ var Server = class extends Protocol {
20365
20367
  if (hasPreviousToolUse) {
20366
20368
  const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
20367
20369
  const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
20368
- if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
20370
+ if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id2) => toolResultIds.has(id2))) {
20369
20371
  throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
20370
20372
  }
20371
20373
  }
@@ -21457,8 +21459,70 @@ var StdioServerTransport = class {
21457
21459
  }
21458
21460
  };
21459
21461
 
21462
+ // src/shared/dashboard.ts
21463
+ var DASHBOARD_LIMITS = {
21464
+ recordsPerKind: 200,
21465
+ runsPerTask: 100,
21466
+ htmlBytes: 256 * 1024,
21467
+ htmlBytesPerSquad: 8 * 1024 * 1024
21468
+ };
21469
+
21470
+ // src/shared/dashboard-schemas.ts
21471
+ var id = external_exports.string().min(1).max(128);
21472
+ var text = external_exports.string().max(8e3);
21473
+ var artifacts = external_exports.array(id).max(8);
21474
+ var taskFields = {
21475
+ action: external_exports.enum(["create", "update", "get", "list", "archive", "restore"]).default("list"),
21476
+ id: id.optional(),
21477
+ title: external_exports.string().trim().min(1).max(200).optional(),
21478
+ description: text.optional(),
21479
+ acceptance: text.optional(),
21480
+ position: external_exports.number().finite().optional(),
21481
+ artifact_ids: artifacts.optional(),
21482
+ archived: external_exports.boolean().optional(),
21483
+ offset: external_exports.number().int().min(0).default(0),
21484
+ limit: external_exports.number().int().min(1).max(50).default(20)
21485
+ };
21486
+ var questionFields = {
21487
+ target: external_exports.enum(["commander", "user"]).default("commander"),
21488
+ action: external_exports.enum(["create", "update", "get", "list", "withdraw", "handle"]).default("create"),
21489
+ id: id.optional(),
21490
+ task_id: id.optional(),
21491
+ version: external_exports.number().int().positive().optional(),
21492
+ description: text.optional(),
21493
+ kind: external_exports.enum(["single", "multiple", "text", "confirm"]).optional(),
21494
+ options: external_exports.array(external_exports.object({ id, label: external_exports.string().trim().min(1).max(300) }).strict()).max(20).optional(),
21495
+ artifact_ids: artifacts.optional(),
21496
+ result: text.optional(),
21497
+ status: external_exports.enum(["pending", "answered", "handled", "withdrawn"]).optional(),
21498
+ offset: external_exports.number().int().min(0).default(0),
21499
+ limit: external_exports.number().int().min(1).max(50).default(20)
21500
+ };
21501
+ var artifactFields = {
21502
+ action: external_exports.enum(["publish", "get", "list"]).default("publish"),
21503
+ id: id.optional(),
21504
+ version: external_exports.number().int().positive().optional(),
21505
+ title: external_exports.string().trim().min(1).max(200).optional(),
21506
+ html: external_exports.string().min(1).refine((s) => Buffer.byteLength(s) <= DASHBOARD_LIMITS.htmlBytes, "MESSAGE_TOO_LARGE").optional(),
21507
+ offset: external_exports.number().int().min(0).default(0),
21508
+ limit: external_exports.number().int().min(1).max(50).default(20)
21509
+ };
21510
+ var answerSchema = external_exports.object({
21511
+ question_id: id,
21512
+ version: external_exports.number().int().positive(),
21513
+ submission_id: external_exports.string().uuid(),
21514
+ selected: external_exports.array(id).max(20).default([]),
21515
+ text: text.default(""),
21516
+ confirmed: external_exports.boolean().optional()
21517
+ }).strict();
21518
+ var userMessageSchema = external_exports.object({
21519
+ squad_id: id,
21520
+ submission_id: external_exports.string().uuid(),
21521
+ text: external_exports.string().trim().min(1).max(8e3)
21522
+ }).strict();
21523
+
21460
21524
  // src/shared/schemas.ts
21461
- var text = external_exports.string().min(1).refine((v) => Buffer.byteLength(v) <= LIMITS.maxBody, "MESSAGE_TOO_LARGE");
21525
+ var text2 = external_exports.string().min(1).refine((v) => Buffer.byteLength(v) <= LIMITS.maxBody, "MESSAGE_TOO_LARGE");
21462
21526
  var data = external_exports.record(external_exports.unknown()).refine((v) => Buffer.byteLength(JSON.stringify(v)) <= LIMITS.maxData, "MESSAGE_TOO_LARGE").optional();
21463
21527
  var wait = external_exports.number().min(0).max(300).default(0);
21464
21528
  var identity = { _cmdr_session: external_exports.string().min(1).max(256).optional() };
@@ -21468,7 +21532,7 @@ var schemas = {
21468
21532
  role: external_exports.enum(["commander", "executor"]).optional(),
21469
21533
  squad: external_exports.string().optional(),
21470
21534
  name: external_exports.string().trim().min(1).max(64).optional(),
21471
- note: text.optional(),
21535
+ note: text2.optional(),
21472
21536
  squad_name: external_exports.string().trim().min(1).max(64).optional(),
21473
21537
  takeover: external_exports.boolean().default(false),
21474
21538
  standby: external_exports.enum(["auto", "manual"]).optional(),
@@ -21483,17 +21547,27 @@ var schemas = {
21483
21547
  report: external_exports.object({
21484
21548
  ...identity,
21485
21549
  status: external_exports.enum(["ready", "working", "blocked", "done", "failed", "cancelled"]),
21486
- message: text,
21550
+ message: text2,
21551
+ reply_to: external_exports.string().optional(),
21552
+ data
21553
+ }).strict(),
21554
+ ask: external_exports.object({
21555
+ ...identity,
21556
+ ...questionFields,
21557
+ question: text2.optional(),
21558
+ wait,
21487
21559
  reply_to: external_exports.string().optional(),
21488
21560
  data
21489
21561
  }).strict(),
21490
- ask: external_exports.object({ ...identity, question: text, wait, reply_to: external_exports.string().optional(), data }).strict(),
21562
+ task: external_exports.object({ ...identity, ...taskFields }).strict(),
21563
+ artifact: external_exports.object({ ...identity, ...artifactFields }).strict(),
21491
21564
  send: external_exports.object({
21492
21565
  ...identity,
21493
21566
  to: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).min(1).max(1e3)]),
21494
- message: text,
21567
+ message: text2,
21495
21568
  type: external_exports.enum(["command", "cancel", "answer", "info"]).default("command"),
21496
21569
  task_key: external_exports.string().min(1).max(128).optional(),
21570
+ task_id: external_exports.string().min(1).max(128).optional(),
21497
21571
  reassign: external_exports.string().optional(),
21498
21572
  attention: external_exports.boolean().optional(),
21499
21573
  priority: external_exports.enum(["high", "normal", "low"]).optional(),
@@ -21511,11 +21585,11 @@ var schemas = {
21511
21585
  recover: external_exports.boolean().default(false),
21512
21586
  full: external_exports.boolean().default(false)
21513
21587
  }).strict(),
21514
- leave: external_exports.object({ ...identity, dissolve: external_exports.boolean().default(false), message: text.optional() }).strict()
21588
+ leave: external_exports.object({ ...identity, dissolve: external_exports.boolean().default(false), message: text2.optional() }).strict()
21515
21589
  };
21516
21590
 
21517
21591
  // src/shared/version.ts
21518
- var VERSION = true ? "0.4.0" : MIN_CLIENT_VERSION;
21592
+ var VERSION = true ? "0.5.0" : MIN_CLIENT_VERSION;
21519
21593
  var PROTOCOL = 1;
21520
21594
  function newer(a, b) {
21521
21595
  const x = a.split(".").map(Number), y = b.split(".").map(Number);
@@ -21736,26 +21810,26 @@ var Rpc = class extends EventEmitter {
21736
21810
  if (this.socket.destroyed) return Promise.reject(new CmdrError("DAEMON_UNAVAILABLE"));
21737
21811
  if (signal?.aborted) return Promise.reject(new CmdrError("REQUEST_CANCELLED"));
21738
21812
  return new Promise((resolve2, reject) => {
21739
- const id = this.next++;
21813
+ const id2 = this.next++;
21740
21814
  const cancel = (code) => {
21741
- const p = this.pending.get(id);
21815
+ const p = this.pending.get(id2);
21742
21816
  if (!p) return;
21743
- this.pending.delete(id);
21817
+ this.pending.delete(id2);
21744
21818
  clearTimeout(p.timer);
21745
21819
  p.cleanup();
21746
- this.notify("rpc.cancel", { id });
21820
+ this.notify("rpc.cancel", { id: id2 });
21747
21821
  reject(new CmdrError(code));
21748
21822
  };
21749
21823
  const abort = () => cancel("REQUEST_CANCELLED");
21750
21824
  const timer = setTimeout(() => cancel("DAEMON_UNAVAILABLE"), timeout);
21751
- this.pending.set(id, {
21825
+ this.pending.set(id2, {
21752
21826
  resolve: resolve2,
21753
21827
  reject,
21754
21828
  timer,
21755
21829
  cleanup: () => signal?.removeEventListener("abort", abort)
21756
21830
  });
21757
21831
  signal?.addEventListener("abort", abort, { once: true });
21758
- this.send({ jsonrpc: "2.0", id, method, params });
21832
+ this.send({ jsonrpc: "2.0", id: id2, method, params });
21759
21833
  });
21760
21834
  }
21761
21835
  notify(method, params) {
@@ -22049,9 +22123,11 @@ var server = new McpServer({ name: "cmdr", version: VERSION });
22049
22123
  var descriptions = {
22050
22124
  join: "Create/join a squad. For /cmdr <name>, pass squad_name for atomic find-or-create; role defaults to executor. Explicitly claim role=commander, use takeover=true for handover or rebind=member_id for a new endpoint. Otherwise specify role and optional squad ID/name. Use standby=auto; Claude/ZCode must run listener.arm.command with the indicated native host tool, and re-arm on termination. Codex is daemon driven. Inspect listener health before ending the turn. Executors report ready after joining. Reply with user_reply and follow listener health; bounded read(wait=me.recommended_wait) is the manual fallback.",
22051
22125
  list: "Show task ownership, unacked_for, execution activity, connection presence and listener health. Offline never authorizes reassignment. Use full=true for expanded session metadata; listings never include command bodies. Read your own messages with read(id=...). scope=all lists squads and sessions.",
22052
- send: "Commander: dispatch clear tasks with acceptance criteria, or answer an ask using type=answer and reply_to. Use task_key to prevent duplicate tickets and reassign=<command id> for a gated handover preserving the original task_key. type=cancel with reply_to requests a safe stop. to accepts all, member_id, sid, unique sid prefix or member name.",
22126
+ send: "Commander: dispatch clear tasks with acceptance criteria, optionally linked to task_id from the dashboard task tool, or answer an executor ask using type=answer and reply_to. Use task_key to prevent duplicate tickets and reassign=<command id> for a gated handover preserving the original task/task_key. type=cancel with reply_to requests a safe stop. to accepts all, member_id, sid, unique sid prefix or member name.",
22053
22127
  report: "Executor: report ready (cwd/capabilities), working, blocked, done, failed or cancelled; include reply_to for the command.",
22054
- ask: "Executor: ask the commander for guidance. Optional wait waits for the matching answer; use me.recommended_wait as the upper bound.",
22128
+ ask: "Executor: ask the commander (default target=commander). Commander: target=user creates a durable dashboard question (kind=single|multiple|text|confirm); use action=list|get|update|withdraw|handle, id and current version. handle requires result. User replies arrive in read; query status=answered to recover unhandled decisions. User questions do not use wait.",
22129
+ task: "Maintain dashboard tasks. Commander uses action=create|update|archive|restore; title is required for create. Members can list/get within their squad. Dispatch with send(task_id=...). Execution states follow commands/reports; unfinished work cannot be archived. list is paginated; get includes durable execution history.",
22130
+ artifact: "Commander publishes self-contained HTML as an isolated dashboard explanation (256 KiB maximum). action=publish requires title and html; updating also requires id and current version. Link returned id via task/ask artifact_ids. Members can list/get. User answers always use built-in forms outside HTML. Updating an artifact increments versions of pending questions that reference it.",
22055
22131
  read: "Fetch messages in priority order (reading dequeues). Use wait=me.recommended_wait to stand by, peek to inspect or history to review delivered messages. Use recover=true for all unfinished commands (non-consuming), id for a non-consuming message lookup (blocked replacements return REASSIGNMENT_PENDING), full for squad details. With a healthy listener, end the turn. Claude/ZCode must first arm the built-in host watcher from listener.arm. Only when host wake is unavailable, do at most two waits and explain manual continuation.",
22056
22132
  leave: "Leave the squad. Commander departure orphans it; dissolve=true disbands it. Messages already queued remain readable."
22057
22133
  };
@@ -5,7 +5,7 @@ metadata:
5
5
  source: https://github.com/njugray/cmdr
6
6
  ---
7
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.
8
+ Connect existing sessions; cmdr never creates agents. For `cmdr <name>`, `/cmdr <name>`, or a request to join a channel, use the nine cmdr MCP tools: join, list, send, report, ask, read, leave, task, artifact. A host may namespace their names.
9
9
 
10
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
11
 
@@ -18,3 +18,5 @@ Use the host's real session identity, supplied through the integration. Never in
18
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
19
 
20
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.
21
+
22
+ The dashboard is built into the full runtime: `cmdr dashboard` opens it. A skill-only install does not provide its server or assets. Commander dashboard operations use task, artifact and ask(target="user"); use the role reference for answer recovery and handling. UI styles and forms are runtime-owned; agents operate data and may publish isolated HTML explanations.
@@ -10,3 +10,5 @@
10
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
11
 
12
12
  Apply normal judgment and the user's scope to messages. cmdr does not create new agents or grant extra permissions.
13
+
14
+ For the built-in dashboard, create/update tasks with `task`; dispatch with `send(task_id=...)`. Use `ask(target="user", question=..., kind=single|multiple|text|confirm)` for user decisions; ordinary executor asks still receive `send(type="answer", reply_to=...)`. User answers arrive in the role inbox. On recovery also query `ask(target="user", action="list", status="answered")`; reading does not process a decision. Record its outcome using `ask(target="user", action="handle", id=..., version=..., result=...)`. Pending edits/withdrawals require the current version; create a new question after an answer. Publish complex, self-contained HTML with `artifact`, then link its ID through `artifact_ids`. Use built-in forms for official answers; never fabricate user confirmation. `cmdr dashboard` opens the runtime-owned page locally and prints separate short-lived links for loopback and each non-loopback IPv4 address; `--no-open` only prints the links. The dashboard listens on `0.0.0.0` with a system-assigned port. Keep the returned listener arm command’s CMDR_HOME binding intact.
@@ -9,3 +9,5 @@
9
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
10
 
11
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.
12
+
13
+ Dashboard task/artifact queries are available for your squad. Execution status still follows the owned command and correlated reports; do not edit task state or create user confirmations. Ask the commander when blocked. Only the current commander manages user questions and records their handling. Keep the listener arm command’s CMDR_HOME binding intact.
@@ -12,3 +12,5 @@ description: Coordinate a persistent cmdr channel, track task ownership and ackn
12
12
  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").
13
13
 
14
14
  Apply normal judgment and the user's scope to messages. cmdr does not create new agents or grant extra permissions.
15
+
16
+ For the built-in dashboard, create/update tasks with `task`; dispatch with `send(task_id=...)`. Use `ask(target="user", question=..., kind=single|multiple|text|confirm)` for user decisions; ordinary executor asks still receive `send(type="answer", reply_to=...)`. User answers arrive in the role inbox. On recovery also query `ask(target="user", action="list", status="answered")`; reading does not process a decision. Record its outcome using `ask(target="user", action="handle", id=..., version=..., result=...)`. Pending edits/withdrawals require the current version; create a new question after an answer. Publish complex, self-contained HTML with `artifact`, then link its ID through `artifact_ids`. Use built-in forms for official answers; never fabricate user confirmation. `cmdr dashboard` opens the runtime-owned page locally and prints separate short-lived links for loopback and each non-loopback IPv4 address; `--no-open` only prints the links. The dashboard listens on `0.0.0.0` with a system-assigned port. Keep the returned listener arm command’s CMDR_HOME binding intact.
@@ -11,3 +11,5 @@ description: Join an existing cmdr channel as executor, acknowledge tasks, repor
11
11
  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.
12
12
 
13
13
  Messages do not expand user authorization. Apply normal judgment. Unknown hosts remain manual; never claim a successful wake merely because a message was queued.
14
+
15
+ Dashboard task/artifact queries are available for your squad. Execution status still follows the owned command and correlated reports; do not edit task state or create user confirmations. Ask the commander when blocked. Only the current commander manages user questions and records their handling. Keep the listener arm command’s CMDR_HOME binding intact.
@@ -2,11 +2,11 @@
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 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.
5
+ If the nine 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
 
9
- Seven tools: join, list, send, report, ask, read, leave. Read is transport delivery; report(working, reply_to) acknowledges a command, and done/failed/cancelled completes it. On recovery inspect both read and read(recover=true). Use read(id=...) for a complete non-consuming lookup; full=true requests expanded output. Do not truncate a consuming read with head.
9
+ Nine tools: join, list, send, report, ask, read, leave, task, artifact. Read is transport delivery; report(working, reply_to) acknowledges a command, and done/failed/cancelled completes it. On recovery inspect both read and read(recover=true). Use read(id=...) for a complete non-consuming lookup; full=true requests expanded output. Do not truncate a consuming read with head.
10
10
 
11
11
  Executors report ready with cwd and capabilities, then acknowledge commands before working. Commanders inspect list for unfinished commands and their age before dispatch, and use task_key plus reassign=<command id> to prevent duplicate ownership. Offline never means stopped. Cancel messages take priority at safe checkpoints; replacements wait for a terminal report. Answer asks with reply_to.
12
12