@mu-crew/mu 3.9.0 → 3.10.1
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/dist/chunk-4PACTXAB.js +17 -0
- package/dist/chunk-4PACTXAB.js.map +1 -0
- package/dist/chunk-77GBZ2KR.js +85 -0
- package/dist/chunk-77GBZ2KR.js.map +1 -0
- package/dist/chunk-7OQNJWBY.js +391 -0
- package/dist/chunk-7OQNJWBY.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-WT7IN2OD.js +9887 -0
- package/dist/chunk-WT7IN2OD.js.map +1 -0
- package/dist/chunk-XXK7FR37.js +640 -0
- package/dist/chunk-XXK7FR37.js.map +1 -0
- package/dist/chunk-YIF3X32A.js +2792 -0
- package/dist/chunk-YIF3X32A.js.map +1 -0
- package/dist/cli-KJGVEZW5.js +6266 -0
- package/dist/cli-KJGVEZW5.js.map +1 -0
- package/dist/cli.js +37 -26127
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +148 -104
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +108 -53
- package/dist/index.js +324 -11728
- package/dist/index.js.map +1 -1
- package/dist/tui-X2XICJTN.js +6452 -0
- package/dist/tui-X2XICJTN.js.map +1 -0
- package/dist/tui-sync-worker.js +16 -0
- package/dist/tui-sync-worker.js.map +1 -0
- package/dist/yank-T3AYQTVR.js +12 -0
- package/dist/yank-T3AYQTVR.js.map +1 -0
- package/docs/ARCHITECTURE.md +9 -3
- package/docs/ROADMAP.md +7 -0
- package/docs/architecture/control-socket.md +5 -1
- package/docs/architecture/sync.md +18 -4
- package/docs/guide/delegate.md +2 -1
- package/docs/guide/dispatch.md +4 -0
- package/docs/guide/sql.md +1 -1
- package/docs/reference/env.md +2 -1
- package/package.json +1 -1
- package/skills/mu/SKILL.md +1 -1
- package/skills/mu/recipes/codemode-driver.md +3 -0
- package/skills/mu/recipes/review-panel.md +2 -1
package/dist/extension/mu-pi.js
CHANGED
|
@@ -175,6 +175,12 @@ function labelStem(label) {
|
|
|
175
175
|
const stem = label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 20).replace(/-+$/, "");
|
|
176
176
|
return stem || void 0;
|
|
177
177
|
}
|
|
178
|
+
var MODEL_RE = /^[A-Za-z0-9._:/@+-]+$/;
|
|
179
|
+
function modelCommand(cli, model, env = process.env) {
|
|
180
|
+
const override = env[`MU_${cli.toUpperCase().replace(/-/g, "_")}_COMMAND`];
|
|
181
|
+
const base = override && override.trim() !== "" ? override.trim() : cli;
|
|
182
|
+
return `${base} --model ${model}`;
|
|
183
|
+
}
|
|
178
184
|
function registerDelegate(pi, run = defaultRunner()) {
|
|
179
185
|
if (!delegateEnabled()) return;
|
|
180
186
|
const inflight = /* @__PURE__ */ new Map();
|
|
@@ -182,7 +188,6 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
182
188
|
const queue = [];
|
|
183
189
|
let queueSeq = 0;
|
|
184
190
|
const failed = /* @__PURE__ */ new Set();
|
|
185
|
-
const reserved = /* @__PURE__ */ new Set();
|
|
186
191
|
let ui;
|
|
187
192
|
let lastPending = 0;
|
|
188
193
|
const reportPending = () => {
|
|
@@ -209,7 +214,6 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
209
214
|
};
|
|
210
215
|
const forget = (name) => {
|
|
211
216
|
inflight.delete(name);
|
|
212
|
-
reserved.delete(name);
|
|
213
217
|
drain();
|
|
214
218
|
showStatus();
|
|
215
219
|
};
|
|
@@ -248,63 +252,60 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
248
252
|
}
|
|
249
253
|
};
|
|
250
254
|
const failure = (what, r) => new Error(`${what} failed (exit ${r.code}): ${(r.stderr || r.stdout).trim()}`);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
Array.isArray(agents)
|
|
256
|
-
|
|
257
|
-
if (Array.isArray(agents)) {
|
|
255
|
+
function pruneFailed() {
|
|
256
|
+
if (failed.size === 0) return;
|
|
257
|
+
void mu(["agent", "list", "-w", W, "--json"]).then((r) => {
|
|
258
|
+
const agents = json(r)?.agents;
|
|
259
|
+
if (!Array.isArray(agents)) return;
|
|
260
|
+
const taken = new Set(agents.map((a) => a.name));
|
|
258
261
|
for (const f of [...failed]) if (!taken.has(f)) failed.delete(f);
|
|
259
262
|
showStatus();
|
|
260
|
-
}
|
|
261
|
-
for (let n = 1; ; n++) {
|
|
262
|
-
const name = stem ? n === 1 ? `delegate-${stem}` : `delegate-${stem}-${n}` : `delegate-${n}`;
|
|
263
|
-
if (!taken.has(name) && !reserved.has(name)) {
|
|
264
|
-
reserved.add(name);
|
|
265
|
-
return name;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
263
|
+
});
|
|
268
264
|
}
|
|
269
|
-
async function spawn(params, cwd, signal) {
|
|
265
|
+
async function spawn(params, text, cwd, signal) {
|
|
266
|
+
signal?.throwIfAborted();
|
|
267
|
+
pruneFailed();
|
|
270
268
|
const stem = labelStem(params.label);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const out = json(r) ?? {};
|
|
293
|
-
if (out.ctl !== "ok") {
|
|
294
|
-
reserved.delete(name);
|
|
295
|
-
throw new Error(
|
|
296
|
-
`${W}/${name} spawned but its control socket is ${String(out.ctl)}, so its answer cannot come back. Pane kept; close it with: mu agent close ${name} -w ${W}`
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
const steps = Array.isArray(out.nextSteps) ? out.nextSteps : [];
|
|
300
|
-
const attach = steps.map((s) => s).find((s) => s.intent === "Attach the pane")?.command;
|
|
301
|
-
const wsPath = out.workspace?.path;
|
|
302
|
-
return {
|
|
303
|
-
name,
|
|
304
|
-
...typeof attach === "string" ? { attach } : {},
|
|
305
|
-
...typeof wsPath === "string" ? { workspace: wsPath } : {}
|
|
306
|
-
};
|
|
269
|
+
const base = stem ? `delegate-${stem}` : "delegate-1";
|
|
270
|
+
const args = ["agent", "spawn", base, "-w", W, "--next-free", "--send", text, "--json"];
|
|
271
|
+
if (params.workspace === true) args.push("--workspace");
|
|
272
|
+
else if (cwd) args.push("--cwd", cwd);
|
|
273
|
+
const cli = typeof params.cli === "string" && params.cli ? params.cli : void 0;
|
|
274
|
+
if (cli) args.push("--cli", cli);
|
|
275
|
+
if (typeof params.model === "string" && params.model)
|
|
276
|
+
args.push("--command", modelCommand(cli ?? "pi", params.model));
|
|
277
|
+
const r = await mu(args);
|
|
278
|
+
const out = json(r);
|
|
279
|
+
const spawned = out?.agent?.name;
|
|
280
|
+
if (typeof spawned !== "string") throw failure("mu agent spawn", r);
|
|
281
|
+
const name = spawned;
|
|
282
|
+
if (signal?.aborted) {
|
|
283
|
+
await mu(["agent", "close", name, "-w", W]);
|
|
284
|
+
signal.throwIfAborted();
|
|
285
|
+
}
|
|
286
|
+
if (out?.ctl !== "ok") {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`${W}/${name} spawned but its control socket is ${String(out?.ctl)}, so its answer cannot come back. Pane kept; close it with: mu agent close ${name} -w ${W}`
|
|
289
|
+
);
|
|
307
290
|
}
|
|
291
|
+
const sent = out.send;
|
|
292
|
+
if (sent?.ok !== true) {
|
|
293
|
+
const c = await mu(["agent", "close", name, "-w", W]);
|
|
294
|
+
const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
|
|
295
|
+
const why = typeof sent?.message === "string" ? sent.message : (r.stderr || r.stdout).trim();
|
|
296
|
+
throw new Error(`mu agent send to ${W}/${name} failed (exit ${r.code}): ${why}. ${pane}`);
|
|
297
|
+
}
|
|
298
|
+
const steps = Array.isArray(out.nextSteps) ? out.nextSteps : [];
|
|
299
|
+
const attach = steps.map((s) => s).find((s) => s.intent === "Attach the pane")?.command;
|
|
300
|
+
const wsPath = out.workspace?.path;
|
|
301
|
+
return {
|
|
302
|
+
name,
|
|
303
|
+
// A pi just spawned has settled no run, so 0 is exact when an older
|
|
304
|
+
// extension's reply carries no runs.
|
|
305
|
+
runs: typeof sent.runs === "number" ? sent.runs : 0,
|
|
306
|
+
...typeof attach === "string" ? { attach } : {},
|
|
307
|
+
...typeof wsPath === "string" ? { workspace: wsPath } : {}
|
|
308
|
+
};
|
|
308
309
|
}
|
|
309
310
|
const recordLabel = (params, name) => typeof params.label === "string" && params.label.trim() ? params.label.trim() : name;
|
|
310
311
|
async function resolveRecord(raw) {
|
|
@@ -400,7 +401,14 @@ ${recorded}` : message,
|
|
|
400
401
|
cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
401
402
|
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
402
403
|
}
|
|
403
|
-
const { name, attach, workspace } = await spawn(
|
|
404
|
+
const { name, runs, attach, workspace } = await spawn(
|
|
405
|
+
params,
|
|
406
|
+
brief ? `${brief}
|
|
407
|
+
|
|
408
|
+
${task}` : task,
|
|
409
|
+
cwd,
|
|
410
|
+
signal
|
|
411
|
+
);
|
|
404
412
|
const entry = {
|
|
405
413
|
abort: new AbortController(),
|
|
406
414
|
cancelling: false,
|
|
@@ -410,43 +418,21 @@ ${recorded}` : message,
|
|
|
410
418
|
freeSlot();
|
|
411
419
|
showStatus();
|
|
412
420
|
const started = Date.now();
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
"agent",
|
|
429
|
-
"send",
|
|
430
|
-
name,
|
|
431
|
-
brief ? `${brief}
|
|
432
|
-
|
|
433
|
-
${task}` : task,
|
|
434
|
-
"-w",
|
|
435
|
-
W,
|
|
436
|
-
"--json"
|
|
437
|
-
]);
|
|
438
|
-
if (sent.code !== 0) {
|
|
439
|
-
plain.abort();
|
|
440
|
-
forget(name);
|
|
441
|
-
const c = await mu(["agent", "close", name, "-w", W]);
|
|
442
|
-
const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
|
|
443
|
-
throw new Error(`${failure(`mu agent send to ${W}/${name}`, sent).message}. ${pane}`);
|
|
444
|
-
}
|
|
445
|
-
const runs = json(sent)?.runs;
|
|
446
|
-
if (typeof runs === "number") {
|
|
447
|
-
plain.abort();
|
|
448
|
-
waiting = mu(waitArgs(runs), entry.abort.signal);
|
|
449
|
-
}
|
|
421
|
+
const waiting = mu(
|
|
422
|
+
[
|
|
423
|
+
"agent",
|
|
424
|
+
"wait",
|
|
425
|
+
name,
|
|
426
|
+
"-w",
|
|
427
|
+
W,
|
|
428
|
+
"--json",
|
|
429
|
+
"--timeout",
|
|
430
|
+
String(timeoutS),
|
|
431
|
+
"--after-runs",
|
|
432
|
+
String(runs)
|
|
433
|
+
],
|
|
434
|
+
entry.abort.signal
|
|
435
|
+
);
|
|
450
436
|
const settle = async (r) => {
|
|
451
437
|
forget(name);
|
|
452
438
|
try {
|
|
@@ -536,7 +522,11 @@ ${task}` : task,
|
|
|
536
522
|
},
|
|
537
523
|
cli: {
|
|
538
524
|
type: "string",
|
|
539
|
-
description: "Agent CLI key (default pi).
|
|
525
|
+
description: "Agent CLI key (default pi). Only keys with $MU_<KEY>_COMMAND set in pi's environment exist; to pick a model, use model instead."
|
|
526
|
+
},
|
|
527
|
+
model: {
|
|
528
|
+
type: "string",
|
|
529
|
+
description: "Model for the subagent, passed to pi as --model (e.g. 'sonnet', 'openai/gpt-5:high'); appended to the cli's command. Default: the cli's own model. Use it to vary models across a review panel."
|
|
540
530
|
},
|
|
541
531
|
keep: {
|
|
542
532
|
type: "boolean",
|
|
@@ -569,6 +559,11 @@ ${task}` : task,
|
|
|
569
559
|
const cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
570
560
|
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
571
561
|
}
|
|
562
|
+
const m = params.model;
|
|
563
|
+
if (m !== void 0 && !(typeof m === "string" && MODEL_RE.test(m)))
|
|
564
|
+
throw new Error(
|
|
565
|
+
`mu_delegate: model must be a pi model id like 'provider/id:thinking' (got ${JSON.stringify(m)})`
|
|
566
|
+
);
|
|
572
567
|
const record = await resolveRecord(params.record);
|
|
573
568
|
const max = delegateMax();
|
|
574
569
|
if (inflight.size + starting < max) {
|
|
@@ -892,6 +887,54 @@ function nudgeText(rule, refs) {
|
|
|
892
887
|
`${refs.length} task(s) IN_PROGRESS. Next: mu task wait ${shown} --first --on-stall exit --json${more}`
|
|
893
888
|
].join("\n");
|
|
894
889
|
}
|
|
890
|
+
function breadcrumb(run, args) {
|
|
891
|
+
void run(args).catch(() => {
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
function parallelSettle(pi) {
|
|
895
|
+
const handlers = [];
|
|
896
|
+
const api = {
|
|
897
|
+
on(event, handler) {
|
|
898
|
+
if (event === "agent_before_settle") handlers.push(handler);
|
|
899
|
+
else pi.on(event, handler);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
let errors = [];
|
|
903
|
+
return {
|
|
904
|
+
api,
|
|
905
|
+
flush() {
|
|
906
|
+
if (handlers.length === 0) return;
|
|
907
|
+
pi.on("agent_before_settle", async (event, ctx) => {
|
|
908
|
+
errors = handlers.map(() => void 0);
|
|
909
|
+
const results = await Promise.all(
|
|
910
|
+
handlers.map(async (h, i) => {
|
|
911
|
+
try {
|
|
912
|
+
return await h(event, ctx);
|
|
913
|
+
} catch (err) {
|
|
914
|
+
errors[i] = [err];
|
|
915
|
+
return void 0;
|
|
916
|
+
}
|
|
917
|
+
})
|
|
918
|
+
);
|
|
919
|
+
const fired = results.filter((r) => r !== void 0);
|
|
920
|
+
if (fired.length === 0) return void 0;
|
|
921
|
+
const prior = event?.entries ?? [];
|
|
922
|
+
return {
|
|
923
|
+
entries: [...prior, ...fired.flatMap((r) => r.entries ?? [])],
|
|
924
|
+
...fired.some((r) => r.continue === true) ? { continue: true } : {}
|
|
925
|
+
};
|
|
926
|
+
});
|
|
927
|
+
handlers.forEach((_, i) => {
|
|
928
|
+
pi.on("agent_before_settle", () => {
|
|
929
|
+
const err = errors[i];
|
|
930
|
+
errors[i] = void 0;
|
|
931
|
+
if (err !== void 0) throw err[0];
|
|
932
|
+
return void 0;
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
}
|
|
895
938
|
function outcomeOf(event) {
|
|
896
939
|
return typeof event === "object" && event !== null ? event.outcome : void 0;
|
|
897
940
|
}
|
|
@@ -923,7 +966,7 @@ function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested
|
|
|
923
966
|
if (refs === void 0 || refs.length === 0) return;
|
|
924
967
|
const text = nudgeText(rule, refs);
|
|
925
968
|
const logWs = [...armed].find((w) => w !== "");
|
|
926
|
-
|
|
969
|
+
breadcrumb(run, [
|
|
927
970
|
"log",
|
|
928
971
|
...logWs ? ["-w", logWs] : [],
|
|
929
972
|
"--kind",
|
|
@@ -979,7 +1022,7 @@ function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested
|
|
|
979
1022
|
fired = true;
|
|
980
1023
|
const names = await ownedInProgress(run, me.agent, me.workstream);
|
|
981
1024
|
if (names === void 0 || names.length === 0) return;
|
|
982
|
-
|
|
1025
|
+
breadcrumb(run, [
|
|
983
1026
|
"log",
|
|
984
1027
|
"-w",
|
|
985
1028
|
me.workstream,
|
|
@@ -1033,13 +1076,12 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1033
1076
|
if (fired || armed.size === 0 || nested() || noUI(ctx)) return;
|
|
1034
1077
|
if (outcomeOf(event) !== "completed") return;
|
|
1035
1078
|
fired = true;
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1079
|
+
const tasks = [...armed];
|
|
1080
|
+
const refuted = await Promise.all(tasks.map(([, t]) => briefRefuted(run, t.ws, t.id)));
|
|
1081
|
+
const refs = tasks.flatMap(([ref], i) => refuted[i] === false ? [ref] : []);
|
|
1040
1082
|
if (refs.length === 0) return;
|
|
1041
1083
|
const logWs = [...armed.values()].find((t) => t.ws !== "")?.ws;
|
|
1042
|
-
|
|
1084
|
+
breadcrumb(run, [
|
|
1043
1085
|
"log",
|
|
1044
1086
|
...logWs ? ["-w", logWs] : [],
|
|
1045
1087
|
"--kind",
|
|
@@ -1060,7 +1102,7 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1060
1102
|
}
|
|
1061
1103
|
|
|
1062
1104
|
// extension/mu-pi.ts
|
|
1063
|
-
var EXT_VERSION = true ? "3.
|
|
1105
|
+
var EXT_VERSION = true ? "3.10.1" : void 0;
|
|
1064
1106
|
var FRESH_COMMAND = "mu-fresh";
|
|
1065
1107
|
var FRESH_TIMEOUT_MS = 3e4;
|
|
1066
1108
|
function commandName(name) {
|
|
@@ -1203,9 +1245,11 @@ function muPi(pi, run = defaultRunner()) {
|
|
|
1203
1245
|
registerDelegate(pi, run);
|
|
1204
1246
|
registerPrompts(pi);
|
|
1205
1247
|
const nested = serveCtl(pi);
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1248
|
+
const settle = parallelSettle(pi);
|
|
1249
|
+
registerNudge(settle.api, run, void 0, nested);
|
|
1250
|
+
registerCloseNudge(settle.api, run, process.env, nested);
|
|
1251
|
+
registerRefuteNudge(settle.api, run, nested);
|
|
1252
|
+
settle.flush();
|
|
1209
1253
|
}
|
|
1210
1254
|
function serveCtl(pi) {
|
|
1211
1255
|
const sock = process.env.MU_CTL_SOCK;
|