cmdr-mcp 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +29 -6
- package/docs/README.zh-CN.md +29 -6
- package/docs/agent-integration.md +2 -2
- package/docs/dashboard-plan.md +327 -0
- package/docs/dashboard.md +101 -0
- package/docs/implementation.md +25 -4
- package/docs/publishing.md +10 -8
- package/docs/setup.md +1 -1
- package/docs/troubleshooting.md +2 -2
- package/marketplace.json +1 -1
- package/package.json +9 -1
- 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 +3 -1
- package/plugins/cmdr/THIRD_PARTY_NOTICES.txt +130 -0
- package/plugins/cmdr/bin/cmdr-check.mjs +3 -0
- package/plugins/cmdr/commands/cmdr.md +2 -0
- package/plugins/cmdr/dist/cli.mjs +121 -31
- package/plugins/cmdr/dist/daemon.mjs +4729 -137
- 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 +20 -17
- package/plugins/cmdr/dist/mcp.mjs +140 -64
- package/plugins/cmdr/skills/cmdr/SKILL.md +3 -1
- package/plugins/cmdr/skills/cmdr/references/commander.md +2 -0
- package/plugins/cmdr/skills/cmdr/references/executor.md +2 -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
|
@@ -240,26 +240,26 @@ var Rpc = class extends EventEmitter {
|
|
|
240
240
|
if (this.socket.destroyed) return Promise.reject(new CmdrError("DAEMON_UNAVAILABLE"));
|
|
241
241
|
if (signal?.aborted) return Promise.reject(new CmdrError("REQUEST_CANCELLED"));
|
|
242
242
|
return new Promise((resolve4, reject) => {
|
|
243
|
-
const
|
|
243
|
+
const id2 = this.next++;
|
|
244
244
|
const cancel = (code) => {
|
|
245
|
-
const p = this.pending.get(
|
|
245
|
+
const p = this.pending.get(id2);
|
|
246
246
|
if (!p) return;
|
|
247
|
-
this.pending.delete(
|
|
247
|
+
this.pending.delete(id2);
|
|
248
248
|
clearTimeout(p.timer);
|
|
249
249
|
p.cleanup();
|
|
250
|
-
this.notify("rpc.cancel", { id });
|
|
250
|
+
this.notify("rpc.cancel", { id: id2 });
|
|
251
251
|
reject(new CmdrError(code));
|
|
252
252
|
};
|
|
253
253
|
const abort = () => cancel("REQUEST_CANCELLED");
|
|
254
254
|
const timer = setTimeout(() => cancel("DAEMON_UNAVAILABLE"), timeout);
|
|
255
|
-
this.pending.set(
|
|
255
|
+
this.pending.set(id2, {
|
|
256
256
|
resolve: resolve4,
|
|
257
257
|
reject,
|
|
258
258
|
timer,
|
|
259
259
|
cleanup: () => signal?.removeEventListener("abort", abort)
|
|
260
260
|
});
|
|
261
261
|
signal?.addEventListener("abort", abort, { once: true });
|
|
262
|
-
this.send({ jsonrpc: "2.0", id, method, params });
|
|
262
|
+
this.send({ jsonrpc: "2.0", id: id2, method, params });
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
notify(method, params) {
|
|
@@ -271,7 +271,7 @@ var Rpc = class extends EventEmitter {
|
|
|
271
271
|
};
|
|
272
272
|
|
|
273
273
|
// src/shared/version.ts
|
|
274
|
-
var VERSION = true ? "0.
|
|
274
|
+
var VERSION = true ? "0.5.0" : MIN_CLIENT_VERSION;
|
|
275
275
|
var PROTOCOL = 1;
|
|
276
276
|
function newer(a, b) {
|
|
277
277
|
const x = a.split(".").map(Number), y = b.split(".").map(Number);
|
|
@@ -4664,8 +4664,70 @@ var coerce = {
|
|
|
4664
4664
|
};
|
|
4665
4665
|
var NEVER = INVALID;
|
|
4666
4666
|
|
|
4667
|
+
// src/shared/dashboard.ts
|
|
4668
|
+
var DASHBOARD_LIMITS = {
|
|
4669
|
+
recordsPerKind: 200,
|
|
4670
|
+
runsPerTask: 100,
|
|
4671
|
+
htmlBytes: 256 * 1024,
|
|
4672
|
+
htmlBytesPerSquad: 8 * 1024 * 1024
|
|
4673
|
+
};
|
|
4674
|
+
|
|
4675
|
+
// src/shared/dashboard-schemas.ts
|
|
4676
|
+
var id = external_exports.string().min(1).max(128);
|
|
4677
|
+
var text = external_exports.string().max(8e3);
|
|
4678
|
+
var artifacts = external_exports.array(id).max(8);
|
|
4679
|
+
var taskFields = {
|
|
4680
|
+
action: external_exports.enum(["create", "update", "get", "list", "archive", "restore"]).default("list"),
|
|
4681
|
+
id: id.optional(),
|
|
4682
|
+
title: external_exports.string().trim().min(1).max(200).optional(),
|
|
4683
|
+
description: text.optional(),
|
|
4684
|
+
acceptance: text.optional(),
|
|
4685
|
+
position: external_exports.number().finite().optional(),
|
|
4686
|
+
artifact_ids: artifacts.optional(),
|
|
4687
|
+
archived: external_exports.boolean().optional(),
|
|
4688
|
+
offset: external_exports.number().int().min(0).default(0),
|
|
4689
|
+
limit: external_exports.number().int().min(1).max(50).default(20)
|
|
4690
|
+
};
|
|
4691
|
+
var questionFields = {
|
|
4692
|
+
target: external_exports.enum(["commander", "user"]).default("commander"),
|
|
4693
|
+
action: external_exports.enum(["create", "update", "get", "list", "withdraw", "handle"]).default("create"),
|
|
4694
|
+
id: id.optional(),
|
|
4695
|
+
task_id: id.optional(),
|
|
4696
|
+
version: external_exports.number().int().positive().optional(),
|
|
4697
|
+
description: text.optional(),
|
|
4698
|
+
kind: external_exports.enum(["single", "multiple", "text", "confirm"]).optional(),
|
|
4699
|
+
options: external_exports.array(external_exports.object({ id, label: external_exports.string().trim().min(1).max(300) }).strict()).max(20).optional(),
|
|
4700
|
+
artifact_ids: artifacts.optional(),
|
|
4701
|
+
result: text.optional(),
|
|
4702
|
+
status: external_exports.enum(["pending", "answered", "handled", "withdrawn"]).optional(),
|
|
4703
|
+
offset: external_exports.number().int().min(0).default(0),
|
|
4704
|
+
limit: external_exports.number().int().min(1).max(50).default(20)
|
|
4705
|
+
};
|
|
4706
|
+
var artifactFields = {
|
|
4707
|
+
action: external_exports.enum(["publish", "get", "list"]).default("publish"),
|
|
4708
|
+
id: id.optional(),
|
|
4709
|
+
version: external_exports.number().int().positive().optional(),
|
|
4710
|
+
title: external_exports.string().trim().min(1).max(200).optional(),
|
|
4711
|
+
html: external_exports.string().min(1).refine((s) => Buffer.byteLength(s) <= DASHBOARD_LIMITS.htmlBytes, "MESSAGE_TOO_LARGE").optional(),
|
|
4712
|
+
offset: external_exports.number().int().min(0).default(0),
|
|
4713
|
+
limit: external_exports.number().int().min(1).max(50).default(20)
|
|
4714
|
+
};
|
|
4715
|
+
var answerSchema = external_exports.object({
|
|
4716
|
+
question_id: id,
|
|
4717
|
+
version: external_exports.number().int().positive(),
|
|
4718
|
+
submission_id: external_exports.string().uuid(),
|
|
4719
|
+
selected: external_exports.array(id).max(20).default([]),
|
|
4720
|
+
text: text.default(""),
|
|
4721
|
+
confirmed: external_exports.boolean().optional()
|
|
4722
|
+
}).strict();
|
|
4723
|
+
var userMessageSchema = external_exports.object({
|
|
4724
|
+
squad_id: id,
|
|
4725
|
+
submission_id: external_exports.string().uuid(),
|
|
4726
|
+
text: external_exports.string().trim().min(1).max(8e3)
|
|
4727
|
+
}).strict();
|
|
4728
|
+
|
|
4667
4729
|
// src/shared/schemas.ts
|
|
4668
|
-
var
|
|
4730
|
+
var text2 = external_exports.string().min(1).refine((v) => Buffer.byteLength(v) <= LIMITS.maxBody, "MESSAGE_TOO_LARGE");
|
|
4669
4731
|
var data = external_exports.record(external_exports.unknown()).refine((v) => Buffer.byteLength(JSON.stringify(v)) <= LIMITS.maxData, "MESSAGE_TOO_LARGE").optional();
|
|
4670
4732
|
var wait = external_exports.number().min(0).max(300).default(0);
|
|
4671
4733
|
var identity = { _cmdr_session: external_exports.string().min(1).max(256).optional() };
|
|
@@ -4675,7 +4737,7 @@ var schemas = {
|
|
|
4675
4737
|
role: external_exports.enum(["commander", "executor"]).optional(),
|
|
4676
4738
|
squad: external_exports.string().optional(),
|
|
4677
4739
|
name: external_exports.string().trim().min(1).max(64).optional(),
|
|
4678
|
-
note:
|
|
4740
|
+
note: text2.optional(),
|
|
4679
4741
|
squad_name: external_exports.string().trim().min(1).max(64).optional(),
|
|
4680
4742
|
takeover: external_exports.boolean().default(false),
|
|
4681
4743
|
standby: external_exports.enum(["auto", "manual"]).optional(),
|
|
@@ -4690,17 +4752,27 @@ var schemas = {
|
|
|
4690
4752
|
report: external_exports.object({
|
|
4691
4753
|
...identity,
|
|
4692
4754
|
status: external_exports.enum(["ready", "working", "blocked", "done", "failed", "cancelled"]),
|
|
4693
|
-
message:
|
|
4755
|
+
message: text2,
|
|
4756
|
+
reply_to: external_exports.string().optional(),
|
|
4757
|
+
data
|
|
4758
|
+
}).strict(),
|
|
4759
|
+
ask: external_exports.object({
|
|
4760
|
+
...identity,
|
|
4761
|
+
...questionFields,
|
|
4762
|
+
question: text2.optional(),
|
|
4763
|
+
wait,
|
|
4694
4764
|
reply_to: external_exports.string().optional(),
|
|
4695
4765
|
data
|
|
4696
4766
|
}).strict(),
|
|
4697
|
-
|
|
4767
|
+
task: external_exports.object({ ...identity, ...taskFields }).strict(),
|
|
4768
|
+
artifact: external_exports.object({ ...identity, ...artifactFields }).strict(),
|
|
4698
4769
|
send: external_exports.object({
|
|
4699
4770
|
...identity,
|
|
4700
4771
|
to: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).min(1).max(1e3)]),
|
|
4701
|
-
message:
|
|
4772
|
+
message: text2,
|
|
4702
4773
|
type: external_exports.enum(["command", "cancel", "answer", "info"]).default("command"),
|
|
4703
4774
|
task_key: external_exports.string().min(1).max(128).optional(),
|
|
4775
|
+
task_id: external_exports.string().min(1).max(128).optional(),
|
|
4704
4776
|
reassign: external_exports.string().optional(),
|
|
4705
4777
|
attention: external_exports.boolean().optional(),
|
|
4706
4778
|
priority: external_exports.enum(["high", "normal", "low"]).optional(),
|
|
@@ -4718,7 +4790,7 @@ var schemas = {
|
|
|
4718
4790
|
recover: external_exports.boolean().default(false),
|
|
4719
4791
|
full: external_exports.boolean().default(false)
|
|
4720
4792
|
}).strict(),
|
|
4721
|
-
leave: external_exports.object({ ...identity, dissolve: external_exports.boolean().default(false), message:
|
|
4793
|
+
leave: external_exports.object({ ...identity, dissolve: external_exports.boolean().default(false), message: text2.optional() }).strict()
|
|
4722
4794
|
};
|
|
4723
4795
|
function parse(tool, args) {
|
|
4724
4796
|
const r = schemas[tool].safeParse(args);
|
|
@@ -4738,7 +4810,9 @@ var methods = {
|
|
|
4738
4810
|
report: "msg.report",
|
|
4739
4811
|
ask: "msg.ask",
|
|
4740
4812
|
read: "msg.read",
|
|
4741
|
-
leave: "session.leave"
|
|
4813
|
+
leave: "session.leave",
|
|
4814
|
+
task: "dashboard.task",
|
|
4815
|
+
artifact: "dashboard.artifact"
|
|
4742
4816
|
};
|
|
4743
4817
|
|
|
4744
4818
|
// src/shared/env.ts
|
|
@@ -4787,6 +4861,7 @@ async function runSession(argv) {
|
|
|
4787
4861
|
"reply-to": { type: "string" },
|
|
4788
4862
|
priority: { type: "string" },
|
|
4789
4863
|
"task-key": { type: "string" },
|
|
4864
|
+
"task-id": { type: "string" },
|
|
4790
4865
|
reassign: { type: "string" },
|
|
4791
4866
|
rebind: { type: "string" },
|
|
4792
4867
|
takeover: { type: "boolean" },
|
|
@@ -4804,13 +4879,13 @@ async function runSession(argv) {
|
|
|
4804
4879
|
});
|
|
4805
4880
|
if (v.help) {
|
|
4806
4881
|
console.log(
|
|
4807
|
-
"cmdr session join|list|send|report|ask|read|leave --agent HOST --native-id ID [--input JSON] [--timeout SECONDS]\nUse --squad-name for join; --status and text for report; --to and text for send; text for ask. read supports --wait/--peek/--history. IDs must match the host session; read also supports --recover/--id/--full/--limit. Configure automatic wake with cmdr standby start --session SID; unsupported hosts remain manual."
|
|
4882
|
+
"cmdr session join|list|send|report|ask|read|leave|task|artifact --agent HOST --native-id ID [--input JSON] [--timeout SECONDS]\nUse --squad-name for join; --status and text for report; --to and text for send; text for ask. read supports --wait/--peek/--history. IDs must match the host session; read also supports --recover/--id/--full/--limit. Configure automatic wake with cmdr standby start --session SID; unsupported hosts remain manual."
|
|
4808
4883
|
);
|
|
4809
4884
|
return;
|
|
4810
4885
|
}
|
|
4811
4886
|
const action = args[0];
|
|
4812
4887
|
if (!Object.hasOwn(schemas, action))
|
|
4813
|
-
throw new Error("Expected session join|list|send|report|ask|read|leave");
|
|
4888
|
+
throw new Error("Expected session join|list|send|report|ask|read|leave|task|artifact");
|
|
4814
4889
|
const agent = v.agent || process.env.CMDR_AGENT;
|
|
4815
4890
|
const native = v["native-id"] || process.env.CMDR_SESSION_ID;
|
|
4816
4891
|
if (!agent || !/^[a-z][a-z0-9_-]{0,63}$/.test(agent))
|
|
@@ -4837,6 +4912,7 @@ async function runSession(argv) {
|
|
|
4837
4912
|
"reply-to": "reply_to",
|
|
4838
4913
|
priority: "priority",
|
|
4839
4914
|
"task-key": "task_key",
|
|
4915
|
+
"task-id": "task_id",
|
|
4840
4916
|
reassign: "reassign",
|
|
4841
4917
|
rebind: "rebind",
|
|
4842
4918
|
takeover: "takeover",
|
|
@@ -4952,9 +5028,9 @@ async function probeMcp(root) {
|
|
|
4952
5028
|
reject(new Error("MCP exited"));
|
|
4953
5029
|
return;
|
|
4954
5030
|
}
|
|
4955
|
-
const
|
|
4956
|
-
pending.set(
|
|
4957
|
-
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
5031
|
+
const id2 = ++requestId;
|
|
5032
|
+
pending.set(id2, { resolve: resolve4, reject });
|
|
5033
|
+
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: id2, method, params }) + "\n");
|
|
4958
5034
|
});
|
|
4959
5035
|
let timer;
|
|
4960
5036
|
try {
|
|
@@ -4970,8 +5046,8 @@ async function probeMcp(root) {
|
|
|
4970
5046
|
);
|
|
4971
5047
|
const result = await request("tools/list", {});
|
|
4972
5048
|
const names = result.tools?.map((t) => t.name).sort();
|
|
4973
|
-
if (JSON.stringify(names) !== JSON.stringify(
|
|
4974
|
-
throw new Error("
|
|
5049
|
+
if (JSON.stringify(names) !== JSON.stringify(Object.keys(schemas).sort()))
|
|
5050
|
+
throw new Error("Unexpected cmdr tool set");
|
|
4975
5051
|
const call = await request("tools/call", { name: "list", arguments: {} });
|
|
4976
5052
|
if (call.isError) throw new Error("MCP tool cannot reach daemon");
|
|
4977
5053
|
return { ok: true, tools: names, isolated: true };
|
|
@@ -5837,9 +5913,9 @@ function object(value, label) {
|
|
|
5837
5913
|
throw new Error(`${label} must be an object; no configuration was changed.`);
|
|
5838
5914
|
return value;
|
|
5839
5915
|
}
|
|
5840
|
-
function jsonConfig(
|
|
5916
|
+
function jsonConfig(text3, label) {
|
|
5841
5917
|
try {
|
|
5842
|
-
return object(JSON.parse(
|
|
5918
|
+
return object(JSON.parse(text3 || "{}"), label);
|
|
5843
5919
|
} catch {
|
|
5844
5920
|
throw new Error(`Cannot parse ${label} as a JSON object; no configuration was changed.`);
|
|
5845
5921
|
}
|
|
@@ -5876,10 +5952,10 @@ function mergeJsonServer(config, command, host) {
|
|
|
5876
5952
|
const servers = parent[key] = object(parent[key] ?? {}, key);
|
|
5877
5953
|
servers.cmdr = serverConfig(servers.cmdr, command, host);
|
|
5878
5954
|
}
|
|
5879
|
-
function codexConfig(
|
|
5955
|
+
function codexConfig(text3, command) {
|
|
5880
5956
|
let config;
|
|
5881
5957
|
try {
|
|
5882
|
-
config = parse2(
|
|
5958
|
+
config = parse2(text3, { integersAsBigInt: "asNeeded" });
|
|
5883
5959
|
} catch {
|
|
5884
5960
|
throw new Error("Cannot parse Codex config.toml; no configuration was changed.");
|
|
5885
5961
|
}
|
|
@@ -5888,20 +5964,20 @@ function codexConfig(text2, command) {
|
|
|
5888
5964
|
const server = serverConfig(servers.cmdr, command, "codex");
|
|
5889
5965
|
const block = `${begin}
|
|
5890
5966
|
${stringify({ mcp_servers: { cmdr: server } })}${end}`;
|
|
5891
|
-
const start =
|
|
5967
|
+
const start = text3.indexOf(begin), stop = text3.indexOf(end);
|
|
5892
5968
|
let output;
|
|
5893
5969
|
if (start >= 0 || stop >= 0) {
|
|
5894
|
-
if (start < 0 || stop < start ||
|
|
5970
|
+
if (start < 0 || stop < start || text3.indexOf(begin, start + begin.length) >= 0 || text3.indexOf(end, stop + end.length) >= 0)
|
|
5895
5971
|
throw new Error(
|
|
5896
5972
|
"Invalid cmdr setup markers in config.toml. Restore the managed block before retrying."
|
|
5897
5973
|
);
|
|
5898
|
-
output =
|
|
5974
|
+
output = text3.slice(0, start) + block + text3.slice(stop + end.length);
|
|
5899
5975
|
} else {
|
|
5900
5976
|
if (servers.cmdr !== void 0)
|
|
5901
5977
|
throw new Error(
|
|
5902
5978
|
"The cmdr MCP entry is not managed by setup. Remove that entry before retrying."
|
|
5903
5979
|
);
|
|
5904
|
-
output = `${
|
|
5980
|
+
output = `${text3}${text3 && !text3.endsWith("\n") ? "\n" : ""}
|
|
5905
5981
|
${block}
|
|
5906
5982
|
`;
|
|
5907
5983
|
}
|
|
@@ -6314,6 +6390,7 @@ if (process.argv[2] === "setup") {
|
|
|
6314
6390
|
follow: { type: "boolean" },
|
|
6315
6391
|
full: { type: "boolean" },
|
|
6316
6392
|
json: { type: "boolean" },
|
|
6393
|
+
"no-open": { type: "boolean" },
|
|
6317
6394
|
help: { type: "boolean" }
|
|
6318
6395
|
}
|
|
6319
6396
|
});
|
|
@@ -6404,9 +6481,22 @@ if (process.argv[2] === "setup") {
|
|
|
6404
6481
|
try {
|
|
6405
6482
|
if (v.help)
|
|
6406
6483
|
process.stdout.write(
|
|
6407
|
-
"cmdr status | setup --agent claude-code|codex|zcode [--dry-run] [--json] | list [--all] [--squad ID] | tail [--follow] [--full] [--json] [--after EVENT_SEQ|now] [--actionable] [--format line|json] [--for SID] | standby start|status|stop|resume|watch --session SID [--adapter codex|claude|zcode|manual] [--transport auto|proxy|queue] [--once] | send --squad ID [--to MEMBER] [--type command|cancel|info|answer] TEXT | read --session SID [--peek] | daemon start|stop|restart|status|logs | config [--agent HOST] [--session ID] | doctor [--plugin-root PATH] [--deep] | session --help | purge [--all]\n"
|
|
6484
|
+
"cmdr status | dashboard [--no-open] [--json] | setup --agent claude-code|codex|zcode [--dry-run] [--json] | list [--all] [--squad ID] | tail [--follow] [--full] [--json] [--after EVENT_SEQ|now] [--actionable] [--format line|json] [--for SID] | standby start|status|stop|resume|watch --session SID [--adapter codex|claude|zcode|manual] [--transport auto|proxy|queue] [--once] | send --squad ID [--to MEMBER] [--type command|cancel|info|answer] TEXT | read --session SID [--peek] | daemon start|stop|restart|status|logs | config [--agent HOST] [--session ID] | doctor [--plugin-root PATH] [--deep] | session --help | purge [--all]\n"
|
|
6408
6485
|
);
|
|
6409
|
-
else if (cmd === "
|
|
6486
|
+
else if (cmd === "dashboard") {
|
|
6487
|
+
const result = await call("admin.dashboard", {}, true);
|
|
6488
|
+
print(result);
|
|
6489
|
+
if (!v["no-open"]) {
|
|
6490
|
+
try {
|
|
6491
|
+
execFileSync(process.platform === "darwin" ? "open" : "xdg-open", [result.url], {
|
|
6492
|
+
stdio: "ignore",
|
|
6493
|
+
timeout: 5e3
|
|
6494
|
+
});
|
|
6495
|
+
} catch {
|
|
6496
|
+
console.error("Open the printed URL in a local browser (valid for 60 seconds).");
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
} else if (cmd === "config") {
|
|
6410
6500
|
const agent = v.agent || "generic";
|
|
6411
6501
|
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(agent))
|
|
6412
6502
|
throw new Error("Invalid --agent: use lowercase letters, digits, underscores or hyphens.");
|