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