cmdr-mcp 0.4.0 → 0.6.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/README.md +44 -17
- package/docs/README.zh-CN.md +33 -8
- package/docs/agent-integration.md +74 -12
- package/docs/dashboard-plan.md +327 -0
- package/docs/dashboard.md +101 -0
- package/docs/implementation.md +25 -4
- package/docs/long-running-collaboration.md +4 -2
- package/docs/publishing.md +11 -9
- package/docs/setup.md +4 -3
- package/docs/troubleshooting.md +3 -3
- package/marketplace.json +2 -2
- package/package.json +10 -2
- package/plugins/cmdr/.claude-plugin/plugin.json +1 -1
- package/plugins/cmdr/.codex-plugin/plugin.json +1 -1
- package/plugins/cmdr/.kimi-plugin/plugin.json +65 -0
- package/plugins/cmdr/.zcode-plugin/plugin.json +1 -1
- package/plugins/cmdr/README.md +7 -5
- package/plugins/cmdr/THIRD_PARTY_NOTICES.txt +130 -0
- package/plugins/cmdr/bin/cmdr-check.mjs +6 -1
- package/plugins/cmdr/bin/cmdr-node +8 -1
- package/plugins/cmdr/commands/cmdr.md +3 -1
- package/plugins/cmdr/dist/cli.mjs +226 -43
- package/plugins/cmdr/dist/daemon.mjs +4792 -161
- package/plugins/cmdr/dist/dashboard/app.css +1 -0
- package/plugins/cmdr/dist/dashboard/app.js +10 -0
- package/plugins/cmdr/dist/dashboard/index.html +13 -0
- package/plugins/cmdr/dist/hook.mjs +22 -4
- package/plugins/cmdr/dist/integrity.json +24 -19
- package/plugins/cmdr/dist/mcp.mjs +148 -66
- package/plugins/cmdr/kimi-identity/SKILL.md +12 -0
- package/plugins/cmdr/skills/cmdr/SKILL.md +4 -2
- package/plugins/cmdr/skills/cmdr/references/commander.md +3 -1
- package/plugins/cmdr/skills/cmdr/references/executor.md +3 -1
- package/plugins/cmdr/skills/cmdr/references/setup.md +1 -1
- package/plugins/cmdr/skills/cmdr-commander/SKILL.md +3 -1
- package/plugins/cmdr/skills/cmdr-executor/SKILL.md +3 -1
- package/plugins/cmdr/skills/using-cmdr/SKILL.md +3 -3
|
@@ -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,10 +85,11 @@ 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";
|
|
92
|
+
if (env.KIMI_PLUGIN_ROOT) return "kimi";
|
|
92
93
|
if (env.CLAUDE_CODE_SESSION_ID || env.CLAUDE_CODE_ENTRYPOINT) return "claude";
|
|
93
94
|
if (hook?.transcript_path && String(hook.transcript_path).includes("/.claude/")) return "claude";
|
|
94
95
|
if (env.CODEX_HOME || env.CODEX_THREAD_ID || env.CODEX_SESSION_ID || hook?.turn_id)
|
|
@@ -254,7 +255,7 @@ var Rpc = class extends EventEmitter {
|
|
|
254
255
|
};
|
|
255
256
|
|
|
256
257
|
// src/shared/version.ts
|
|
257
|
-
var VERSION = true ? "0.
|
|
258
|
+
var VERSION = true ? "0.6.0" : MIN_CLIENT_VERSION;
|
|
258
259
|
var PROTOCOL = 1;
|
|
259
260
|
function newer(a, b) {
|
|
260
261
|
const x = a.split(".").map(Number), y = b.split(".").map(Number);
|
|
@@ -391,6 +392,13 @@ async function runHook(input, event = input.hook_event_name) {
|
|
|
391
392
|
return;
|
|
392
393
|
}
|
|
393
394
|
if (event === "PreToolUse" && cmdrTool.test(input.tool_name || "")) {
|
|
395
|
+
if (agent === "kimi") {
|
|
396
|
+
if ((input.tool_input || {})._cmdr_session === input.session_id) return;
|
|
397
|
+
return {
|
|
398
|
+
decision: "block",
|
|
399
|
+
reason: `[cmdr] Kimi Code shares one cmdr MCP process per workspace; retry this call with _cmdr_session="${input.session_id}".`
|
|
400
|
+
};
|
|
401
|
+
}
|
|
394
402
|
if (agent !== "claude")
|
|
395
403
|
return {
|
|
396
404
|
hookSpecificOutput: {
|
|
@@ -424,8 +432,18 @@ try {
|
|
|
424
432
|
input += chunk;
|
|
425
433
|
if (input.length > 2 * 1024 * 1024) throw new Error("large input");
|
|
426
434
|
}
|
|
427
|
-
const
|
|
428
|
-
|
|
435
|
+
const parsed = JSON.parse(input);
|
|
436
|
+
const agent = detectAgent(process.env, parsed);
|
|
437
|
+
const result = await runHook(parsed, process.argv[2]);
|
|
438
|
+
if (result) {
|
|
439
|
+
if (agent === "kimi") {
|
|
440
|
+
if (result.decision === "block")
|
|
441
|
+
process.stderr.write(`${result.reason}
|
|
442
|
+
`, () => process.exit(2));
|
|
443
|
+
else if (process.argv[2] === "UserPromptSubmit" && result.hookSpecificOutput?.additionalContext)
|
|
444
|
+
process.stdout.write(result.hookSpecificOutput.additionalContext + "\n");
|
|
445
|
+
} else process.stdout.write(JSON.stringify(result) + "\n");
|
|
446
|
+
}
|
|
429
447
|
} catch (e) {
|
|
430
448
|
diagnostic(e.code === "DAEMON_UNAVAILABLE" ? "hook-unavailable" : "hook-error");
|
|
431
449
|
}
|
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.6.0",
|
|
3
3
|
"files": {
|
|
4
|
-
".claude-plugin/plugin.json": "
|
|
5
|
-
".codex-plugin/plugin.json": "
|
|
4
|
+
".claude-plugin/plugin.json": "03daaf06535131d19dc7444907f1af1100a9deeb2b07553862805c33d49f878d",
|
|
5
|
+
".codex-plugin/plugin.json": "36b3066ada5434eda049904b6a90ef867f093a3f861e6a61e9df7fddb5963156",
|
|
6
|
+
".kimi-plugin/plugin.json": "7634842fb15abaf7a6ccc9d4500cd27447515e3d6c99de0a3249bf0f74631bc6",
|
|
6
7
|
".mcp.json": "34e310a2874c8fda625745672a54df19614f32dabd2be4013f8ce871260e88c4",
|
|
7
|
-
".zcode-plugin/plugin.json": "
|
|
8
|
-
"THIRD_PARTY_NOTICES.txt": "
|
|
8
|
+
".zcode-plugin/plugin.json": "6a5f67567958487a9a10db5bf879641de790c5734fafaeab7ce39a978ddab43a",
|
|
9
|
+
"THIRD_PARTY_NOTICES.txt": "061121858596143e1ec0609aeee0d45ec839e53f05a4b7c23a48ec7df33194fc",
|
|
9
10
|
"bin/cmdr": "be6ea6b84ce121738ca729e9c6dbfb87bbf349a84d251acc711e3ea11f8dd8fd",
|
|
10
|
-
"bin/cmdr-check.mjs": "
|
|
11
|
+
"bin/cmdr-check.mjs": "669204363e26323af6abd623e9039c2c7e9ca9626ee9418e9ab9e2a85be7fc67",
|
|
11
12
|
"bin/cmdr-daemon": "7f8ed3a755f975751ddda077242adf661834dddbb8be7d3a88caee0c70cce5db",
|
|
12
13
|
"bin/cmdr-hook": "e1fa5950325775e467e4e01aeff3c5cb8c1dba35c4535d7cb569f658f95e7f15",
|
|
13
14
|
"bin/cmdr-mcp": "356bea13c2b82075c09fd663106791edab9e06fdb04fc679a98de33514b10a83",
|
|
14
|
-
"bin/cmdr-node": "
|
|
15
|
-
"commands/cmdr.md": "
|
|
16
|
-
"dist/cli.mjs": "
|
|
17
|
-
"dist/daemon.mjs": "
|
|
18
|
-
"dist/
|
|
19
|
-
"dist/
|
|
15
|
+
"bin/cmdr-node": "d4005e39ec1edc05a45413f38172a239a234cc457fd17a320db5e24bdbc2e6c8",
|
|
16
|
+
"commands/cmdr.md": "c46d1d3d38af10ac75f8793b998e0889a9136da82b883816a724502689184e49",
|
|
17
|
+
"dist/cli.mjs": "99ffbb22e10223c012100896ed7fe571fe0e1095c34003f54fdc9b389987cd22",
|
|
18
|
+
"dist/daemon.mjs": "21335e66c4eb808e8f9e8d6c6de0daf3a3e733616eb4c89547c7621a9e51c690",
|
|
19
|
+
"dist/dashboard/app.css": "58d74d9a98c39bef501a53f2530a99906d2fbb8ef5a619ff7a8ee432005d65d3",
|
|
20
|
+
"dist/dashboard/app.js": "c3549fce634931de741df6883e63e246969eedfedd8af4e81e7afe0687a10d1e",
|
|
21
|
+
"dist/dashboard/index.html": "670b1a05ca906b352ed5d8f53d2adc1a9ad5bb937e758a09ae200752f4e25356",
|
|
22
|
+
"dist/hook.mjs": "ce32d8fda6272f9cbfe0fb8bde9d68ce55a10c3ceacb6f3166787115df96e793",
|
|
23
|
+
"dist/mcp.mjs": "55950f4e6be2600881e8ca9c89e316b41a2039c98278199b8c846900869e41ba",
|
|
20
24
|
"hooks/hooks.json": "6ff937910fc04eb81db4a84dfeb91a92ab971364d684a45a85f3a9953eb21259",
|
|
21
|
-
"
|
|
22
|
-
"skills/cmdr/
|
|
23
|
-
"skills/cmdr/references/
|
|
24
|
-
"skills/cmdr/references/
|
|
25
|
-
"skills/cmdr
|
|
26
|
-
"skills/cmdr-
|
|
27
|
-
"skills/
|
|
25
|
+
"kimi-identity/SKILL.md": "967454ed3a9c1ddeeb87c5f419ce6303399caec1563192777c564445e6e6d59f",
|
|
26
|
+
"skills/cmdr/SKILL.md": "f95875b0b54877547a16158403dbdf7162c9a10d417dc956907acd81fd174305",
|
|
27
|
+
"skills/cmdr/references/commander.md": "48728f778a53cd2ae9d38cafcfa5f6c00f9b92a29acad452eecba1c07d04985d",
|
|
28
|
+
"skills/cmdr/references/executor.md": "c7527c2a15cb593407b9547dd431bc499d6eaa7216e8fae5c14402c6c748b9ad",
|
|
29
|
+
"skills/cmdr/references/setup.md": "8049617af8d441a586e498a8c6fb6bd84836b5d8ffd7199c4cec2b589fdcf4ad",
|
|
30
|
+
"skills/cmdr-commander/SKILL.md": "2b39799de58cef778d2009acede67701e2ec3fef5e0e617480a79d048fc0a692",
|
|
31
|
+
"skills/cmdr-executor/SKILL.md": "dad00e3f9116b19d0009bbeb9f2527e0ffcbce20c7b70ab5208656e091bfbd14",
|
|
32
|
+
"skills/using-cmdr/SKILL.md": "921ac245e5884cf4e5bf9a07520b186ebdf47c0cfc93e6e171c4072d163e03fd"
|
|
28
33
|
}
|
|
29
34
|
}
|
|
@@ -2232,10 +2232,10 @@ var require_resolve = __commonJS({
|
|
|
2232
2232
|
}
|
|
2233
2233
|
return count;
|
|
2234
2234
|
}
|
|
2235
|
-
function getFullPath(resolver,
|
|
2235
|
+
function getFullPath(resolver, id2 = "", normalize) {
|
|
2236
2236
|
if (normalize !== false)
|
|
2237
|
-
|
|
2238
|
-
const p = resolver.parse(
|
|
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(
|
|
2249
|
-
return
|
|
2248
|
+
function normalizeId(id2) {
|
|
2249
|
+
return id2 ? id2.replace(TRAILING_SLASH_HASH, "") : "";
|
|
2250
2250
|
}
|
|
2251
2251
|
exports.normalizeId = normalizeId;
|
|
2252
|
-
function resolveUrl(resolver, baseId,
|
|
2253
|
-
|
|
2254
|
-
return resolver.resolve(baseId,
|
|
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
|
|
3025
|
-
const schOrRef = this.refs[
|
|
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 (
|
|
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
|
|
4462
|
+
let id2;
|
|
4463
4463
|
if (typeof schema === "object") {
|
|
4464
4464
|
const { schemaId } = this.opts;
|
|
4465
|
-
|
|
4466
|
-
if (
|
|
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 ||
|
|
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
|
|
4550
|
-
if (
|
|
4551
|
-
|
|
4552
|
-
delete this.schemas[
|
|
4553
|
-
delete this.refs[
|
|
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((
|
|
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
|
|
4660
|
+
let id2;
|
|
4661
4661
|
const { schemaId } = this.opts;
|
|
4662
4662
|
if (typeof schema == "object") {
|
|
4663
|
-
|
|
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)(
|
|
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(
|
|
4687
|
-
if (this.schemas[
|
|
4688
|
-
throw new Error(`schema with key or id "${
|
|
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
|
|
13035
|
-
doc.write(`const ${
|
|
13036
|
+
const id2 = ids[key];
|
|
13037
|
+
doc.write(`const ${id2} = ${parseStr(key)};`);
|
|
13036
13038
|
const k = esc(key);
|
|
13037
13039
|
doc.write(`
|
|
13038
|
-
if (${
|
|
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
|
-
${
|
|
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 (${
|
|
13053
|
+
} else if (${id2}.value === undefined) {
|
|
13052
13054
|
if (${k} in input) newResult[${k}] = undefined;
|
|
13053
13055
|
} else {
|
|
13054
|
-
newResult[${k}] = ${
|
|
13056
|
+
newResult[${k}] = ${id2}.value;
|
|
13055
13057
|
}
|
|
13056
13058
|
`);
|
|
13057
13059
|
} else {
|
|
13058
|
-
const
|
|
13059
|
-
doc.write(`const ${
|
|
13060
|
+
const id2 = ids[key];
|
|
13061
|
+
doc.write(`const ${id2} = ${parseStr(key)};`);
|
|
13060
13062
|
doc.write(`
|
|
13061
|
-
if (${
|
|
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)}] = ${
|
|
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 ?? ((
|
|
14800
|
+
const uriGenerator = params.external.uri ?? ((id3) => id3);
|
|
14799
14801
|
if (externalId) {
|
|
14800
14802
|
return { ref: uriGenerator(externalId) };
|
|
14801
14803
|
}
|
|
14802
|
-
const
|
|
14803
|
-
entry[1].defId =
|
|
14804
|
-
return { defId:
|
|
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
|
|
14853
|
-
if (
|
|
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
|
|
14908
|
-
if (!
|
|
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(
|
|
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((
|
|
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((
|
|
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
|
|
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:
|
|
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:
|
|
21550
|
+
message: text2,
|
|
21487
21551
|
reply_to: external_exports.string().optional(),
|
|
21488
21552
|
data
|
|
21489
21553
|
}).strict(),
|
|
21490
|
-
ask: external_exports.object({
|
|
21554
|
+
ask: external_exports.object({
|
|
21555
|
+
...identity,
|
|
21556
|
+
...questionFields,
|
|
21557
|
+
question: text2.optional(),
|
|
21558
|
+
wait,
|
|
21559
|
+
reply_to: external_exports.string().optional(),
|
|
21560
|
+
data
|
|
21561
|
+
}).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:
|
|
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:
|
|
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.
|
|
21592
|
+
var VERSION = true ? "0.6.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);
|
|
@@ -21529,6 +21603,7 @@ function newer(a, b) {
|
|
|
21529
21603
|
function detectAgent(env = process.env, hook) {
|
|
21530
21604
|
if (env.CMDR_AGENT && /^[a-z][a-z0-9_-]{0,63}$/.test(env.CMDR_AGENT)) return env.CMDR_AGENT;
|
|
21531
21605
|
if (env.ZCODE_PLUGIN_ROOT || env.ZCODE_PLUGIN_ID) return "zcode";
|
|
21606
|
+
if (env.KIMI_PLUGIN_ROOT) return "kimi";
|
|
21532
21607
|
if (env.CLAUDE_CODE_SESSION_ID || env.CLAUDE_CODE_ENTRYPOINT) return "claude";
|
|
21533
21608
|
if (hook?.transcript_path && String(hook.transcript_path).includes("/.claude/")) return "claude";
|
|
21534
21609
|
if (env.CODEX_HOME || env.CODEX_THREAD_ID || env.CODEX_SESSION_ID || hook?.turn_id)
|
|
@@ -21736,26 +21811,26 @@ var Rpc = class extends EventEmitter {
|
|
|
21736
21811
|
if (this.socket.destroyed) return Promise.reject(new CmdrError("DAEMON_UNAVAILABLE"));
|
|
21737
21812
|
if (signal?.aborted) return Promise.reject(new CmdrError("REQUEST_CANCELLED"));
|
|
21738
21813
|
return new Promise((resolve2, reject) => {
|
|
21739
|
-
const
|
|
21814
|
+
const id2 = this.next++;
|
|
21740
21815
|
const cancel = (code) => {
|
|
21741
|
-
const p = this.pending.get(
|
|
21816
|
+
const p = this.pending.get(id2);
|
|
21742
21817
|
if (!p) return;
|
|
21743
|
-
this.pending.delete(
|
|
21818
|
+
this.pending.delete(id2);
|
|
21744
21819
|
clearTimeout(p.timer);
|
|
21745
21820
|
p.cleanup();
|
|
21746
|
-
this.notify("rpc.cancel", { id });
|
|
21821
|
+
this.notify("rpc.cancel", { id: id2 });
|
|
21747
21822
|
reject(new CmdrError(code));
|
|
21748
21823
|
};
|
|
21749
21824
|
const abort = () => cancel("REQUEST_CANCELLED");
|
|
21750
21825
|
const timer = setTimeout(() => cancel("DAEMON_UNAVAILABLE"), timeout);
|
|
21751
|
-
this.pending.set(
|
|
21826
|
+
this.pending.set(id2, {
|
|
21752
21827
|
resolve: resolve2,
|
|
21753
21828
|
reject,
|
|
21754
21829
|
timer,
|
|
21755
21830
|
cleanup: () => signal?.removeEventListener("abort", abort)
|
|
21756
21831
|
});
|
|
21757
21832
|
signal?.addEventListener("abort", abort, { once: true });
|
|
21758
|
-
this.send({ jsonrpc: "2.0", id, method, params });
|
|
21833
|
+
this.send({ jsonrpc: "2.0", id: id2, method, params });
|
|
21759
21834
|
});
|
|
21760
21835
|
}
|
|
21761
21836
|
notify(method, params) {
|
|
@@ -22047,12 +22122,14 @@ function closeClients() {
|
|
|
22047
22122
|
}
|
|
22048
22123
|
var server = new McpServer({ name: "cmdr", version: VERSION });
|
|
22049
22124
|
var descriptions = {
|
|
22050
|
-
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.",
|
|
22125
|
+
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/Kimi 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
22126
|
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.",
|
|
22127
|
+
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
22128
|
report: "Executor: report ready (cwd/capabilities), working, blocked, done, failed or cancelled; include reply_to for the command.",
|
|
22054
|
-
ask: "Executor: ask the commander
|
|
22055
|
-
|
|
22129
|
+
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.",
|
|
22130
|
+
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.",
|
|
22131
|
+
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.",
|
|
22132
|
+
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/Kimi 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
22133
|
leave: "Leave the squad. Commander departure orphans it; dissolve=true disbands it. Messages already queued remain readable."
|
|
22057
22134
|
};
|
|
22058
22135
|
for (const name of Object.keys(schemas)) {
|
|
@@ -22062,6 +22139,11 @@ for (const name of Object.keys(schemas)) {
|
|
|
22062
22139
|
async (args, extra) => {
|
|
22063
22140
|
try {
|
|
22064
22141
|
const { _cmdr_session, ...params } = args;
|
|
22142
|
+
if (agent === "kimi" && !_cmdr_session && !process.env.CMDR_SESSION_ID)
|
|
22143
|
+
throw new CmdrError(
|
|
22144
|
+
"SESSION_STAMP_REQUIRED",
|
|
22145
|
+
'Kimi Code shares one cmdr MCP process per workspace, so every cmdr call must carry this session identity: retry with _cmdr_session="<session-id>". The id is the session_... value the cmdr identity skill renders for this session (${KIMI_SESSION_ID}); the main agent passes it on every call, including calls made on behalf of subagents.'
|
|
22146
|
+
);
|
|
22065
22147
|
const selected = await forSession(_cmdr_session);
|
|
22066
22148
|
const result = await selected.call(methods[name], params, extra.signal);
|
|
22067
22149
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cmdr-identity
|
|
3
|
+
description: Kimi Code session identity for cmdr; carry it on every cmdr MCP call so the shared per-workspace MCP process routes to the right member.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You run as a Kimi Code session inside a cmdr squad. Kimi Code shares ONE cmdr MCP process per workspace, so the daemon cannot tell which session is calling unless each call identifies itself.
|
|
7
|
+
|
|
8
|
+
Your session id for this conversation: ${KIMI_SESSION_ID}
|
|
9
|
+
|
|
10
|
+
- Pass `_cmdr_session` with exactly that value on EVERY cmdr MCP tool call (`join`, `list`, `send`, `report`, `ask`, `read`, `leave`, `task`, `artifact`), including calls you make on behalf of subagents — subagents never receive this injection.
|
|
11
|
+
- If a cmdr call is rejected for a missing or mismatched `_cmdr_session`, retry it with the id given in the error message; that id is always this session's current id (resuming a conversation never changes it).
|
|
12
|
+
- Use the value only for `_cmdr_session`; it identifies this session to the local cmdr daemon and is not a credential for anything else.
|
|
@@ -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
|
|
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
|
|
|
@@ -15,6 +15,8 @@ Read delivers a message, not task acceptance or completion. Acknowledge a comman
|
|
|
15
15
|
|
|
16
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
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.
|
|
18
|
+
For Claude/ZCode/Kimi, 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.
|
|
@@ -6,7 +6,9 @@
|
|
|
6
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
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
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
|
|
9
|
+
7. For Claude, ZCode or Kimi Code, 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 and Kimi Code: 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
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.
|