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
|
@@ -239,27 +239,27 @@ var Rpc = class extends EventEmitter {
|
|
|
239
239
|
request(method, params = {}, timeout = 5e3, signal) {
|
|
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
|
-
return new Promise((
|
|
243
|
-
const
|
|
242
|
+
return new Promise((resolve4, reject) => {
|
|
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(
|
|
256
|
-
resolve:
|
|
255
|
+
this.pending.set(id2, {
|
|
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);
|
|
@@ -284,7 +284,7 @@ function newer(a, b) {
|
|
|
284
284
|
// src/shared/client.ts
|
|
285
285
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
286
286
|
async function dial(p, timeout = 1e3) {
|
|
287
|
-
return new Promise((
|
|
287
|
+
return new Promise((resolve4, reject) => {
|
|
288
288
|
const socket = connect(p.socket);
|
|
289
289
|
const timer = setTimeout(() => socket.destroy(new Error("connect timeout")), timeout);
|
|
290
290
|
socket.once("error", (e) => {
|
|
@@ -293,7 +293,7 @@ async function dial(p, timeout = 1e3) {
|
|
|
293
293
|
});
|
|
294
294
|
socket.once("connect", () => {
|
|
295
295
|
clearTimeout(timer);
|
|
296
|
-
|
|
296
|
+
resolve4(new Rpc(socket));
|
|
297
297
|
});
|
|
298
298
|
});
|
|
299
299
|
}
|
|
@@ -473,9 +473,9 @@ async function watch(sid, once = false) {
|
|
|
473
473
|
process.on("SIGINT", stop);
|
|
474
474
|
process.on("SIGTERM", stop);
|
|
475
475
|
const closed = new Promise(
|
|
476
|
-
(
|
|
476
|
+
(resolve4) => rpc.once("close", () => {
|
|
477
477
|
if (!stopped) error ||= new Error("cmdr daemon disconnected; re-arm the host watcher");
|
|
478
|
-
|
|
478
|
+
resolve4();
|
|
479
479
|
})
|
|
480
480
|
);
|
|
481
481
|
const show = (result, initial = false) => {
|
|
@@ -570,7 +570,7 @@ async function tail(options) {
|
|
|
570
570
|
do {
|
|
571
571
|
try {
|
|
572
572
|
const rpc = connection = await daemonConnection();
|
|
573
|
-
const closed = new Promise((
|
|
573
|
+
const closed = new Promise((resolve4) => rpc.once("close", resolve4));
|
|
574
574
|
await rpc.request("session.register", { kind: "cli" });
|
|
575
575
|
let replaying = true;
|
|
576
576
|
const buffer = [];
|
|
@@ -767,10 +767,10 @@ var util;
|
|
|
767
767
|
return obj[e];
|
|
768
768
|
});
|
|
769
769
|
};
|
|
770
|
-
util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (
|
|
770
|
+
util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object2) => {
|
|
771
771
|
const keys = [];
|
|
772
|
-
for (const key in
|
|
773
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
772
|
+
for (const key in object2) {
|
|
773
|
+
if (Object.prototype.hasOwnProperty.call(object2, key)) {
|
|
774
774
|
keys.push(key);
|
|
775
775
|
}
|
|
776
776
|
}
|
|
@@ -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",
|
|
@@ -4947,14 +5023,14 @@ async function probeMcp(root) {
|
|
|
4947
5023
|
fail2();
|
|
4948
5024
|
}
|
|
4949
5025
|
});
|
|
4950
|
-
const request = (method, params) => new Promise((
|
|
5026
|
+
const request = (method, params) => new Promise((resolve4, reject) => {
|
|
4951
5027
|
if (closed || child.exitCode !== null || child.signalCode !== null) {
|
|
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 };
|
|
@@ -4986,15 +5062,15 @@ async function probeMcp(root) {
|
|
|
4986
5062
|
clearTimeout(timer);
|
|
4987
5063
|
child.stdin.end();
|
|
4988
5064
|
child.kill("SIGTERM");
|
|
4989
|
-
await new Promise((
|
|
4990
|
-
if (child.exitCode !== null || child.signalCode !== null) return
|
|
5065
|
+
await new Promise((resolve4) => {
|
|
5066
|
+
if (child.exitCode !== null || child.signalCode !== null) return resolve4();
|
|
4991
5067
|
const t = setTimeout(() => {
|
|
4992
5068
|
child.kill("SIGKILL");
|
|
4993
|
-
|
|
5069
|
+
resolve4();
|
|
4994
5070
|
}, 1e3);
|
|
4995
5071
|
child.once("close", () => {
|
|
4996
5072
|
clearTimeout(t);
|
|
4997
|
-
|
|
5073
|
+
resolve4();
|
|
4998
5074
|
});
|
|
4999
5075
|
});
|
|
5000
5076
|
lines.close();
|
|
@@ -5009,16 +5085,1279 @@ async function probeMcp(root) {
|
|
|
5009
5085
|
}
|
|
5010
5086
|
|
|
5011
5087
|
// src/cli/main.ts
|
|
5012
|
-
import { readFileSync as
|
|
5013
|
-
import { dirname as
|
|
5014
|
-
import { homedir as
|
|
5088
|
+
import { readFileSync as readFileSync5, existsSync as existsSync3 } from "node:fs";
|
|
5089
|
+
import { dirname as dirname3, join as join7, resolve as resolve3 } from "node:path";
|
|
5090
|
+
import { homedir as homedir3 } from "node:os";
|
|
5015
5091
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
5016
5092
|
import { execFileSync } from "node:child_process";
|
|
5093
|
+
import { parseArgs as parseArgs3 } from "node:util";
|
|
5094
|
+
|
|
5095
|
+
// src/cli/setup.ts
|
|
5096
|
+
import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
|
|
5097
|
+
import {
|
|
5098
|
+
cpSync as cpSync2,
|
|
5099
|
+
existsSync as existsSync2,
|
|
5100
|
+
mkdirSync as mkdirSync5,
|
|
5101
|
+
readFileSync as readFileSync4,
|
|
5102
|
+
realpathSync,
|
|
5103
|
+
renameSync as renameSync3,
|
|
5104
|
+
rmSync as rmSync5,
|
|
5105
|
+
writeFileSync as writeFileSync3
|
|
5106
|
+
} from "node:fs";
|
|
5107
|
+
import { homedir as homedir2 } from "node:os";
|
|
5108
|
+
import { join as join6, resolve as resolve2 } from "node:path";
|
|
5017
5109
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
5018
|
-
|
|
5110
|
+
|
|
5111
|
+
// src/cli/setup-config.ts
|
|
5112
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5113
|
+
|
|
5114
|
+
// node_modules/smol-toml/dist/date.js
|
|
5115
|
+
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
5116
|
+
var TomlDate = class _TomlDate extends Date {
|
|
5117
|
+
#hasDate = false;
|
|
5118
|
+
#hasTime = false;
|
|
5119
|
+
#offset = null;
|
|
5120
|
+
constructor(date) {
|
|
5121
|
+
let hasDate = true;
|
|
5122
|
+
let hasTime = true;
|
|
5123
|
+
let offset = "Z";
|
|
5124
|
+
if (typeof date === "string") {
|
|
5125
|
+
let match = date.match(DATE_TIME_RE);
|
|
5126
|
+
if (match) {
|
|
5127
|
+
if (!match[1]) {
|
|
5128
|
+
hasDate = false;
|
|
5129
|
+
date = `0000-01-01T${date}`;
|
|
5130
|
+
}
|
|
5131
|
+
hasTime = !!match[2];
|
|
5132
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
5133
|
+
if (match[2] && +match[2] > 23) {
|
|
5134
|
+
date = "";
|
|
5135
|
+
} else {
|
|
5136
|
+
offset = match[3] || null;
|
|
5137
|
+
date = date.toUpperCase();
|
|
5138
|
+
if (!offset && hasTime)
|
|
5139
|
+
date += "Z";
|
|
5140
|
+
}
|
|
5141
|
+
} else {
|
|
5142
|
+
date = "";
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
super(date);
|
|
5146
|
+
if (!isNaN(this.getTime())) {
|
|
5147
|
+
this.#hasDate = hasDate;
|
|
5148
|
+
this.#hasTime = hasTime;
|
|
5149
|
+
this.#offset = offset;
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
isDateTime() {
|
|
5153
|
+
return this.#hasDate && this.#hasTime;
|
|
5154
|
+
}
|
|
5155
|
+
isLocal() {
|
|
5156
|
+
return !this.#hasDate || !this.#hasTime || !this.#offset;
|
|
5157
|
+
}
|
|
5158
|
+
isDate() {
|
|
5159
|
+
return this.#hasDate && !this.#hasTime;
|
|
5160
|
+
}
|
|
5161
|
+
isTime() {
|
|
5162
|
+
return this.#hasTime && !this.#hasDate;
|
|
5163
|
+
}
|
|
5164
|
+
isValid() {
|
|
5165
|
+
return this.#hasDate || this.#hasTime;
|
|
5166
|
+
}
|
|
5167
|
+
toISOString() {
|
|
5168
|
+
let iso = super.toISOString();
|
|
5169
|
+
if (this.isDate())
|
|
5170
|
+
return iso.slice(0, 10);
|
|
5171
|
+
if (this.isTime())
|
|
5172
|
+
return iso.slice(11, 23);
|
|
5173
|
+
if (this.#offset === null)
|
|
5174
|
+
return iso.slice(0, -1);
|
|
5175
|
+
if (this.#offset === "Z")
|
|
5176
|
+
return iso;
|
|
5177
|
+
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
5178
|
+
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
5179
|
+
let offsetDate = new Date(this.getTime() - offset * 6e4);
|
|
5180
|
+
return offsetDate.toISOString().slice(0, -1) + this.#offset;
|
|
5181
|
+
}
|
|
5182
|
+
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
|
|
5183
|
+
let date = new _TomlDate(jsDate);
|
|
5184
|
+
date.#offset = offset;
|
|
5185
|
+
return date;
|
|
5186
|
+
}
|
|
5187
|
+
static wrapAsLocalDateTime(jsDate) {
|
|
5188
|
+
let date = new _TomlDate(jsDate);
|
|
5189
|
+
date.#offset = null;
|
|
5190
|
+
return date;
|
|
5191
|
+
}
|
|
5192
|
+
static wrapAsLocalDate(jsDate) {
|
|
5193
|
+
let date = new _TomlDate(jsDate);
|
|
5194
|
+
date.#hasTime = false;
|
|
5195
|
+
date.#offset = null;
|
|
5196
|
+
return date;
|
|
5197
|
+
}
|
|
5198
|
+
static wrapAsLocalTime(jsDate) {
|
|
5199
|
+
let date = new _TomlDate(jsDate);
|
|
5200
|
+
date.#hasDate = false;
|
|
5201
|
+
date.#offset = null;
|
|
5202
|
+
return date;
|
|
5203
|
+
}
|
|
5204
|
+
};
|
|
5205
|
+
|
|
5206
|
+
// node_modules/smol-toml/dist/error.js
|
|
5207
|
+
function getLineColFromPtr(string, ptr) {
|
|
5208
|
+
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
5209
|
+
return [lines.length, lines.pop().length + 1];
|
|
5210
|
+
}
|
|
5211
|
+
function makeCodeBlock(string, line, column) {
|
|
5212
|
+
let lines = string.split(/\r\n|\n|\r/g);
|
|
5213
|
+
let codeblock = "";
|
|
5214
|
+
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
5215
|
+
for (let i = line - 1; i <= line + 1; i++) {
|
|
5216
|
+
let l = lines[i - 1];
|
|
5217
|
+
if (!l)
|
|
5218
|
+
continue;
|
|
5219
|
+
codeblock += i.toString().padEnd(numberLen, " ");
|
|
5220
|
+
codeblock += ": ";
|
|
5221
|
+
codeblock += l;
|
|
5222
|
+
codeblock += "\n";
|
|
5223
|
+
if (i === line) {
|
|
5224
|
+
codeblock += " ".repeat(numberLen + column + 2);
|
|
5225
|
+
codeblock += "^\n";
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
return codeblock;
|
|
5229
|
+
}
|
|
5230
|
+
var TomlError = class extends Error {
|
|
5231
|
+
line;
|
|
5232
|
+
column;
|
|
5233
|
+
codeblock;
|
|
5234
|
+
constructor(message, options) {
|
|
5235
|
+
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
|
|
5236
|
+
const codeblock = makeCodeBlock(options.toml, line, column);
|
|
5237
|
+
super(`Invalid TOML document: ${message}
|
|
5238
|
+
|
|
5239
|
+
${codeblock}`, options);
|
|
5240
|
+
this.line = line;
|
|
5241
|
+
this.column = column;
|
|
5242
|
+
this.codeblock = codeblock;
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
|
|
5246
|
+
// node_modules/smol-toml/dist/util.js
|
|
5247
|
+
function indexOfNewline(str, start = 0) {
|
|
5248
|
+
let idx = str.indexOf("\n", start);
|
|
5249
|
+
if (str.charCodeAt(idx - 1) === 13)
|
|
5250
|
+
idx--;
|
|
5251
|
+
return idx;
|
|
5252
|
+
}
|
|
5253
|
+
function skipComment(ctx) {
|
|
5254
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
5255
|
+
let c = ctx.s.charCodeAt(ctx.p);
|
|
5256
|
+
if (c === 10)
|
|
5257
|
+
break;
|
|
5258
|
+
if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
|
|
5259
|
+
ctx.p++;
|
|
5260
|
+
break;
|
|
5261
|
+
}
|
|
5262
|
+
if (c < 32 && c !== 9 || c === 127) {
|
|
5263
|
+
throw new TomlError("control characters are not allowed in comments", {
|
|
5264
|
+
toml: ctx.s,
|
|
5265
|
+
ptr: ctx.p
|
|
5266
|
+
});
|
|
5267
|
+
}
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
function skipVoid(ctx, banNewLines, banComments) {
|
|
5271
|
+
let c;
|
|
5272
|
+
while (1) {
|
|
5273
|
+
while ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10))
|
|
5274
|
+
ctx.p++;
|
|
5275
|
+
if (banComments || c !== 35)
|
|
5276
|
+
break;
|
|
5277
|
+
skipComment(ctx);
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
function skipUntil(ctx, sep, end2) {
|
|
5281
|
+
let ptr = ctx.p;
|
|
5282
|
+
if (!end2) {
|
|
5283
|
+
ptr = indexOfNewline(ctx.s, ptr);
|
|
5284
|
+
ctx.p = ptr < 0 ? ctx.s.length : ptr;
|
|
5285
|
+
return;
|
|
5286
|
+
}
|
|
5287
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
5288
|
+
let c = ctx.s.charCodeAt(ctx.p);
|
|
5289
|
+
if (c === 35) {
|
|
5290
|
+
skipComment(ctx);
|
|
5291
|
+
} else if (c === end2 || c === sep) {
|
|
5292
|
+
return;
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
throw new TomlError("cannot find end of structure", {
|
|
5296
|
+
toml: ctx.s,
|
|
5297
|
+
ptr
|
|
5298
|
+
});
|
|
5299
|
+
}
|
|
5300
|
+
|
|
5301
|
+
// node_modules/smol-toml/dist/primitive.js
|
|
5302
|
+
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
|
5303
|
+
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
|
5304
|
+
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
5305
|
+
function parseString(ctx) {
|
|
5306
|
+
let start = ctx.p;
|
|
5307
|
+
let c = ctx.s.charCodeAt(ctx.p++);
|
|
5308
|
+
let first = c;
|
|
5309
|
+
let isLiteral = c === 39;
|
|
5310
|
+
let isMultiline = c === ctx.s.charCodeAt(ctx.p) && c === ctx.s.charCodeAt(ctx.p + 1);
|
|
5311
|
+
if (isMultiline) {
|
|
5312
|
+
if ((c = ctx.s.charCodeAt(ctx.p += 2)) === 10)
|
|
5313
|
+
ctx.p++;
|
|
5314
|
+
else if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)
|
|
5315
|
+
ctx.p += 2;
|
|
5316
|
+
}
|
|
5317
|
+
let parsed = "";
|
|
5318
|
+
let sliceStart = ctx.p;
|
|
5319
|
+
let state = 0;
|
|
5320
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
5321
|
+
c = ctx.s.charCodeAt(ctx.p);
|
|
5322
|
+
if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) {
|
|
5323
|
+
state = state && 3;
|
|
5324
|
+
} else if (c < 32 && c !== 9 || c === 127) {
|
|
5325
|
+
throw new TomlError("control characters are not allowed in strings", {
|
|
5326
|
+
toml: ctx.s,
|
|
5327
|
+
ptr: ctx.p
|
|
5328
|
+
});
|
|
5329
|
+
} else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
|
|
5330
|
+
if (isMultiline) {
|
|
5331
|
+
if (ctx.s.charCodeAt(ctx.p + 3) === first)
|
|
5332
|
+
ctx.p++;
|
|
5333
|
+
if (ctx.s.charCodeAt(ctx.p + 3) === first)
|
|
5334
|
+
ctx.p++;
|
|
5335
|
+
}
|
|
5336
|
+
if (!state)
|
|
5337
|
+
parsed += ctx.s.slice(sliceStart, ctx.p);
|
|
5338
|
+
ctx.p += isMultiline ? 3 : 1;
|
|
5339
|
+
return parsed;
|
|
5340
|
+
} else if (!state) {
|
|
5341
|
+
if (!isLiteral && c === 92) {
|
|
5342
|
+
parsed += ctx.s.slice(sliceStart, sliceStart = ctx.p);
|
|
5343
|
+
state = 1;
|
|
5344
|
+
}
|
|
5345
|
+
} else if (state === 1) {
|
|
5346
|
+
if (c === 120 || c === 117 || c === 85) {
|
|
5347
|
+
let value = 0;
|
|
5348
|
+
let len = c === 120 ? 2 : c === 117 ? 4 : 8;
|
|
5349
|
+
for (let j = 0; j < len; j++, ctx.p++) {
|
|
5350
|
+
let hex = ctx.s.charCodeAt(ctx.p + 1);
|
|
5351
|
+
let digit = (
|
|
5352
|
+
/* 0-9 */
|
|
5353
|
+
hex >= 48 && hex <= 57 ? hex - 48 : (
|
|
5354
|
+
/* A-F */
|
|
5355
|
+
hex >= 65 && hex <= 70 ? hex - 65 + 10 : (
|
|
5356
|
+
/* a-f */
|
|
5357
|
+
hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1
|
|
5358
|
+
)
|
|
5359
|
+
)
|
|
5360
|
+
);
|
|
5361
|
+
if (digit < 0)
|
|
5362
|
+
throw new TomlError("invalid non-hex character in unicode escape", { toml: ctx.s, ptr: ctx.p + 1 });
|
|
5363
|
+
value = value << 4 | digit;
|
|
5364
|
+
}
|
|
5365
|
+
if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
|
|
5366
|
+
throw new TomlError("invalid unicode escape", { toml: ctx.s, ptr: ctx.p });
|
|
5367
|
+
}
|
|
5368
|
+
parsed += String.fromCodePoint(value);
|
|
5369
|
+
sliceStart = ctx.p + 1;
|
|
5370
|
+
state = 0;
|
|
5371
|
+
} else if (c === 32 || c === 9) {
|
|
5372
|
+
state = 2;
|
|
5373
|
+
} else {
|
|
5374
|
+
if (c === 98)
|
|
5375
|
+
parsed += "\b";
|
|
5376
|
+
else if (c === 116)
|
|
5377
|
+
parsed += " ";
|
|
5378
|
+
else if (c === 110)
|
|
5379
|
+
parsed += "\n";
|
|
5380
|
+
else if (c === 102)
|
|
5381
|
+
parsed += "\f";
|
|
5382
|
+
else if (c === 114)
|
|
5383
|
+
parsed += "\r";
|
|
5384
|
+
else if (c === 101)
|
|
5385
|
+
parsed += "\x1B";
|
|
5386
|
+
else if (c === 34)
|
|
5387
|
+
parsed += '"';
|
|
5388
|
+
else if (c === 92)
|
|
5389
|
+
parsed += "\\";
|
|
5390
|
+
else
|
|
5391
|
+
throw new TomlError("unrecognized escape sequence", { toml: ctx.s, ptr: ctx.p });
|
|
5392
|
+
sliceStart = ctx.p + 1;
|
|
5393
|
+
state = 0;
|
|
5394
|
+
}
|
|
5395
|
+
} else if (c !== 32 && c !== 9) {
|
|
5396
|
+
if (state === 2) {
|
|
5397
|
+
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
5398
|
+
toml: ctx.s,
|
|
5399
|
+
ptr: sliceStart
|
|
5400
|
+
});
|
|
5401
|
+
}
|
|
5402
|
+
state = !isLiteral && c === 92 ? 1 : 0;
|
|
5403
|
+
sliceStart = ctx.p;
|
|
5404
|
+
}
|
|
5405
|
+
}
|
|
5406
|
+
throw new TomlError("unfinished string", { toml: ctx.s, ptr: start });
|
|
5407
|
+
}
|
|
5408
|
+
function sliceAndTrimEndOf(ctx, start, end2) {
|
|
5409
|
+
let value = ctx.s.slice(start, end2);
|
|
5410
|
+
let commentIdx = value.indexOf("#");
|
|
5411
|
+
if (commentIdx > 0) {
|
|
5412
|
+
skipComment({ s: value, p: commentIdx, d: 0 });
|
|
5413
|
+
value = value.slice(0, commentIdx);
|
|
5414
|
+
}
|
|
5415
|
+
return value.trimEnd();
|
|
5416
|
+
}
|
|
5417
|
+
function parseValue(ctx, integersAsBigInt, end2) {
|
|
5418
|
+
let ptr = ctx.p;
|
|
5419
|
+
let err = { toml: ctx.s, ptr };
|
|
5420
|
+
skipUntil(ctx, 44, end2);
|
|
5421
|
+
let value = sliceAndTrimEndOf(ctx, ptr, ctx.p);
|
|
5422
|
+
if (!value)
|
|
5423
|
+
throw new TomlError("incomplete declaration: value expected", err);
|
|
5424
|
+
if (value === "-inf")
|
|
5425
|
+
return -Infinity;
|
|
5426
|
+
if (value === "inf" || value === "+inf")
|
|
5427
|
+
return Infinity;
|
|
5428
|
+
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
5429
|
+
return NaN;
|
|
5430
|
+
if (value === "-0")
|
|
5431
|
+
return integersAsBigInt ? 0n : 0;
|
|
5432
|
+
let isInt = INT_REGEX.test(value);
|
|
5433
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
5434
|
+
if (LEADING_ZERO.test(value)) {
|
|
5435
|
+
throw new TomlError("leading zeroes are not allowed", err);
|
|
5436
|
+
}
|
|
5437
|
+
value = value.replace(/_/g, "");
|
|
5438
|
+
let numeric = +value;
|
|
5439
|
+
if (isNaN(numeric)) {
|
|
5440
|
+
throw new TomlError("invalid number", err);
|
|
5441
|
+
}
|
|
5442
|
+
if (isInt) {
|
|
5443
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
5444
|
+
throw new TomlError("integer value cannot be represented losslessly", err);
|
|
5445
|
+
}
|
|
5446
|
+
if (isInt || integersAsBigInt === true)
|
|
5447
|
+
numeric = BigInt(value);
|
|
5448
|
+
}
|
|
5449
|
+
return numeric;
|
|
5450
|
+
}
|
|
5451
|
+
const date = new TomlDate(value);
|
|
5452
|
+
if (!date.isValid())
|
|
5453
|
+
throw new TomlError("invalid value", err);
|
|
5454
|
+
return date;
|
|
5455
|
+
}
|
|
5456
|
+
|
|
5457
|
+
// node_modules/smol-toml/dist/extract.js
|
|
5458
|
+
function extractValue(ctx, end2, integersAsBigInt) {
|
|
5459
|
+
let ptr = ctx.p;
|
|
5460
|
+
let c = ctx.s.charCodeAt(ptr);
|
|
5461
|
+
if (c === 91 || c === 123) {
|
|
5462
|
+
if (!ctx.d--) {
|
|
5463
|
+
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
5464
|
+
toml: ctx.s,
|
|
5465
|
+
ptr
|
|
5466
|
+
});
|
|
5467
|
+
}
|
|
5468
|
+
let value = c === 91 ? parseArray(ctx, integersAsBigInt) : parseInlineTable(ctx, integersAsBigInt);
|
|
5469
|
+
ctx.d++;
|
|
5470
|
+
return value;
|
|
5471
|
+
}
|
|
5472
|
+
if (c === 34 || c === 39) {
|
|
5473
|
+
return parseString(ctx);
|
|
5474
|
+
}
|
|
5475
|
+
if (c === 116) {
|
|
5476
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101)
|
|
5477
|
+
throw new TomlError("invalid value", { toml: ctx.s, ptr });
|
|
5478
|
+
ctx.p++;
|
|
5479
|
+
return true;
|
|
5480
|
+
}
|
|
5481
|
+
if (c === 102) {
|
|
5482
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 108 || ctx.s.charCodeAt(++ctx.p) !== 115 || ctx.s.charCodeAt(++ctx.p) !== 101)
|
|
5483
|
+
throw new TomlError("invalid value", { toml: ctx.s, ptr });
|
|
5484
|
+
ctx.p++;
|
|
5485
|
+
return false;
|
|
5486
|
+
}
|
|
5487
|
+
return parseValue(ctx, integersAsBigInt, end2);
|
|
5488
|
+
}
|
|
5489
|
+
|
|
5490
|
+
// node_modules/smol-toml/dist/struct.js
|
|
5491
|
+
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
5492
|
+
function parseKey(ctx, end2 = "=") {
|
|
5493
|
+
let start = ctx.p;
|
|
5494
|
+
let dot = start - 1;
|
|
5495
|
+
let parsed = [];
|
|
5496
|
+
let endPtr = ctx.s.indexOf(end2, start);
|
|
5497
|
+
if (endPtr < 0) {
|
|
5498
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
5499
|
+
toml: ctx.s,
|
|
5500
|
+
ptr: start
|
|
5501
|
+
});
|
|
5502
|
+
}
|
|
5503
|
+
do {
|
|
5504
|
+
let c = ctx.s.charCodeAt(ctx.p = ++dot);
|
|
5505
|
+
if (c !== 32 && c !== 9) {
|
|
5506
|
+
if (c === 34 || c === 39) {
|
|
5507
|
+
if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2)) {
|
|
5508
|
+
throw new TomlError("multiline strings are not allowed in keys", {
|
|
5509
|
+
toml: ctx.s,
|
|
5510
|
+
ptr: ctx.p
|
|
5511
|
+
});
|
|
5512
|
+
}
|
|
5513
|
+
let part = parseString(ctx);
|
|
5514
|
+
dot = ctx.s.indexOf(".", ctx.p);
|
|
5515
|
+
let strEnd = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
5516
|
+
let newLine = indexOfNewline(strEnd);
|
|
5517
|
+
if (newLine > -1) {
|
|
5518
|
+
throw new TomlError("newlines are not allowed in keys", {
|
|
5519
|
+
toml: ctx.s,
|
|
5520
|
+
ptr: newLine
|
|
5521
|
+
});
|
|
5522
|
+
}
|
|
5523
|
+
if (strEnd.trimStart()) {
|
|
5524
|
+
throw new TomlError("found extra tokens after the string part", {
|
|
5525
|
+
toml: ctx.s,
|
|
5526
|
+
ptr: ctx.p
|
|
5527
|
+
});
|
|
5528
|
+
}
|
|
5529
|
+
if (endPtr < ctx.p) {
|
|
5530
|
+
endPtr = ctx.s.indexOf(end2, ctx.p);
|
|
5531
|
+
if (endPtr < 0) {
|
|
5532
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
5533
|
+
toml: ctx.s,
|
|
5534
|
+
ptr: start
|
|
5535
|
+
});
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
parsed.push(part);
|
|
5539
|
+
} else {
|
|
5540
|
+
dot = ctx.s.indexOf(".", ctx.p);
|
|
5541
|
+
let part = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
5542
|
+
if (!KEY_PART_RE.test(part)) {
|
|
5543
|
+
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
5544
|
+
toml: ctx.s,
|
|
5545
|
+
ptr: ctx.p
|
|
5546
|
+
});
|
|
5547
|
+
}
|
|
5548
|
+
parsed.push(part.trimEnd());
|
|
5549
|
+
}
|
|
5550
|
+
}
|
|
5551
|
+
} while (dot + 1 && dot < endPtr);
|
|
5552
|
+
ctx.p = endPtr + 1;
|
|
5553
|
+
skipVoid(ctx, true, true);
|
|
5554
|
+
return parsed;
|
|
5555
|
+
}
|
|
5556
|
+
function parseInlineTable(ctx, integersAsBigInt) {
|
|
5557
|
+
let res = {};
|
|
5558
|
+
let seen = /* @__PURE__ */ new Set();
|
|
5559
|
+
let c;
|
|
5560
|
+
ctx.p++;
|
|
5561
|
+
while (ctx.p < ctx.s.length) {
|
|
5562
|
+
skipVoid(ctx);
|
|
5563
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
|
|
5564
|
+
ctx.p++;
|
|
5565
|
+
return res;
|
|
5566
|
+
}
|
|
5567
|
+
let k;
|
|
5568
|
+
let t = res;
|
|
5569
|
+
let hasOwn = false;
|
|
5570
|
+
let p = ctx.p;
|
|
5571
|
+
let key = parseKey(ctx);
|
|
5572
|
+
for (let i = 0; i < key.length; i++) {
|
|
5573
|
+
if (i)
|
|
5574
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
5575
|
+
k = key[i];
|
|
5576
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
|
|
5577
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
5578
|
+
toml: ctx.s,
|
|
5579
|
+
ptr: p
|
|
5580
|
+
});
|
|
5581
|
+
}
|
|
5582
|
+
if (!hasOwn && k === "__proto__") {
|
|
5583
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
if (hasOwn) {
|
|
5587
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
5588
|
+
toml: ctx.s,
|
|
5589
|
+
ptr: ctx.p
|
|
5590
|
+
});
|
|
5591
|
+
}
|
|
5592
|
+
let value = extractValue(ctx, 125, integersAsBigInt);
|
|
5593
|
+
seen.add(t[k] = value);
|
|
5594
|
+
skipVoid(ctx);
|
|
5595
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) {
|
|
5596
|
+
return res;
|
|
5597
|
+
}
|
|
5598
|
+
if (c !== 44) {
|
|
5599
|
+
throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
|
|
5600
|
+
}
|
|
5601
|
+
}
|
|
5602
|
+
throw new TomlError("unfinished table encountered", {
|
|
5603
|
+
toml: ctx.s,
|
|
5604
|
+
ptr: ctx.p
|
|
5605
|
+
});
|
|
5606
|
+
}
|
|
5607
|
+
function parseArray(ctx, integersAsBigInt) {
|
|
5608
|
+
let res = [];
|
|
5609
|
+
let c;
|
|
5610
|
+
ctx.p++;
|
|
5611
|
+
while (ctx.p < ctx.s.length) {
|
|
5612
|
+
skipVoid(ctx);
|
|
5613
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
|
|
5614
|
+
ctx.p++;
|
|
5615
|
+
return res;
|
|
5616
|
+
}
|
|
5617
|
+
res.push(extractValue(ctx, 93, integersAsBigInt));
|
|
5618
|
+
skipVoid(ctx);
|
|
5619
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) {
|
|
5620
|
+
return res;
|
|
5621
|
+
}
|
|
5622
|
+
if (c !== 44) {
|
|
5623
|
+
throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
throw new TomlError("unfinished array encountered", {
|
|
5627
|
+
toml: ctx.s,
|
|
5628
|
+
ptr: ctx.p
|
|
5629
|
+
});
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5632
|
+
// node_modules/smol-toml/dist/parse.js
|
|
5633
|
+
function peekTable(key, table, meta, type) {
|
|
5634
|
+
let t = table;
|
|
5635
|
+
let m = meta;
|
|
5636
|
+
let k;
|
|
5637
|
+
let hasOwn = false;
|
|
5638
|
+
let state;
|
|
5639
|
+
for (let i = 0; i < key.length; i++) {
|
|
5640
|
+
if (i) {
|
|
5641
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
5642
|
+
m = (state = m[k]).c;
|
|
5643
|
+
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
5644
|
+
return null;
|
|
5645
|
+
}
|
|
5646
|
+
if (state.t === 2) {
|
|
5647
|
+
let l = t.length - 1;
|
|
5648
|
+
t = t[l];
|
|
5649
|
+
m = m[l].c;
|
|
5650
|
+
}
|
|
5651
|
+
}
|
|
5652
|
+
k = key[i];
|
|
5653
|
+
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
|
|
5654
|
+
return null;
|
|
5655
|
+
}
|
|
5656
|
+
if (!hasOwn) {
|
|
5657
|
+
if (k === "__proto__") {
|
|
5658
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
5659
|
+
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
|
|
5660
|
+
}
|
|
5661
|
+
m[k] = {
|
|
5662
|
+
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
5663
|
+
d: false,
|
|
5664
|
+
i: 0,
|
|
5665
|
+
c: {}
|
|
5666
|
+
};
|
|
5667
|
+
}
|
|
5668
|
+
}
|
|
5669
|
+
state = m[k];
|
|
5670
|
+
if (state.t !== type && !(type === 1 && state.t === 3)) {
|
|
5671
|
+
return null;
|
|
5672
|
+
}
|
|
5673
|
+
if (type === 2) {
|
|
5674
|
+
if (!state.d) {
|
|
5675
|
+
state.d = true;
|
|
5676
|
+
t[k] = [];
|
|
5677
|
+
}
|
|
5678
|
+
t[k].push(t = {});
|
|
5679
|
+
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
|
|
5680
|
+
}
|
|
5681
|
+
if (state.d) {
|
|
5682
|
+
return null;
|
|
5683
|
+
}
|
|
5684
|
+
state.d = true;
|
|
5685
|
+
if (type === 1) {
|
|
5686
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
5687
|
+
} else if (type === 0 && hasOwn) {
|
|
5688
|
+
return null;
|
|
5689
|
+
}
|
|
5690
|
+
return [k, t, state.c];
|
|
5691
|
+
}
|
|
5692
|
+
function parse2(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
5693
|
+
let ctx = { s: toml, p: 0, d: maxDepth };
|
|
5694
|
+
let res = {};
|
|
5695
|
+
let meta = {};
|
|
5696
|
+
let tmp;
|
|
5697
|
+
let tbl = res;
|
|
5698
|
+
let m = meta;
|
|
5699
|
+
skipVoid(ctx);
|
|
5700
|
+
while (ctx.p < toml.length) {
|
|
5701
|
+
if (toml.charCodeAt(ctx.p) === 91) {
|
|
5702
|
+
let isTableArray = toml.charCodeAt(++ctx.p) === 91;
|
|
5703
|
+
tmp = ctx.p += +isTableArray;
|
|
5704
|
+
let k = parseKey(ctx, "]");
|
|
5705
|
+
if (isTableArray) {
|
|
5706
|
+
if (toml.charCodeAt(ctx.p - 1) !== 93) {
|
|
5707
|
+
throw new TomlError("expected end of table declaration", {
|
|
5708
|
+
toml,
|
|
5709
|
+
ptr: ctx.p - 1
|
|
5710
|
+
});
|
|
5711
|
+
}
|
|
5712
|
+
ctx.p++;
|
|
5713
|
+
}
|
|
5714
|
+
let p = peekTable(
|
|
5715
|
+
k,
|
|
5716
|
+
res,
|
|
5717
|
+
meta,
|
|
5718
|
+
isTableArray ? 2 : 1
|
|
5719
|
+
/* Type.EXPLICIT */
|
|
5720
|
+
);
|
|
5721
|
+
if (!p) {
|
|
5722
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
5723
|
+
toml,
|
|
5724
|
+
ptr: tmp
|
|
5725
|
+
});
|
|
5726
|
+
}
|
|
5727
|
+
m = p[2];
|
|
5728
|
+
tbl = p[1];
|
|
5729
|
+
} else {
|
|
5730
|
+
tmp = ctx.p;
|
|
5731
|
+
let k = parseKey(ctx);
|
|
5732
|
+
let p = peekTable(
|
|
5733
|
+
k,
|
|
5734
|
+
tbl,
|
|
5735
|
+
m,
|
|
5736
|
+
0
|
|
5737
|
+
/* Type.DOTTED */
|
|
5738
|
+
);
|
|
5739
|
+
if (!p) {
|
|
5740
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
5741
|
+
toml,
|
|
5742
|
+
ptr: tmp
|
|
5743
|
+
});
|
|
5744
|
+
}
|
|
5745
|
+
p[1][p[0]] = extractValue(ctx, void 0, integersAsBigInt);
|
|
5746
|
+
}
|
|
5747
|
+
skipVoid(ctx, true);
|
|
5748
|
+
if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && tmp !== 13) {
|
|
5749
|
+
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
|
|
5750
|
+
toml,
|
|
5751
|
+
ptr: ctx.p
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
skipVoid(ctx);
|
|
5755
|
+
}
|
|
5756
|
+
return res;
|
|
5757
|
+
}
|
|
5758
|
+
|
|
5759
|
+
// node_modules/smol-toml/dist/stringify.js
|
|
5760
|
+
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
5761
|
+
function extendedTypeOf(obj) {
|
|
5762
|
+
let type = typeof obj;
|
|
5763
|
+
if (type === "object") {
|
|
5764
|
+
if (Array.isArray(obj))
|
|
5765
|
+
return "array";
|
|
5766
|
+
if (typeof obj?.getUTCDate === "function" && obj instanceof Date)
|
|
5767
|
+
return "date";
|
|
5768
|
+
if (globalThis.Temporal && // check for the 'since' property as an early bailout that avoids running all 5 instanceof checks
|
|
5769
|
+
typeof obj?.since === "function" && (obj instanceof Temporal.Instant || obj instanceof Temporal.PlainDate || obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainTime || obj instanceof Temporal.ZonedDateTime)) {
|
|
5770
|
+
return "temporal";
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
return type;
|
|
5774
|
+
}
|
|
5775
|
+
function isArrayOfTables(obj) {
|
|
5776
|
+
for (let i = 0; i < obj.length; i++) {
|
|
5777
|
+
if (extendedTypeOf(obj[i]) !== "object")
|
|
5778
|
+
return false;
|
|
5779
|
+
}
|
|
5780
|
+
return obj.length != 0;
|
|
5781
|
+
}
|
|
5782
|
+
function formatString(s) {
|
|
5783
|
+
return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
|
|
5784
|
+
}
|
|
5785
|
+
function stringifyTemporal(temporal) {
|
|
5786
|
+
return temporal.toString({
|
|
5787
|
+
calendarName: "never",
|
|
5788
|
+
timeZoneName: "never"
|
|
5789
|
+
});
|
|
5790
|
+
}
|
|
5791
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
5792
|
+
if (depth === 0) {
|
|
5793
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
5794
|
+
}
|
|
5795
|
+
switch (type) {
|
|
5796
|
+
// @ts-expect-error -- intentional fallthrough case
|
|
5797
|
+
case "number":
|
|
5798
|
+
if (isNaN(val))
|
|
5799
|
+
return "nan";
|
|
5800
|
+
if (val === Infinity)
|
|
5801
|
+
return "inf";
|
|
5802
|
+
if (val === -Infinity)
|
|
5803
|
+
return "-inf";
|
|
5804
|
+
if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val)))
|
|
5805
|
+
return val.toFixed(1);
|
|
5806
|
+
case "bigint":
|
|
5807
|
+
case "boolean":
|
|
5808
|
+
return val.toString();
|
|
5809
|
+
case "string":
|
|
5810
|
+
return formatString(val);
|
|
5811
|
+
case "date":
|
|
5812
|
+
if (isNaN(val.getTime()))
|
|
5813
|
+
throw new TypeError("cannot serialize invalid date");
|
|
5814
|
+
return val.toISOString();
|
|
5815
|
+
case "object":
|
|
5816
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
5817
|
+
case "array":
|
|
5818
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
5819
|
+
case "temporal":
|
|
5820
|
+
return stringifyTemporal(val);
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
5824
|
+
let keys = Object.keys(obj);
|
|
5825
|
+
if (keys.length === 0)
|
|
5826
|
+
return "{}";
|
|
5827
|
+
let res = "{ ";
|
|
5828
|
+
for (let i = 0; i < keys.length; i++) {
|
|
5829
|
+
let k = keys[i];
|
|
5830
|
+
if (i)
|
|
5831
|
+
res += ", ";
|
|
5832
|
+
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
5833
|
+
res += " = ";
|
|
5834
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
5835
|
+
}
|
|
5836
|
+
return res + " }";
|
|
5837
|
+
}
|
|
5838
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
5839
|
+
if (array.length === 0)
|
|
5840
|
+
return "[]";
|
|
5841
|
+
let res = "[ ";
|
|
5842
|
+
for (let i = 0; i < array.length; i++) {
|
|
5843
|
+
if (i)
|
|
5844
|
+
res += ", ";
|
|
5845
|
+
if (array[i] === null || array[i] === void 0) {
|
|
5846
|
+
throw new TypeError("arrays cannot contain null or undefined values");
|
|
5847
|
+
}
|
|
5848
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
5849
|
+
}
|
|
5850
|
+
return res + " ]";
|
|
5851
|
+
}
|
|
5852
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
5853
|
+
if (depth === 0) {
|
|
5854
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
5855
|
+
}
|
|
5856
|
+
let res = "";
|
|
5857
|
+
for (let i = 0; i < array.length; i++) {
|
|
5858
|
+
res += `${res && "\n"}[[${key}]]
|
|
5859
|
+
`;
|
|
5860
|
+
res += stringifyTable(0, array[i], key, depth, numberAsFloat);
|
|
5861
|
+
}
|
|
5862
|
+
return res;
|
|
5863
|
+
}
|
|
5864
|
+
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
|
|
5865
|
+
if (depth === 0) {
|
|
5866
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
5867
|
+
}
|
|
5868
|
+
let preamble = "";
|
|
5869
|
+
let tables = "";
|
|
5870
|
+
let keys = Object.keys(obj);
|
|
5871
|
+
for (let i = 0; i < keys.length; i++) {
|
|
5872
|
+
let k = keys[i];
|
|
5873
|
+
if (obj[k] !== null && obj[k] !== void 0) {
|
|
5874
|
+
let type = extendedTypeOf(obj[k]);
|
|
5875
|
+
if (type === "symbol" || type === "function") {
|
|
5876
|
+
throw new TypeError(`cannot serialize values of type '${type}'`);
|
|
5877
|
+
}
|
|
5878
|
+
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
5879
|
+
if (type === "array" && isArrayOfTables(obj[k])) {
|
|
5880
|
+
tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
5881
|
+
} else if (type === "object") {
|
|
5882
|
+
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
5883
|
+
tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
|
|
5884
|
+
} else {
|
|
5885
|
+
preamble += key;
|
|
5886
|
+
preamble += " = ";
|
|
5887
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
5888
|
+
preamble += "\n";
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5891
|
+
}
|
|
5892
|
+
if (tableKey && (preamble || !tables))
|
|
5893
|
+
preamble = preamble ? `[${tableKey}]
|
|
5894
|
+
${preamble}` : `[${tableKey}]`;
|
|
5895
|
+
return preamble && tables ? `${preamble}
|
|
5896
|
+
${tables}` : preamble || tables;
|
|
5897
|
+
}
|
|
5898
|
+
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
5899
|
+
if (extendedTypeOf(obj) !== "object") {
|
|
5900
|
+
throw new TypeError("stringify can only be called with an object");
|
|
5901
|
+
}
|
|
5902
|
+
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
|
|
5903
|
+
if (str[str.length - 1] !== "\n")
|
|
5904
|
+
return str + "\n";
|
|
5905
|
+
return str;
|
|
5906
|
+
}
|
|
5907
|
+
|
|
5908
|
+
// src/cli/setup-config.ts
|
|
5909
|
+
var begin = "# BEGIN cmdr setup";
|
|
5910
|
+
var end = "# END cmdr setup";
|
|
5911
|
+
function object(value, label) {
|
|
5912
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
5913
|
+
throw new Error(`${label} must be an object; no configuration was changed.`);
|
|
5914
|
+
return value;
|
|
5915
|
+
}
|
|
5916
|
+
function jsonConfig(text3, label) {
|
|
5917
|
+
try {
|
|
5918
|
+
return object(JSON.parse(text3 || "{}"), label);
|
|
5919
|
+
} catch {
|
|
5920
|
+
throw new Error(`Cannot parse ${label} as a JSON object; no configuration was changed.`);
|
|
5921
|
+
}
|
|
5922
|
+
}
|
|
5923
|
+
function shellQuote(value) {
|
|
5924
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
5925
|
+
}
|
|
5926
|
+
function checkPlugin(config, host) {
|
|
5927
|
+
const plugins = host === "codex" ? config.plugins : config.enabledPlugins || config.plugins?.enabledPlugins;
|
|
5928
|
+
if (plugins && Object.entries(object(plugins, "plugins")).some(
|
|
5929
|
+
([name, value]) => /^(cmdr@|cmdr$)/.test(name) && (value === true || typeof value === "object" && value !== null && value.enabled !== false)
|
|
5930
|
+
))
|
|
5931
|
+
throw new Error(
|
|
5932
|
+
"The cmdr plugin is already enabled. Use its installation, or disable it before running standalone setup to avoid duplicate tools and hooks."
|
|
5933
|
+
);
|
|
5934
|
+
}
|
|
5935
|
+
function serverConfig(previous, command, host) {
|
|
5936
|
+
const server = previous === void 0 ? {} : object(previous, "cmdr MCP server");
|
|
5937
|
+
if (previous !== void 0 && (server.command !== command || server.url))
|
|
5938
|
+
throw new Error(
|
|
5939
|
+
"An unmanaged cmdr MCP server already exists. Remove that cmdr entry before running setup; other servers will be preserved."
|
|
5940
|
+
);
|
|
5941
|
+
return {
|
|
5942
|
+
...server,
|
|
5943
|
+
command,
|
|
5944
|
+
args: [],
|
|
5945
|
+
...host === "codex" ? { tool_timeout_sec: 600 } : { type: "stdio" },
|
|
5946
|
+
...host === "zcode" ? { timeoutMs: 6e5 } : {}
|
|
5947
|
+
};
|
|
5948
|
+
}
|
|
5949
|
+
function mergeJsonServer(config, command, host) {
|
|
5950
|
+
const parent = host === "zcode" ? config.mcp = object(config.mcp ?? {}, "mcp") : config;
|
|
5951
|
+
const key = host === "zcode" ? "servers" : "mcpServers";
|
|
5952
|
+
const servers = parent[key] = object(parent[key] ?? {}, key);
|
|
5953
|
+
servers.cmdr = serverConfig(servers.cmdr, command, host);
|
|
5954
|
+
}
|
|
5955
|
+
function codexConfig(text3, command) {
|
|
5956
|
+
let config;
|
|
5957
|
+
try {
|
|
5958
|
+
config = parse2(text3, { integersAsBigInt: "asNeeded" });
|
|
5959
|
+
} catch {
|
|
5960
|
+
throw new Error("Cannot parse Codex config.toml; no configuration was changed.");
|
|
5961
|
+
}
|
|
5962
|
+
checkPlugin(config, "codex");
|
|
5963
|
+
const servers = object(config.mcp_servers ?? {}, "mcp_servers");
|
|
5964
|
+
const server = serverConfig(servers.cmdr, command, "codex");
|
|
5965
|
+
const block = `${begin}
|
|
5966
|
+
${stringify({ mcp_servers: { cmdr: server } })}${end}`;
|
|
5967
|
+
const start = text3.indexOf(begin), stop = text3.indexOf(end);
|
|
5968
|
+
let output;
|
|
5969
|
+
if (start >= 0 || stop >= 0) {
|
|
5970
|
+
if (start < 0 || stop < start || text3.indexOf(begin, start + begin.length) >= 0 || text3.indexOf(end, stop + end.length) >= 0)
|
|
5971
|
+
throw new Error(
|
|
5972
|
+
"Invalid cmdr setup markers in config.toml. Restore the managed block before retrying."
|
|
5973
|
+
);
|
|
5974
|
+
output = text3.slice(0, start) + block + text3.slice(stop + end.length);
|
|
5975
|
+
} else {
|
|
5976
|
+
if (servers.cmdr !== void 0)
|
|
5977
|
+
throw new Error(
|
|
5978
|
+
"The cmdr MCP entry is not managed by setup. Remove that entry before retrying."
|
|
5979
|
+
);
|
|
5980
|
+
output = `${text3}${text3 && !text3.endsWith("\n") ? "\n" : ""}
|
|
5981
|
+
${block}
|
|
5982
|
+
`;
|
|
5983
|
+
}
|
|
5984
|
+
const expected = { ...config, mcp_servers: { ...servers, cmdr: server } };
|
|
5985
|
+
try {
|
|
5986
|
+
if (!isDeepStrictEqual(parse2(output, { integersAsBigInt: "asNeeded" }), expected))
|
|
5987
|
+
throw new Error();
|
|
5988
|
+
} catch {
|
|
5989
|
+
throw new Error(
|
|
5990
|
+
"Cannot safely merge the cmdr block into config.toml. Move the cmdr MCP entry to a separate table and retry."
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
return {
|
|
5994
|
+
text: output,
|
|
5995
|
+
hooksDisabled: config.features?.hooks === false || config.features?.codex_hooks === false,
|
|
5996
|
+
serverDisabled: server.enabled === false
|
|
5997
|
+
};
|
|
5998
|
+
}
|
|
5999
|
+
function mergeHooks(config, executable, host) {
|
|
6000
|
+
const container = config.hooks = object(config.hooks ?? {}, "hooks");
|
|
6001
|
+
const hooks = host === "zcode" ? container.events = object(container.events ?? {}, "hooks.events") : container;
|
|
6002
|
+
const disabled = host === "zcode" ? container.enabled === false : config.disableAllHooks === true;
|
|
6003
|
+
if (host === "zcode" && container.enabled === void 0) container.enabled = true;
|
|
6004
|
+
const events2 = [
|
|
6005
|
+
"SessionStart",
|
|
6006
|
+
"UserPromptSubmit",
|
|
6007
|
+
"PreToolUse",
|
|
6008
|
+
"Stop",
|
|
6009
|
+
...host === "zcode" ? [] : ["SessionEnd"]
|
|
6010
|
+
];
|
|
6011
|
+
for (const event of events2) {
|
|
6012
|
+
const entries = hooks[event] ?? [];
|
|
6013
|
+
if (!Array.isArray(entries)) throw new Error(`hooks.${event} must be an array.`);
|
|
6014
|
+
const handler = host === "zcode" ? { type: "process", command: executable, args: [event], enabled: true, timeoutMs: 5e3 } : {
|
|
6015
|
+
type: "command",
|
|
6016
|
+
command: `${shellQuote(executable)} ${event}`,
|
|
6017
|
+
timeout: event === "SessionEnd" ? 1 : 5
|
|
6018
|
+
};
|
|
6019
|
+
const retained = entries.flatMap((entry) => {
|
|
6020
|
+
const group = object(entry, `hooks.${event} entry`);
|
|
6021
|
+
if (!Array.isArray(group.hooks))
|
|
6022
|
+
throw new Error(`hooks.${event} entry must contain a hooks array.`);
|
|
6023
|
+
const handlers = group.hooks.filter((value) => {
|
|
6024
|
+
const hook = object(value, "hook handler");
|
|
6025
|
+
return !(hook.type === handler.type && hook.command === handler.command && (host !== "zcode" || isDeepStrictEqual(hook.args, handler.args)));
|
|
6026
|
+
});
|
|
6027
|
+
return handlers.length === group.hooks.length ? [group] : handlers.length ? [{ ...group, hooks: handlers }] : [];
|
|
6028
|
+
});
|
|
6029
|
+
hooks[event] = [...retained, { hooks: [handler] }];
|
|
6030
|
+
}
|
|
6031
|
+
return disabled;
|
|
6032
|
+
}
|
|
6033
|
+
|
|
6034
|
+
// src/cli/setup-files.ts
|
|
6035
|
+
import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
|
|
6036
|
+
import {
|
|
6037
|
+
cpSync,
|
|
6038
|
+
existsSync,
|
|
6039
|
+
lstatSync,
|
|
6040
|
+
mkdirSync as mkdirSync4,
|
|
6041
|
+
readFileSync as readFileSync3,
|
|
6042
|
+
readdirSync,
|
|
6043
|
+
readlinkSync,
|
|
6044
|
+
renameSync as renameSync2,
|
|
6045
|
+
rmSync as rmSync4,
|
|
6046
|
+
symlinkSync,
|
|
6047
|
+
writeFileSync as writeFileSync2
|
|
6048
|
+
} from "node:fs";
|
|
6049
|
+
import { basename, dirname as dirname2, join as join5 } from "node:path";
|
|
6050
|
+
function fingerprint(path) {
|
|
6051
|
+
let stat;
|
|
6052
|
+
try {
|
|
6053
|
+
stat = lstatSync(path);
|
|
6054
|
+
} catch (e) {
|
|
6055
|
+
if (e.code === "ENOENT") return null;
|
|
6056
|
+
throw e;
|
|
6057
|
+
}
|
|
6058
|
+
if (stat.isSymbolicLink()) return `link:${readlinkSync(path)}`;
|
|
6059
|
+
if (stat.isDirectory())
|
|
6060
|
+
return `dir:${readdirSync(path).sort().map((name) => JSON.stringify([name, fingerprint(join5(path, name))])).join("")}`;
|
|
6061
|
+
if (!stat.isFile()) throw new Error(`Cannot replace non-file: ${path}`);
|
|
6062
|
+
return `file:${stat.mode}:${createHash2("sha256").update(readFileSync3(path)).digest("hex")}`;
|
|
6063
|
+
}
|
|
6064
|
+
function fileChange(path, content, mode) {
|
|
6065
|
+
const before = fingerprint(path);
|
|
6066
|
+
if (before !== null && !before.startsWith("file:"))
|
|
6067
|
+
throw new Error(`Expected a regular file at ${path}; no configuration was changed.`);
|
|
6068
|
+
if (before !== null && readFileSync3(path, "utf8") === content && (mode === void 0 || (lstatSync(path).mode & 511) === mode))
|
|
6069
|
+
return;
|
|
6070
|
+
return {
|
|
6071
|
+
path,
|
|
6072
|
+
before,
|
|
6073
|
+
content,
|
|
6074
|
+
mode: mode ?? (before === null ? 384 : lstatSync(path).mode & 511)
|
|
6075
|
+
};
|
|
6076
|
+
}
|
|
6077
|
+
function skillChange(path, target) {
|
|
6078
|
+
const before = fingerprint(path);
|
|
6079
|
+
if (before === `link:${target}`) return;
|
|
6080
|
+
if (before !== null) {
|
|
6081
|
+
let skill = "";
|
|
6082
|
+
try {
|
|
6083
|
+
skill = readFileSync3(join5(path, "SKILL.md"), "utf8");
|
|
6084
|
+
} catch {
|
|
6085
|
+
}
|
|
6086
|
+
if (!/^name: cmdr$/m.test(skill) || !/^ source: https:\/\/github.com\/njugray\/cmdr$/m.test(skill))
|
|
6087
|
+
throw new Error(
|
|
6088
|
+
`An unrelated or unreadable skill exists at ${path}. Move it before installing cmdr.`
|
|
6089
|
+
);
|
|
6090
|
+
}
|
|
6091
|
+
return { path, before, link: target };
|
|
6092
|
+
}
|
|
6093
|
+
function applyChanges(changes, backupRoot) {
|
|
6094
|
+
const run = join5(backupRoot, `${Date.now()}-${randomUUID3()}`);
|
|
6095
|
+
const applied = [];
|
|
6096
|
+
const backups = [];
|
|
6097
|
+
try {
|
|
6098
|
+
for (const change of changes) {
|
|
6099
|
+
if (fingerprint(change.path) !== change.before)
|
|
6100
|
+
throw new Error(`Configuration changed during setup: ${change.path}. Retry setup.`);
|
|
6101
|
+
}
|
|
6102
|
+
for (const [index, change] of changes.entries()) {
|
|
6103
|
+
if (fingerprint(change.path) !== change.before)
|
|
6104
|
+
throw new Error(`Configuration changed during setup: ${change.path}. Retry setup.`);
|
|
6105
|
+
mkdirSync4(dirname2(change.path), { recursive: true, mode: 448 });
|
|
6106
|
+
const temporary = join5(
|
|
6107
|
+
dirname2(change.path),
|
|
6108
|
+
`.${basename(change.path)}.cmdr-${randomUUID3()}`
|
|
6109
|
+
);
|
|
6110
|
+
let backup;
|
|
6111
|
+
try {
|
|
6112
|
+
if (change.link) symlinkSync(change.link, temporary, "dir");
|
|
6113
|
+
else writeFileSync2(temporary, change.content, { mode: change.mode, flag: "wx" });
|
|
6114
|
+
if (change.before !== null) {
|
|
6115
|
+
mkdirSync4(run, { recursive: true, mode: 448 });
|
|
6116
|
+
backup = join5(run, `${index}-${basename(change.path)}`);
|
|
6117
|
+
cpSync(change.path, backup, {
|
|
6118
|
+
recursive: true,
|
|
6119
|
+
dereference: false,
|
|
6120
|
+
verbatimSymlinks: true
|
|
6121
|
+
});
|
|
6122
|
+
}
|
|
6123
|
+
mkdirSync4(run, { recursive: true, mode: 448 });
|
|
6124
|
+
backups.push({ path: change.path, backup: backup ?? null });
|
|
6125
|
+
writeFileSync2(join5(run, "restore.json"), JSON.stringify(backups, null, 2) + "\n", {
|
|
6126
|
+
mode: 384
|
|
6127
|
+
});
|
|
6128
|
+
if (change.before !== null) {
|
|
6129
|
+
if (lstatSync(change.path).isDirectory()) rmSync4(change.path, { recursive: true });
|
|
6130
|
+
}
|
|
6131
|
+
const record = { change, backup, after: fingerprint(change.path) };
|
|
6132
|
+
applied.push(record);
|
|
6133
|
+
renameSync2(temporary, change.path);
|
|
6134
|
+
record.after = fingerprint(change.path);
|
|
6135
|
+
} finally {
|
|
6136
|
+
rmSync4(temporary, { force: true });
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
6139
|
+
return backups.length ? run : null;
|
|
6140
|
+
} catch (error) {
|
|
6141
|
+
const failures = [];
|
|
6142
|
+
for (const { change, backup, after } of applied.reverse()) {
|
|
6143
|
+
try {
|
|
6144
|
+
if (fingerprint(change.path) !== after) throw new Error("concurrent edit");
|
|
6145
|
+
rmSync4(change.path, { recursive: true, force: true });
|
|
6146
|
+
if (backup)
|
|
6147
|
+
cpSync(backup, change.path, {
|
|
6148
|
+
recursive: true,
|
|
6149
|
+
dereference: false,
|
|
6150
|
+
verbatimSymlinks: true
|
|
6151
|
+
});
|
|
6152
|
+
} catch {
|
|
6153
|
+
failures.push(change.path);
|
|
6154
|
+
}
|
|
6155
|
+
}
|
|
6156
|
+
if (existsSync(run))
|
|
6157
|
+
writeFileSync2(join5(run, "restore.json"), JSON.stringify(backups, null, 2) + "\n", {
|
|
6158
|
+
mode: 384
|
|
6159
|
+
});
|
|
6160
|
+
if (failures.length)
|
|
6161
|
+
throw new Error(`Setup failed. Restore these paths from ${run}: ${failures.join(", ")}`, {
|
|
6162
|
+
cause: error
|
|
6163
|
+
});
|
|
6164
|
+
throw error;
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
|
|
6168
|
+
// src/cli/setup.ts
|
|
6169
|
+
function read(path) {
|
|
6170
|
+
try {
|
|
6171
|
+
return readFileSync4(path, "utf8");
|
|
6172
|
+
} catch (e) {
|
|
6173
|
+
if (e.code === "ENOENT") return "";
|
|
6174
|
+
throw e;
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
function configPath(path) {
|
|
6178
|
+
return existsSync2(path) ? realpathSync(path) : path;
|
|
6179
|
+
}
|
|
6180
|
+
function launcher(runtime, entry, state, agent, codexHome) {
|
|
6181
|
+
return `#!/bin/sh
|
|
6182
|
+
# Managed by cmdr setup (https://github.com/njugray/cmdr).
|
|
6183
|
+
export CMDR_HOME=${shellQuote(state)}
|
|
6184
|
+
${agent ? `export CMDR_AGENT=${shellQuote(agent)}
|
|
6185
|
+
` : ""}${agent === "codex" || agent === "zcode" ? "export CMDR_TOOL_TIMEOUT_SEC=600\n" : ""}${codexHome ? `export CODEX_HOME=${shellQuote(codexHome)}
|
|
6186
|
+
` : ""}exec ${shellQuote(join6(runtime, "bin", entry))} "$@"
|
|
6187
|
+
`;
|
|
6188
|
+
}
|
|
6189
|
+
async function runSetup(argv, sourceRoot) {
|
|
6190
|
+
const { values, positionals } = parseArgs2({
|
|
6191
|
+
args: argv,
|
|
6192
|
+
allowPositionals: true,
|
|
6193
|
+
options: {
|
|
6194
|
+
agent: { type: "string" },
|
|
6195
|
+
"config-dir": { type: "string" },
|
|
6196
|
+
"dry-run": { type: "boolean" },
|
|
6197
|
+
json: { type: "boolean" },
|
|
6198
|
+
help: { type: "boolean" }
|
|
6199
|
+
}
|
|
6200
|
+
});
|
|
6201
|
+
if (values.help) {
|
|
6202
|
+
console.log(
|
|
6203
|
+
"cmdr setup --agent claude-code|codex|zcode [--config-dir PATH] [--dry-run] [--json]\nInstall or upgrade for the current user. CMDR_HOME selects runtime/state storage; --config-dir selects the host user profile."
|
|
6204
|
+
);
|
|
6205
|
+
return;
|
|
6206
|
+
}
|
|
6207
|
+
const agent = values.agent === "claude-code" ? "claude" : values.agent;
|
|
6208
|
+
if (positionals.length || !agent || !["claude", "codex", "zcode"].includes(agent))
|
|
6209
|
+
throw new Error(
|
|
6210
|
+
"Use cmdr setup --agent claude-code|codex|zcode. Other MCP hosts can use cmdr config --agent HOST."
|
|
6211
|
+
);
|
|
6212
|
+
const host = agent;
|
|
6213
|
+
const source = await inspectInstallation(sourceRoot);
|
|
6214
|
+
if (!source.ok)
|
|
6215
|
+
throw new Error(`The source installation is incomplete: ${(source.errors || []).join("; ")}`);
|
|
6216
|
+
const state = paths().home;
|
|
6217
|
+
const digest = createHash3("sha256").update(readFileSync4(join6(sourceRoot, "dist/integrity.json"))).digest("hex").slice(0, 16);
|
|
6218
|
+
const runtime = join6(state, "runtimes", `${source.version}-${digest}`);
|
|
6219
|
+
const bin = join6(state, "bin");
|
|
6220
|
+
const hostRoot = values["config-dir"] ? resolve2(values["config-dir"]) : host === "claude" ? resolve2(process.env.CLAUDE_CONFIG_DIR || join6(homedir2(), ".claude")) : host === "codex" ? resolve2(process.env.CODEX_HOME || join6(homedir2(), ".codex")) : join6(homedir2(), ".zcode");
|
|
6221
|
+
const profile = createHash3("sha256").update(hostRoot).digest("hex").slice(0, 12);
|
|
6222
|
+
const mcp = join6(bin, `cmdr-mcp-${host}-${profile}`), hook = join6(bin, `cmdr-hook-${host}-${profile}`);
|
|
6223
|
+
const changes = [];
|
|
6224
|
+
const warnings = [];
|
|
6225
|
+
const add = (change) => {
|
|
6226
|
+
if (change) changes.push(change);
|
|
6227
|
+
};
|
|
6228
|
+
const writeConfig = (path, config2) => add(fileChange(path, JSON.stringify(config2, null, 2) + "\n"));
|
|
6229
|
+
let config;
|
|
6230
|
+
if (host === "codex") {
|
|
6231
|
+
config = configPath(join6(hostRoot, "config.toml"));
|
|
6232
|
+
const merged = codexConfig(read(config), mcp);
|
|
6233
|
+
add(fileChange(config, merged.text));
|
|
6234
|
+
const hooksPath = configPath(join6(hostRoot, "hooks.json"));
|
|
6235
|
+
const hooks = jsonConfig(read(hooksPath), hooksPath);
|
|
6236
|
+
mergeHooks(hooks, hook, host);
|
|
6237
|
+
writeConfig(hooksPath, hooks);
|
|
6238
|
+
if (merged.hooksDisabled)
|
|
6239
|
+
warnings.push(
|
|
6240
|
+
"Codex hooks are explicitly disabled. Enable features.hooks in Codex to use identity stamps and lifecycle reminders."
|
|
6241
|
+
);
|
|
6242
|
+
if (merged.serverDisabled)
|
|
6243
|
+
warnings.push("The existing cmdr MCP server remains disabled; enable it in Codex.");
|
|
6244
|
+
} else {
|
|
6245
|
+
const settingsPath = configPath(
|
|
6246
|
+
join6(hostRoot, host === "claude" ? "settings.json" : "cli/config.json")
|
|
6247
|
+
);
|
|
6248
|
+
const settings = jsonConfig(read(settingsPath), settingsPath);
|
|
6249
|
+
checkPlugin(settings, host);
|
|
6250
|
+
config = host === "claude" ? configPath(
|
|
6251
|
+
values["config-dir"] || process.env.CLAUDE_CONFIG_DIR ? join6(hostRoot, ".claude.json") : join6(homedir2(), ".claude.json")
|
|
6252
|
+
) : settingsPath;
|
|
6253
|
+
const servers = config === settingsPath ? settings : jsonConfig(read(config), config);
|
|
6254
|
+
mergeJsonServer(servers, mcp, host);
|
|
6255
|
+
if (mergeHooks(settings, hook, host))
|
|
6256
|
+
warnings.push(
|
|
6257
|
+
`${host} user hooks remain disabled; enable them in the host settings to use lifecycle reminders.`
|
|
6258
|
+
);
|
|
6259
|
+
writeConfig(settingsPath, settings);
|
|
6260
|
+
if (config !== settingsPath) writeConfig(config, servers);
|
|
6261
|
+
}
|
|
6262
|
+
for (const [path, entry, boundHost] of [
|
|
6263
|
+
[join6(bin, "cmdr"), "cmdr", void 0],
|
|
6264
|
+
[mcp, "cmdr-mcp", host],
|
|
6265
|
+
[hook, "cmdr-hook", host]
|
|
6266
|
+
]) {
|
|
6267
|
+
const current = read(path);
|
|
6268
|
+
if (current && !current.startsWith("#!/bin/sh\n# Managed by cmdr setup (https://github.com/njugray/cmdr).\n"))
|
|
6269
|
+
throw new Error(`Unmanaged executable at ${path}; move it before running setup.`);
|
|
6270
|
+
add(
|
|
6271
|
+
fileChange(
|
|
6272
|
+
path,
|
|
6273
|
+
launcher(runtime, entry, state, boundHost, boundHost === "codex" ? hostRoot : void 0),
|
|
6274
|
+
493
|
|
6275
|
+
)
|
|
6276
|
+
);
|
|
6277
|
+
}
|
|
6278
|
+
const skill = join6(hostRoot, "skills/cmdr");
|
|
6279
|
+
add(skillChange(skill, join6(runtime, "skills/cmdr")));
|
|
6280
|
+
const result = {
|
|
6281
|
+
agent: values.agent,
|
|
6282
|
+
version: source.version,
|
|
6283
|
+
runtime,
|
|
6284
|
+
cli: join6(bin, "cmdr"),
|
|
6285
|
+
config,
|
|
6286
|
+
skill,
|
|
6287
|
+
dry_run: !!values["dry-run"],
|
|
6288
|
+
changed: changes.map((change) => change.path),
|
|
6289
|
+
warnings,
|
|
6290
|
+
restart: "Start a new host session and review any hook trust prompts."
|
|
6291
|
+
};
|
|
6292
|
+
const output = (extra) => {
|
|
6293
|
+
if (values.json) console.log(JSON.stringify({ ...result, ...extra }, null, 2));
|
|
6294
|
+
else {
|
|
6295
|
+
console.log(
|
|
6296
|
+
`${values["dry-run"] ? "Setup preview" : "Setup complete"}: cmdr ${source.version} for ${values.agent}
|
|
6297
|
+
Runtime: ${runtime}
|
|
6298
|
+
Skill: ${skill}
|
|
6299
|
+
Config: ${config}
|
|
6300
|
+
CLI: ${join6(bin, "cmdr")}
|
|
6301
|
+
${changes.length} files/links ${values["dry-run"] ? "would change" : "changed"}.`
|
|
6302
|
+
);
|
|
6303
|
+
if (extra.backup) console.log(`Backups: ${extra.backup}`);
|
|
6304
|
+
for (const warning of warnings) console.log(warning);
|
|
6305
|
+
console.log(result.restart);
|
|
6306
|
+
}
|
|
6307
|
+
};
|
|
6308
|
+
if (values["dry-run"]) {
|
|
6309
|
+
output({});
|
|
6310
|
+
return;
|
|
6311
|
+
}
|
|
6312
|
+
mkdirSync5(state, { recursive: true, mode: 448 });
|
|
6313
|
+
const lock = join6(state, "setup.lock");
|
|
6314
|
+
try {
|
|
6315
|
+
writeFileSync3(lock, String(process.pid), { flag: "wx", mode: 384 });
|
|
6316
|
+
} catch (e) {
|
|
6317
|
+
if (e.code === "EEXIST")
|
|
6318
|
+
throw new Error(
|
|
6319
|
+
`Another setup may be running. If it was interrupted, remove ${lock} after confirming that process has stopped, then retry.`
|
|
6320
|
+
);
|
|
6321
|
+
throw e;
|
|
6322
|
+
}
|
|
6323
|
+
let staging;
|
|
6324
|
+
try {
|
|
6325
|
+
if (!existsSync2(runtime)) {
|
|
6326
|
+
mkdirSync5(join6(state, "runtimes"), { recursive: true, mode: 448 });
|
|
6327
|
+
staging = `${runtime}.tmp-${randomUUID4()}`;
|
|
6328
|
+
cpSync2(sourceRoot, staging, { recursive: true, dereference: false });
|
|
6329
|
+
const integrity = await inspectInstallation(staging);
|
|
6330
|
+
if (!integrity.ok) throw new Error("Copied runtime failed integrity verification.");
|
|
6331
|
+
renameSync3(staging, runtime);
|
|
6332
|
+
staging = void 0;
|
|
6333
|
+
} else if (!(await inspectInstallation(runtime)).ok) {
|
|
6334
|
+
throw new Error(`Installed runtime is damaged: ${runtime}. Move it aside and rerun setup.`);
|
|
6335
|
+
}
|
|
6336
|
+
const probe = await probeMcp(runtime);
|
|
6337
|
+
if (!probe.ok)
|
|
6338
|
+
throw new Error(
|
|
6339
|
+
`MCP self-check failed: ${"error" in probe ? probe.error : "unknown error"}. Host configuration was not changed.`
|
|
6340
|
+
);
|
|
6341
|
+
const backup = applyChanges(changes, join6(state, "setup-backups"));
|
|
6342
|
+
output({ ok: true, backup, mcp: probe });
|
|
6343
|
+
} finally {
|
|
6344
|
+
if (staging) rmSync5(staging, { recursive: true, force: true });
|
|
6345
|
+
rmSync5(lock, { force: true });
|
|
6346
|
+
}
|
|
6347
|
+
}
|
|
6348
|
+
|
|
6349
|
+
// src/cli/main.ts
|
|
6350
|
+
if (process.argv[2] === "setup") {
|
|
6351
|
+
try {
|
|
6352
|
+
await runSetup(process.argv.slice(3), dirname3(dirname3(fileURLToPath3(import.meta.url))));
|
|
6353
|
+
} catch (e) {
|
|
6354
|
+
console.error(e.message);
|
|
6355
|
+
process.exitCode = 1;
|
|
6356
|
+
}
|
|
6357
|
+
} else if (process.argv[2] === "session") {
|
|
5019
6358
|
await runSession(process.argv.slice(3));
|
|
5020
6359
|
} else {
|
|
5021
|
-
const { values: v, positionals: args } =
|
|
6360
|
+
const { values: v, positionals: args } = parseArgs3({
|
|
5022
6361
|
allowPositionals: true,
|
|
5023
6362
|
options: {
|
|
5024
6363
|
agent: { type: "string" },
|
|
@@ -5051,6 +6390,7 @@ if (process.argv[2] === "session") {
|
|
|
5051
6390
|
follow: { type: "boolean" },
|
|
5052
6391
|
full: { type: "boolean" },
|
|
5053
6392
|
json: { type: "boolean" },
|
|
6393
|
+
"no-open": { type: "boolean" },
|
|
5054
6394
|
help: { type: "boolean" }
|
|
5055
6395
|
}
|
|
5056
6396
|
});
|
|
@@ -5065,11 +6405,11 @@ if (process.argv[2] === "session") {
|
|
|
5065
6405
|
cmdr: VERSION,
|
|
5066
6406
|
home: p.home
|
|
5067
6407
|
};
|
|
5068
|
-
const root =
|
|
6408
|
+
const root = dirname3(dirname3(fileURLToPath3(import.meta.url)));
|
|
5069
6409
|
checks.bundles = Object.fromEntries(
|
|
5070
|
-
["daemon", "mcp", "hook", "cli"].map((n) => [n,
|
|
6410
|
+
["daemon", "mcp", "hook", "cli"].map((n) => [n, existsSync3(join7(root, "dist", `${n}.mjs`))])
|
|
5071
6411
|
);
|
|
5072
|
-
const target =
|
|
6412
|
+
const target = resolve3(v["plugin-root"] || root);
|
|
5073
6413
|
const installation = await inspectInstallation(target);
|
|
5074
6414
|
checks.installation = installation;
|
|
5075
6415
|
checks.diagnostics = diagnosticStatus();
|
|
@@ -5096,8 +6436,8 @@ if (process.argv[2] === "session") {
|
|
|
5096
6436
|
checks.daemon = "not running";
|
|
5097
6437
|
}
|
|
5098
6438
|
try {
|
|
5099
|
-
const conf =
|
|
5100
|
-
|
|
6439
|
+
const conf = readFileSync5(
|
|
6440
|
+
join7(process.env.CODEX_HOME || join7(homedir3(), ".codex"), "config.toml"),
|
|
5101
6441
|
"utf8"
|
|
5102
6442
|
);
|
|
5103
6443
|
checks.codex_hooks = /(?:^|\n)\s*hooks\s*=\s*false/.test(conf) ? "disabled" : "not explicitly disabled; verify features.hooks in Codex";
|
|
@@ -5115,15 +6455,15 @@ if (process.argv[2] === "session") {
|
|
|
5115
6455
|
checks.codex_hooks = "Codex configuration unavailable";
|
|
5116
6456
|
}
|
|
5117
6457
|
const zcodeRoot = "/Applications/ZCode.app/Contents";
|
|
5118
|
-
if (
|
|
6458
|
+
if (existsSync3(join7(zcodeRoot, "Info.plist"))) {
|
|
5119
6459
|
try {
|
|
5120
6460
|
checks.zcode = {
|
|
5121
6461
|
app_version: execFileSync(
|
|
5122
6462
|
"/usr/libexec/PlistBuddy",
|
|
5123
|
-
["-c", "Print :CFBundleShortVersionString",
|
|
6463
|
+
["-c", "Print :CFBundleShortVersionString", join7(zcodeRoot, "Info.plist")],
|
|
5124
6464
|
{ encoding: "utf8", timeout: 1e3 }
|
|
5125
6465
|
).trim(),
|
|
5126
|
-
runtime:
|
|
6466
|
+
runtime: join7(zcodeRoot, "Resources/glm/zcode.cjs")
|
|
5127
6467
|
};
|
|
5128
6468
|
} catch {
|
|
5129
6469
|
checks.zcode = "Installed";
|
|
@@ -5131,7 +6471,7 @@ if (process.argv[2] === "session") {
|
|
|
5131
6471
|
} else
|
|
5132
6472
|
checks.zcode = "Desktop app not found in /Applications; generic MCP configuration is available.";
|
|
5133
6473
|
try {
|
|
5134
|
-
const zconfig = JSON.parse(
|
|
6474
|
+
const zconfig = JSON.parse(readFileSync5(join7(homedir3(), ".zcode/cli/config.json"), "utf8"));
|
|
5135
6475
|
checks.zcode_user_hooks = zconfig.hooks?.enabled === true;
|
|
5136
6476
|
} catch {
|
|
5137
6477
|
checks.zcode_user_hooks = "No user hook config; installed plugin hooks follow plugin enablement.";
|
|
@@ -5141,15 +6481,28 @@ if (process.argv[2] === "session") {
|
|
|
5141
6481
|
try {
|
|
5142
6482
|
if (v.help)
|
|
5143
6483
|
process.stdout.write(
|
|
5144
|
-
"cmdr status | 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"
|
|
5145
6485
|
);
|
|
5146
|
-
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") {
|
|
5147
6500
|
const agent = v.agent || "generic";
|
|
5148
6501
|
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(agent))
|
|
5149
6502
|
throw new Error("Invalid --agent: use lowercase letters, digits, underscores or hyphens.");
|
|
5150
|
-
const root =
|
|
6503
|
+
const root = dirname3(dirname3(fileURLToPath3(import.meta.url)));
|
|
5151
6504
|
const server = {
|
|
5152
|
-
command:
|
|
6505
|
+
command: join7(root, "bin/cmdr-mcp"),
|
|
5153
6506
|
env: {
|
|
5154
6507
|
CMDR_AGENT: agent,
|
|
5155
6508
|
...v.session ? { CMDR_SESSION_ID: v.session } : {},
|
|
@@ -5272,7 +6625,7 @@ if (process.argv[2] === "session") {
|
|
|
5272
6625
|
} else if (cmd === "daemon") {
|
|
5273
6626
|
const action = args[1] || "status";
|
|
5274
6627
|
if (action === "logs")
|
|
5275
|
-
process.stdout.write(
|
|
6628
|
+
process.stdout.write(existsSync3(p.log) ? readFileSync5(p.log, "utf8") : "No daemon logs.\n");
|
|
5276
6629
|
else if (action === "status") print(await call("admin.status"));
|
|
5277
6630
|
else if (action === "stop" || action === "restart") {
|
|
5278
6631
|
if (action === "restart")
|
|
@@ -5280,7 +6633,7 @@ if (process.argv[2] === "session") {
|
|
|
5280
6633
|
process.execPath,
|
|
5281
6634
|
[
|
|
5282
6635
|
"--experimental-sqlite",
|
|
5283
|
-
|
|
6636
|
+
join7(dirname3(fileURLToPath3(import.meta.url)), "daemon.mjs"),
|
|
5284
6637
|
"--preflight"
|
|
5285
6638
|
],
|
|
5286
6639
|
{ timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
@@ -5291,7 +6644,7 @@ if (process.argv[2] === "session") {
|
|
|
5291
6644
|
if (action === "stop") throw e;
|
|
5292
6645
|
}
|
|
5293
6646
|
if (action === "restart") {
|
|
5294
|
-
for (let n = 0; n < 60 &&
|
|
6647
|
+
for (let n = 0; n < 60 && existsSync3(p.socket); n++) await pause(50);
|
|
5295
6648
|
print(await call("admin.status", {}, true));
|
|
5296
6649
|
}
|
|
5297
6650
|
} else if (action === "start") print(await call("admin.status", {}, true));
|