@mu-crew/mu 3.11.1 → 3.11.3
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/AGENTS.md +2 -1
- package/dist/{chunk-2FJK6OOZ.js → chunk-3L5KO3PX.js} +3 -3
- package/dist/{chunk-JYZUNPPO.js → chunk-F7ZBF6I7.js} +24 -22
- package/dist/chunk-F7ZBF6I7.js.map +1 -0
- package/dist/{chunk-4PACTXAB.js → chunk-L2ABBTYG.js} +1 -1
- package/dist/chunk-L2ABBTYG.js.map +1 -0
- package/dist/{chunk-DXKJY3NT.js → chunk-LEORAGKV.js} +3 -3
- package/dist/{chunk-WYBOR4FX.js → chunk-R2SVBZAB.js} +20 -4
- package/dist/chunk-R2SVBZAB.js.map +1 -0
- package/dist/{cli-GRAPF5VC.js → cli-GJIO7GWD.js} +9 -8
- package/dist/cli-GJIO7GWD.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/extension/mu-pi.js +144 -39
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{tui-DGDEH4JX.js → tui-WHCLVCYE.js} +5 -5
- package/dist/tui-sync-worker.js +2 -2
- package/docs/architecture/control-socket.md +1 -1
- package/docs/guide/delegate.md +7 -0
- package/docs/reference/env.md +1 -0
- package/docs/reference/naming.md +7 -0
- package/package.json +1 -1
- package/dist/chunk-4PACTXAB.js.map +0 -1
- package/dist/chunk-JYZUNPPO.js.map +0 -1
- package/dist/chunk-WYBOR4FX.js.map +0 -1
- package/dist/cli-GRAPF5VC.js.map +0 -1
- /package/dist/{chunk-2FJK6OOZ.js.map → chunk-3L5KO3PX.js.map} +0 -0
- /package/dist/{chunk-DXKJY3NT.js.map → chunk-LEORAGKV.js.map} +0 -0
- /package/dist/{tui-DGDEH4JX.js.map → tui-WHCLVCYE.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
defaultStateDir
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L2ABBTYG.js";
|
|
5
5
|
import "./chunk-PZ5AY32C.js";
|
|
6
6
|
|
|
7
7
|
// src/main.ts
|
|
@@ -47,6 +47,6 @@ function enableCompileCacheIn(dir, enable = nodeEnable ?? null) {
|
|
|
47
47
|
|
|
48
48
|
// src/main.ts
|
|
49
49
|
enableCompileCacheIn(join(defaultStateDir(), "compile-cache"));
|
|
50
|
-
var { runCli } = await import("./cli-
|
|
50
|
+
var { runCli } = await import("./cli-GJIO7GWD.js");
|
|
51
51
|
await runCli(process.argv);
|
|
52
52
|
//# sourceMappingURL=cli.js.map
|
package/dist/extension/mu-pi.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
chmodSync,
|
|
4
4
|
existsSync as existsSync3,
|
|
5
5
|
linkSync,
|
|
6
|
-
mkdirSync,
|
|
6
|
+
mkdirSync as mkdirSync2,
|
|
7
7
|
readdirSync,
|
|
8
8
|
readFileSync as readFileSync2,
|
|
9
9
|
realpathSync,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
statSync as statSync2
|
|
12
12
|
} from "fs";
|
|
13
13
|
import { connect, createServer } from "net";
|
|
14
|
-
import { dirname, join as
|
|
14
|
+
import { dirname, join as join4 } from "path";
|
|
15
15
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16
16
|
|
|
17
17
|
// src/ctl/protocol.ts
|
|
@@ -44,9 +44,19 @@ var LineDecoder = class {
|
|
|
44
44
|
|
|
45
45
|
// extension/delegate.ts
|
|
46
46
|
import { execFile } from "child_process";
|
|
47
|
-
import { existsSync, statSync } from "fs";
|
|
48
|
-
import { delimiter, join } from "path";
|
|
47
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from "fs";
|
|
48
|
+
import { delimiter, join as join2 } from "path";
|
|
49
49
|
import { fileURLToPath } from "url";
|
|
50
|
+
|
|
51
|
+
// src/state-dir.ts
|
|
52
|
+
import { homedir } from "os";
|
|
53
|
+
import { isAbsolute, join } from "path";
|
|
54
|
+
function defaultCacheDir() {
|
|
55
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
56
|
+
return join(xdg !== void 0 && isAbsolute(xdg) ? xdg : join(homedir(), ".cache"), "mu");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// extension/delegate.ts
|
|
50
60
|
var DELEGATE_TOOL = "mu_delegate";
|
|
51
61
|
var DELEGATE_CANCEL_TOOL = "mu_delegate_cancel";
|
|
52
62
|
var DELEGATE_MESSAGE_TYPE = "mu-delegate";
|
|
@@ -84,7 +94,7 @@ function isDir(p) {
|
|
|
84
94
|
}
|
|
85
95
|
}
|
|
86
96
|
function onPath(bin, env) {
|
|
87
|
-
return (env.PATH ?? "").split(delimiter).some((d) => d !== "" && existsSync(
|
|
97
|
+
return (env.PATH ?? "").split(delimiter).some((d) => d !== "" && existsSync(join2(d, bin)));
|
|
88
98
|
}
|
|
89
99
|
function defaultRunner() {
|
|
90
100
|
let cli;
|
|
@@ -154,6 +164,29 @@ ${agent.lastText ?? ""}`;
|
|
|
154
164
|
return `${who}: mu agent wait gave no result. ${fate}${ws}${tailBlock}`;
|
|
155
165
|
}
|
|
156
166
|
}
|
|
167
|
+
function droppedAnswersDir() {
|
|
168
|
+
return join2(defaultCacheDir(), "delegate-answers");
|
|
169
|
+
}
|
|
170
|
+
function droppedNote(dropped) {
|
|
171
|
+
const n = dropped.length;
|
|
172
|
+
const lines = dropped.map((d) => {
|
|
173
|
+
const how = [
|
|
174
|
+
d.outcome ?? "no result",
|
|
175
|
+
d.elapsedMs !== void 0 ? formatElapsed(d.elapsedMs) : void 0
|
|
176
|
+
].filter((x) => x !== void 0).join(", ");
|
|
177
|
+
const where = [
|
|
178
|
+
d.copy ? `answer: ${d.copy}` : void 0,
|
|
179
|
+
d.sessionFile ? `session: ${d.sessionFile}` : void 0
|
|
180
|
+
].filter((x) => x !== void 0);
|
|
181
|
+
if (where.length === 0) where.push(`read: mu agent read ${d.name} -n 50 -w ${W}`);
|
|
182
|
+
return `- ${W}/${d.name} (${how}) ${where.join(" \xB7 ")}`;
|
|
183
|
+
});
|
|
184
|
+
return [
|
|
185
|
+
`The interrupt dropped ${n} delegate answer${n === 1 ? "" : "s"} before ${n === 1 ? "it" : "they"} arrived:`,
|
|
186
|
+
...lines,
|
|
187
|
+
"The answer file holds the message that would have arrived; in a session file the answer is the last assistant message."
|
|
188
|
+
].join("\n");
|
|
189
|
+
}
|
|
157
190
|
var RECORD_NOTE_MAX = 4e3;
|
|
158
191
|
var RECORD_FALLBACK_TAIL = 1500;
|
|
159
192
|
var VERDICT_LINE = /^[\s>*_`-]*VERDICT:/;
|
|
@@ -176,11 +209,23 @@ function labelStem(label) {
|
|
|
176
209
|
const stem = label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 20).replace(/-+$/, "");
|
|
177
210
|
return stem || void 0;
|
|
178
211
|
}
|
|
179
|
-
var
|
|
212
|
+
var MODEL_BARE_RE = /^[A-Za-z0-9._:/@+=-]+$/;
|
|
213
|
+
function normalizeModel(raw) {
|
|
214
|
+
if (typeof raw !== "string") return void 0;
|
|
215
|
+
let m = raw.trim();
|
|
216
|
+
for (let prev = ""; prev !== m; ) {
|
|
217
|
+
prev = m;
|
|
218
|
+
m = m.replace(/^--model(?:=|\s+)/, "").replace(/^(["'`])(.*)\1$/s, "$2").trim();
|
|
219
|
+
}
|
|
220
|
+
return m && !/\s/.test(m) ? m : void 0;
|
|
221
|
+
}
|
|
222
|
+
function shellArg(s) {
|
|
223
|
+
return MODEL_BARE_RE.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
224
|
+
}
|
|
180
225
|
function modelCommand(cli, model, env = process.env) {
|
|
181
226
|
const override = env[`MU_${cli.toUpperCase().replace(/-/g, "_")}_COMMAND`];
|
|
182
227
|
const base = override && override.trim() !== "" ? override.trim() : cli;
|
|
183
|
-
return `${base} --model ${model}`;
|
|
228
|
+
return `${base} --model ${shellArg(model)}`;
|
|
184
229
|
}
|
|
185
230
|
function registerDelegate(pi, run = defaultRunner()) {
|
|
186
231
|
if (!delegateEnabled()) return;
|
|
@@ -215,6 +260,23 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
215
260
|
const track = (ctx) => {
|
|
216
261
|
if (ctx?.hasUI !== false && ctx?.ui) ui = ctx.ui;
|
|
217
262
|
};
|
|
263
|
+
const markQueued = (delivery) => {
|
|
264
|
+
const a = arriving.get(delivery);
|
|
265
|
+
if (a) a.queued = true;
|
|
266
|
+
};
|
|
267
|
+
const saveCopy = (name, content) => {
|
|
268
|
+
try {
|
|
269
|
+
const dir = droppedAnswersDir();
|
|
270
|
+
mkdirSync(dir, { recursive: true });
|
|
271
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
272
|
+
const path = join2(dir, `${stamp}_${name}.md`);
|
|
273
|
+
writeFileSync(path, `${content}
|
|
274
|
+
`);
|
|
275
|
+
return path;
|
|
276
|
+
} catch {
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
218
280
|
const forget = (name) => {
|
|
219
281
|
inflight.delete(name);
|
|
220
282
|
drain();
|
|
@@ -359,12 +421,21 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
359
421
|
recordNote(record.label, name, outcome, agent?.lastText, extras.elapsedMs ?? 0)
|
|
360
422
|
) : void 0;
|
|
361
423
|
const message = delegateMessage(name, agent, pane, { ...extras, ...tail ? { tail } : {} });
|
|
424
|
+
const content = recorded ? `${message}
|
|
425
|
+
|
|
426
|
+
${recorded}` : message;
|
|
427
|
+
const a = arriving.get(delivery);
|
|
428
|
+
if (a)
|
|
429
|
+
Object.assign(a, {
|
|
430
|
+
content,
|
|
431
|
+
...outcome ? { outcome } : {},
|
|
432
|
+
...extras.elapsedMs !== void 0 ? { elapsedMs: extras.elapsedMs } : {},
|
|
433
|
+
...agent?.sessionFile ? { sessionFile: agent.sessionFile } : {}
|
|
434
|
+
});
|
|
362
435
|
await pi.sendMessage(
|
|
363
436
|
{
|
|
364
437
|
customType: DELEGATE_MESSAGE_TYPE,
|
|
365
|
-
content
|
|
366
|
-
|
|
367
|
-
${recorded}` : message,
|
|
438
|
+
content,
|
|
368
439
|
display: true,
|
|
369
440
|
details: {
|
|
370
441
|
name,
|
|
@@ -439,7 +510,7 @@ ${task}` : task,
|
|
|
439
510
|
);
|
|
440
511
|
const settle = async (r) => {
|
|
441
512
|
const delivery = ++deliverySeq;
|
|
442
|
-
arriving.set(delivery, false);
|
|
513
|
+
arriving.set(delivery, { queued: false, name });
|
|
443
514
|
forget(name);
|
|
444
515
|
try {
|
|
445
516
|
await deliver(
|
|
@@ -456,22 +527,28 @@ ${task}` : task,
|
|
|
456
527
|
delivery,
|
|
457
528
|
entry.record
|
|
458
529
|
);
|
|
459
|
-
|
|
530
|
+
markQueued(delivery);
|
|
460
531
|
} catch (e) {
|
|
532
|
+
const content = `Delegate ${W}/${name} settled, but delivering its answer failed: ${e instanceof Error ? e.message : String(e)}. Read it with: mu agent read ${name} -n 50 -w ${W}`;
|
|
533
|
+
const a = arriving.get(delivery);
|
|
534
|
+
if (a) a.content = content;
|
|
461
535
|
await Promise.resolve(
|
|
462
536
|
pi.sendMessage(
|
|
463
537
|
{
|
|
464
538
|
customType: DELEGATE_MESSAGE_TYPE,
|
|
465
|
-
content
|
|
539
|
+
content,
|
|
466
540
|
display: true,
|
|
467
541
|
details: { name, workstream: W, outcome: null, closed: false, delivery }
|
|
468
542
|
},
|
|
469
543
|
{ deliverAs: "followUp", triggerTurn: true }
|
|
470
544
|
)
|
|
471
|
-
).
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
545
|
+
).then(
|
|
546
|
+
() => markQueued(delivery),
|
|
547
|
+
() => {
|
|
548
|
+
arriving.delete(delivery);
|
|
549
|
+
showStatus();
|
|
550
|
+
}
|
|
551
|
+
);
|
|
475
552
|
}
|
|
476
553
|
};
|
|
477
554
|
void waiting.then(async (r) => {
|
|
@@ -569,11 +646,14 @@ ${task}` : task,
|
|
|
569
646
|
const cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
570
647
|
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
571
648
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
649
|
+
if (params.model !== void 0 && params.model !== "") {
|
|
650
|
+
const m = normalizeModel(params.model);
|
|
651
|
+
if (!m)
|
|
652
|
+
throw new Error(
|
|
653
|
+
`mu_delegate: model must be one pi model id like 'provider/id:thinking', as listed by \`pi --list-models\` (got ${JSON.stringify(params.model)}); omit it for the cli's default`
|
|
654
|
+
);
|
|
655
|
+
params = { ...params, model: m };
|
|
656
|
+
}
|
|
577
657
|
const record = await resolveRecord(params.record);
|
|
578
658
|
const max = delegateMax();
|
|
579
659
|
if (inflight.size + starting < max) {
|
|
@@ -671,13 +751,32 @@ ${task}` : task,
|
|
|
671
751
|
});
|
|
672
752
|
pi.on("agent_settled", (e) => {
|
|
673
753
|
if (e.aborted !== true) return;
|
|
674
|
-
|
|
675
|
-
for (const [id,
|
|
676
|
-
if (queued)
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
754
|
+
const dropped = [];
|
|
755
|
+
for (const [id, a] of arriving) {
|
|
756
|
+
if (!a.queued) continue;
|
|
757
|
+
arriving.delete(id);
|
|
758
|
+
dropped.push({
|
|
759
|
+
name: a.name,
|
|
760
|
+
...a.outcome ? { outcome: a.outcome } : {},
|
|
761
|
+
...a.elapsedMs !== void 0 ? { elapsedMs: a.elapsedMs } : {},
|
|
762
|
+
...a.sessionFile ? { sessionFile: a.sessionFile } : {},
|
|
763
|
+
...a.content ? { copy: saveCopy(a.name, a.content) } : {}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
if (dropped.length === 0) return;
|
|
767
|
+
showStatus();
|
|
768
|
+
void Promise.resolve(
|
|
769
|
+
pi.sendMessage(
|
|
770
|
+
{
|
|
771
|
+
customType: DELEGATE_MESSAGE_TYPE,
|
|
772
|
+
content: droppedNote(dropped),
|
|
773
|
+
display: true,
|
|
774
|
+
details: { dropped }
|
|
775
|
+
},
|
|
776
|
+
{ triggerTurn: false }
|
|
777
|
+
)
|
|
778
|
+
).catch(() => {
|
|
779
|
+
});
|
|
681
780
|
});
|
|
682
781
|
pi.on("session_shutdown", (_e, ctx) => {
|
|
683
782
|
if (arriving.size > 0) {
|
|
@@ -707,7 +806,7 @@ ${task}` : task,
|
|
|
707
806
|
|
|
708
807
|
// extension/nudge.ts
|
|
709
808
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
710
|
-
import { join as
|
|
809
|
+
import { join as join3 } from "path";
|
|
711
810
|
var NUDGE_MESSAGE_TYPE = "mu-keep-driving";
|
|
712
811
|
var NUDGE_LOG_KIND = "nudge";
|
|
713
812
|
var CLOSE_NUDGE_MESSAGE_TYPE = "mu-close-task";
|
|
@@ -731,7 +830,7 @@ function keepDrivingRule(skillMd) {
|
|
|
731
830
|
}
|
|
732
831
|
function readSkill() {
|
|
733
832
|
for (const up of ["..", "../.."]) {
|
|
734
|
-
const p =
|
|
833
|
+
const p = join3(import.meta.dirname ?? "", up, "skills", "mu", "SKILL.md");
|
|
735
834
|
if (existsSync2(p)) return readFileSync(p, "utf8");
|
|
736
835
|
}
|
|
737
836
|
return void 0;
|
|
@@ -1132,7 +1231,7 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1132
1231
|
}
|
|
1133
1232
|
|
|
1134
1233
|
// extension/mu-pi.ts
|
|
1135
|
-
var EXT_VERSION = true ? "3.11.
|
|
1234
|
+
var EXT_VERSION = true ? "3.11.3" : void 0;
|
|
1136
1235
|
var FRESH_COMMAND = "mu-fresh";
|
|
1137
1236
|
var FRESH_TIMEOUT_MS = 3e4;
|
|
1138
1237
|
function commandName(name) {
|
|
@@ -1152,7 +1251,7 @@ function detectPiVersion() {
|
|
|
1152
1251
|
if (!entry) return void 0;
|
|
1153
1252
|
let dir = dirname(realpathSync(entry));
|
|
1154
1253
|
for (let i = 0; i < 6; i++) {
|
|
1155
|
-
const pkgPath =
|
|
1254
|
+
const pkgPath = join4(dir, "package.json");
|
|
1156
1255
|
if (existsSync3(pkgPath)) {
|
|
1157
1256
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
1158
1257
|
if (typeof pkg === "object" && pkg !== null) {
|
|
@@ -1258,8 +1357,8 @@ function promptsDir(from = import.meta.url) {
|
|
|
1258
1357
|
return void 0;
|
|
1259
1358
|
}
|
|
1260
1359
|
for (const up of ["..", "../.."]) {
|
|
1261
|
-
const d =
|
|
1262
|
-
if (existsSync3(
|
|
1360
|
+
const d = join4(here, up, "prompts");
|
|
1361
|
+
if (existsSync3(join4(d, "ultrathink.md"))) return d;
|
|
1263
1362
|
}
|
|
1264
1363
|
return void 0;
|
|
1265
1364
|
}
|
|
@@ -1267,7 +1366,7 @@ function registerPrompts(pi) {
|
|
|
1267
1366
|
pi.on("resources_discover", () => {
|
|
1268
1367
|
const d = promptsDir();
|
|
1269
1368
|
if (!d) return {};
|
|
1270
|
-
const paths = readdirSync(d).filter((f) => f.endsWith(".md")).sort().map((f) =>
|
|
1369
|
+
const paths = readdirSync(d).filter((f) => f.endsWith(".md")).sort().map((f) => join4(d, f));
|
|
1271
1370
|
return { promptPaths: paths };
|
|
1272
1371
|
});
|
|
1273
1372
|
}
|
|
@@ -1338,6 +1437,11 @@ function serveCtl(pi) {
|
|
|
1338
1437
|
g.endText = void 0;
|
|
1339
1438
|
g.lastError = g.endError;
|
|
1340
1439
|
g.endError = void 0;
|
|
1440
|
+
try {
|
|
1441
|
+
g.sessionFile = c.sessionManager?.getSessionFile();
|
|
1442
|
+
} catch {
|
|
1443
|
+
g.sessionFile = void 0;
|
|
1444
|
+
}
|
|
1341
1445
|
for (const w of [...g.waiters]) w();
|
|
1342
1446
|
});
|
|
1343
1447
|
pi.registerCommand(FRESH_COMMAND, {
|
|
@@ -1497,7 +1601,8 @@ function serveCtl(pi) {
|
|
|
1497
1601
|
}
|
|
1498
1602
|
const settledRun = () => ({
|
|
1499
1603
|
lastText: g.lastText,
|
|
1500
|
-
...g.lastError !== void 0 ? { lastError: g.lastError } : {}
|
|
1604
|
+
...g.lastError !== void 0 ? { lastError: g.lastError } : {},
|
|
1605
|
+
...g.sessionFile !== void 0 ? { sessionFile: g.sessionFile } : {}
|
|
1501
1606
|
});
|
|
1502
1607
|
function wait(afterRuns, timeoutMs, conn) {
|
|
1503
1608
|
if (afterRuns !== void 0 && g.runs > afterRuns && g.state === "idle") {
|
|
@@ -1555,7 +1660,7 @@ function serveCtl(pi) {
|
|
|
1555
1660
|
});
|
|
1556
1661
|
}
|
|
1557
1662
|
async function bind() {
|
|
1558
|
-
|
|
1663
|
+
mkdirSync2(dirname(sockPath), { recursive: true, mode: 448 });
|
|
1559
1664
|
if (await socketIsLive(sockPath)) {
|
|
1560
1665
|
g.nested = true;
|
|
1561
1666
|
process.stderr.write(
|
|
@@ -1565,7 +1670,7 @@ function serveCtl(pi) {
|
|
|
1565
1670
|
return;
|
|
1566
1671
|
}
|
|
1567
1672
|
rmSync(sockPath, { force: true });
|
|
1568
|
-
const tmp =
|
|
1673
|
+
const tmp = join4(dirname(sockPath), `.${process.pid.toString(36)}${(++bindSeq).toString(36)}`);
|
|
1569
1674
|
rmSync(tmp, { force: true });
|
|
1570
1675
|
const s = createServer(onConnection);
|
|
1571
1676
|
await new Promise((resolve, reject) => {
|