cmdr-mcp 0.3.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +45 -6
- package/docs/README.zh-CN.md +45 -6
- package/docs/agent-integration.md +4 -2
- package/docs/dashboard-plan.md +327 -0
- package/docs/dashboard.md +101 -0
- package/docs/implementation.md +31 -4
- package/docs/publishing.md +11 -9
- package/docs/setup.md +45 -0
- package/docs/troubleshooting.md +2 -2
- package/marketplace.json +1 -1
- package/package.json +11 -2
- package/plugins/cmdr/.claude-plugin/plugin.json +1 -1
- package/plugins/cmdr/.codex-plugin/plugin.json +1 -1
- package/plugins/cmdr/.zcode-plugin/plugin.json +1 -1
- package/plugins/cmdr/README.md +5 -1
- package/plugins/cmdr/THIRD_PARTY_NOTICES.txt +159 -0
- package/plugins/cmdr/bin/cmdr-check.mjs +3 -0
- package/plugins/cmdr/commands/cmdr.md +3 -1
- package/plugins/cmdr/dist/cli.mjs +1410 -57
- package/plugins/cmdr/dist/daemon.mjs +4734 -142
- 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 +2 -2
- package/plugins/cmdr/dist/integrity.json +21 -14
- package/plugins/cmdr/dist/mcp.mjs +140 -64
- package/plugins/cmdr/skills/cmdr/SKILL.md +22 -0
- package/plugins/cmdr/skills/cmdr/references/commander.md +14 -0
- package/plugins/cmdr/skills/cmdr/references/executor.md +13 -0
- package/plugins/cmdr/skills/cmdr/references/setup.md +15 -0
- package/plugins/cmdr/skills/cmdr-commander/SKILL.md +2 -0
- package/plugins/cmdr/skills/cmdr-executor/SKILL.md +2 -0
- 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.
|
|
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,25 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.5.0",
|
|
3
3
|
"files": {
|
|
4
|
-
".claude-plugin/plugin.json": "
|
|
5
|
-
".codex-plugin/plugin.json": "
|
|
4
|
+
".claude-plugin/plugin.json": "535aafc34ca6d592a4a9561c32f61a92935b21c8db404a9d9f4e76adb64deff2",
|
|
5
|
+
".codex-plugin/plugin.json": "99a07fd4edeaa98a198c5ae3b3b4b7269971d18a0aefb42f1ec2dba6d407f038",
|
|
6
6
|
".mcp.json": "34e310a2874c8fda625745672a54df19614f32dabd2be4013f8ce871260e88c4",
|
|
7
|
-
".zcode-plugin/plugin.json": "
|
|
8
|
-
"THIRD_PARTY_NOTICES.txt": "
|
|
7
|
+
".zcode-plugin/plugin.json": "ab0d963f66c8a07c90377eb7a60e10ef468dc2f1534390cd258cc33b71c2c2e5",
|
|
8
|
+
"THIRD_PARTY_NOTICES.txt": "061121858596143e1ec0609aeee0d45ec839e53f05a4b7c23a48ec7df33194fc",
|
|
9
9
|
"bin/cmdr": "be6ea6b84ce121738ca729e9c6dbfb87bbf349a84d251acc711e3ea11f8dd8fd",
|
|
10
|
-
"bin/cmdr-check.mjs": "
|
|
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": "
|
|
16
|
-
"dist/cli.mjs": "
|
|
17
|
-
"dist/daemon.mjs": "
|
|
18
|
-
"dist/
|
|
19
|
-
"dist/
|
|
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
|
|
22
|
-
"skills/cmdr
|
|
23
|
-
"skills/
|
|
24
|
+
"skills/cmdr/SKILL.md": "40ae18c875eb7973c36b041e65976b150675f31375eef04271b21faeea2576aa",
|
|
25
|
+
"skills/cmdr/references/commander.md": "addc597a95a6314d07610915d831aa002833b80f82554269d9ba4895b659b65d",
|
|
26
|
+
"skills/cmdr/references/executor.md": "d52b315c2129fbd9e6dd31bd04e73b08bcdb9eb8d9dd3b47eccce62f65a63d6e",
|
|
27
|
+
"skills/cmdr/references/setup.md": "2ba2db967820ee2ded81730a5ff02bf7306dd8d6c1480818bc8223210392be97",
|
|
28
|
+
"skills/cmdr-commander/SKILL.md": "5475dbc603f2ddd2e28c1ad8bf2cdee790f751e5d1476d0f49c3dc0930093b2d",
|
|
29
|
+
"skills/cmdr-executor/SKILL.md": "d53b0da281bcc9e4919efdd943a7b18eaec8a3da35424ba8e38b8c2cb536643e",
|
|
30
|
+
"skills/using-cmdr/SKILL.md": "70156e942eab0656be3bc39f084bdb05c6d3182c73f86a6d32f9f1d6fb6ed174"
|
|
24
31
|
}
|
|
25
32
|
}
|
|
@@ -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,
|
|
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
|
-
|
|
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.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
|
|
21813
|
+
const id2 = this.next++;
|
|
21740
21814
|
const cancel = (code) => {
|
|
21741
|
-
const p = this.pending.get(
|
|
21815
|
+
const p = this.pending.get(id2);
|
|
21742
21816
|
if (!p) return;
|
|
21743
|
-
this.pending.delete(
|
|
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(
|
|
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
|
|
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
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
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 nine cmdr MCP tools: join, list, send, report, ask, read, leave, task, artifact. 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.
|
|
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.
|
|
@@ -0,0 +1,14 @@
|
|
|
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.
|
|
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.
|
|
@@ -0,0 +1,13 @@
|
|
|
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.
|
|
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.
|
|
@@ -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.
|
|
@@ -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
|
|
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
|
-
|
|
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
|
|