@mu-crew/mu 3.8.1 → 3.10.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.
Files changed (54) hide show
  1. package/AGENTS.md +2 -1
  2. package/README.md +1 -0
  3. package/dist/chunk-4PACTXAB.js +17 -0
  4. package/dist/chunk-4PACTXAB.js.map +1 -0
  5. package/dist/chunk-77GBZ2KR.js +85 -0
  6. package/dist/chunk-77GBZ2KR.js.map +1 -0
  7. package/dist/chunk-7OQNJWBY.js +391 -0
  8. package/dist/chunk-7OQNJWBY.js.map +1 -0
  9. package/dist/chunk-PZ5AY32C.js +10 -0
  10. package/dist/chunk-PZ5AY32C.js.map +1 -0
  11. package/dist/chunk-WT7IN2OD.js +9887 -0
  12. package/dist/chunk-WT7IN2OD.js.map +1 -0
  13. package/dist/chunk-XXK7FR37.js +640 -0
  14. package/dist/chunk-XXK7FR37.js.map +1 -0
  15. package/dist/chunk-YIF3X32A.js +2792 -0
  16. package/dist/chunk-YIF3X32A.js.map +1 -0
  17. package/dist/cli-UZEMPIPW.js +6266 -0
  18. package/dist/cli-UZEMPIPW.js.map +1 -0
  19. package/dist/cli.js +37 -25280
  20. package/dist/cli.js.map +1 -1
  21. package/dist/extension/mu-pi.js +230 -138
  22. package/dist/extension/mu-pi.js.map +1 -1
  23. package/dist/index.d.ts +543 -142
  24. package/dist/index.js +340 -11169
  25. package/dist/index.js.map +1 -1
  26. package/dist/tui-X2XICJTN.js +6452 -0
  27. package/dist/tui-X2XICJTN.js.map +1 -0
  28. package/dist/tui-sync-worker.js +16 -0
  29. package/dist/tui-sync-worker.js.map +1 -0
  30. package/dist/yank-T3AYQTVR.js +12 -0
  31. package/dist/yank-T3AYQTVR.js.map +1 -0
  32. package/docs/ARCHITECTURE.md +14 -6
  33. package/docs/VISION.md +14 -7
  34. package/docs/VOCABULARY.md +5 -6
  35. package/docs/architecture/control-socket.md +6 -2
  36. package/docs/architecture/mux.md +4 -2
  37. package/docs/architecture/ops-log.md +2 -1
  38. package/docs/architecture/sdk.md +3 -1
  39. package/docs/architecture/sync.md +32 -10
  40. package/docs/architecture/tui.md +18 -8
  41. package/docs/guide/backends.md +5 -3
  42. package/docs/guide/cleanup.md +8 -3
  43. package/docs/guide/delegate.md +3 -1
  44. package/docs/guide/dispatch.md +9 -3
  45. package/docs/guide/recovery.md +19 -8
  46. package/docs/guide/sql.md +11 -4
  47. package/docs/guide/stop-a-worker.md +3 -1
  48. package/docs/guide/tui.md +3 -3
  49. package/docs/guide/upgrade.md +8 -2
  50. package/docs/reference/env.md +11 -5
  51. package/docs/reference/naming.md +3 -4
  52. package/package.json +1 -1
  53. package/skills/mu/SKILL.md +2 -2
  54. package/skills/mu/recipes/drift-audit.md +5 -3
@@ -182,7 +182,6 @@ function registerDelegate(pi, run = defaultRunner()) {
182
182
  const queue = [];
183
183
  let queueSeq = 0;
184
184
  const failed = /* @__PURE__ */ new Set();
185
- const reserved = /* @__PURE__ */ new Set();
186
185
  let ui;
187
186
  let lastPending = 0;
188
187
  const reportPending = () => {
@@ -209,7 +208,6 @@ function registerDelegate(pi, run = defaultRunner()) {
209
208
  };
210
209
  const forget = (name) => {
211
210
  inflight.delete(name);
212
- reserved.delete(name);
213
211
  drain();
214
212
  showStatus();
215
213
  };
@@ -248,63 +246,57 @@ function registerDelegate(pi, run = defaultRunner()) {
248
246
  }
249
247
  };
250
248
  const failure = (what, r) => new Error(`${what} failed (exit ${r.code}): ${(r.stderr || r.stdout).trim()}`);
251
- async function pickName(stem) {
252
- const r = await mu(["agent", "list", "-w", W, "--json"]);
253
- const agents = json(r)?.agents;
254
- const taken = new Set(
255
- Array.isArray(agents) ? agents.map((a) => a.name).filter((n) => n) : []
256
- );
257
- if (Array.isArray(agents)) {
249
+ function pruneFailed() {
250
+ if (failed.size === 0) return;
251
+ void mu(["agent", "list", "-w", W, "--json"]).then((r) => {
252
+ const agents = json(r)?.agents;
253
+ if (!Array.isArray(agents)) return;
254
+ const taken = new Set(agents.map((a) => a.name));
258
255
  for (const f of [...failed]) if (!taken.has(f)) failed.delete(f);
259
256
  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
- }
257
+ });
268
258
  }
269
- async function spawn(params, cwd, signal) {
259
+ async function spawn(params, text, cwd, signal) {
260
+ signal?.throwIfAborted();
261
+ pruneFailed();
270
262
  const stem = labelStem(params.label);
271
- for (let attempt = 0; ; attempt++) {
272
- signal?.throwIfAborted();
273
- const name = await pickName(stem);
274
- const args = ["agent", "spawn", name, "-w", W, "--json"];
275
- if (params.workspace === true) args.push("--workspace");
276
- else if (cwd) args.push("--cwd", cwd);
277
- if (typeof params.cli === "string" && params.cli) args.push("--cli", params.cli);
278
- const r = await mu(args);
279
- if (signal?.aborted && r.code === 0) {
280
- reserved.delete(name);
281
- await mu(["agent", "close", name, "-w", W]);
282
- signal.throwIfAborted();
283
- }
284
- if (r.code !== 0 && /already exists/.test(r.stderr) && attempt < 3) {
285
- reserved.delete(name);
286
- continue;
287
- }
288
- if (r.code !== 0) {
289
- reserved.delete(name);
290
- throw failure("mu agent spawn", r);
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
- };
263
+ const base = stem ? `delegate-${stem}` : "delegate-1";
264
+ const args = ["agent", "spawn", base, "-w", W, "--next-free", "--send", text, "--json"];
265
+ if (params.workspace === true) args.push("--workspace");
266
+ else if (cwd) args.push("--cwd", cwd);
267
+ if (typeof params.cli === "string" && params.cli) args.push("--cli", params.cli);
268
+ const r = await mu(args);
269
+ const out = json(r);
270
+ const spawned = out?.agent?.name;
271
+ if (typeof spawned !== "string") throw failure("mu agent spawn", r);
272
+ const name = spawned;
273
+ if (signal?.aborted) {
274
+ await mu(["agent", "close", name, "-w", W]);
275
+ signal.throwIfAborted();
307
276
  }
277
+ if (out?.ctl !== "ok") {
278
+ throw new Error(
279
+ `${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}`
280
+ );
281
+ }
282
+ const sent = out.send;
283
+ if (sent?.ok !== true) {
284
+ const c = await mu(["agent", "close", name, "-w", W]);
285
+ const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
286
+ const why = typeof sent?.message === "string" ? sent.message : (r.stderr || r.stdout).trim();
287
+ throw new Error(`mu agent send to ${W}/${name} failed (exit ${r.code}): ${why}. ${pane}`);
288
+ }
289
+ const steps = Array.isArray(out.nextSteps) ? out.nextSteps : [];
290
+ const attach = steps.map((s) => s).find((s) => s.intent === "Attach the pane")?.command;
291
+ const wsPath = out.workspace?.path;
292
+ return {
293
+ name,
294
+ // A pi just spawned has settled no run, so 0 is exact when an older
295
+ // extension's reply carries no runs.
296
+ runs: typeof sent.runs === "number" ? sent.runs : 0,
297
+ ...typeof attach === "string" ? { attach } : {},
298
+ ...typeof wsPath === "string" ? { workspace: wsPath } : {}
299
+ };
308
300
  }
309
301
  const recordLabel = (params, name) => typeof params.label === "string" && params.label.trim() ? params.label.trim() : name;
310
302
  async function resolveRecord(raw) {
@@ -400,7 +392,14 @@ ${recorded}` : message,
400
392
  cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
401
393
  if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
402
394
  }
403
- const { name, attach, workspace } = await spawn(params, cwd, signal);
395
+ const { name, runs, attach, workspace } = await spawn(
396
+ params,
397
+ brief ? `${brief}
398
+
399
+ ${task}` : task,
400
+ cwd,
401
+ signal
402
+ );
404
403
  const entry = {
405
404
  abort: new AbortController(),
406
405
  cancelling: false,
@@ -410,43 +409,21 @@ ${recorded}` : message,
410
409
  freeSlot();
411
410
  showStatus();
412
411
  const started = Date.now();
413
- const waitArgs = (after) => [
414
- "agent",
415
- "wait",
416
- name,
417
- "-w",
418
- W,
419
- "--json",
420
- "--timeout",
421
- String(timeoutS),
422
- ...after !== void 0 ? ["--after-runs", String(after)] : []
423
- ];
424
- const plain = new AbortController();
425
- entry.abort.signal.addEventListener("abort", () => plain.abort(), { once: true });
426
- let waiting = mu(waitArgs(), plain.signal);
427
- const sent = await mu([
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
- }
412
+ const waiting = mu(
413
+ [
414
+ "agent",
415
+ "wait",
416
+ name,
417
+ "-w",
418
+ W,
419
+ "--json",
420
+ "--timeout",
421
+ String(timeoutS),
422
+ "--after-runs",
423
+ String(runs)
424
+ ],
425
+ entry.abort.signal
426
+ );
450
427
  const settle = async (r) => {
451
428
  forget(name);
452
429
  try {
@@ -501,7 +478,7 @@ ${task}` : task,
501
478
  };
502
479
  } finally {
503
480
  freeSlot();
504
- if (queuedAs) drain();
481
+ drain();
505
482
  }
506
483
  }
507
484
  pi.registerTool({
@@ -711,25 +688,31 @@ function readSkill() {
711
688
  }
712
689
  return void 0;
713
690
  }
691
+ var ENV_ASSIGN = /^[A-Za-z_][A-Za-z0-9_]*=/;
692
+ function muArgs(words) {
693
+ let at = 0;
694
+ while (at < words.length && ENV_ASSIGN.test(words[at] ?? "")) at++;
695
+ const cmd = words[at];
696
+ if (cmd !== "mu" && !cmd?.endsWith("/mu")) return void 0;
697
+ return words.slice(at + 1);
698
+ }
714
699
  function dispatchedWorkstreams(command) {
715
700
  const found = /* @__PURE__ */ new Set();
716
701
  for (const words of shellSegments(command)) {
717
- const at = words.findIndex((w) => w === "mu" || w.endsWith("/mu"));
718
- if (at < 0) continue;
719
- const [noun, verb] = [words[at + 1], words[at + 2]];
720
- const isSendSpawn = noun === "agent" && (verb === "send" || verb === "spawn");
721
- const isClaimFor = noun === "task" && verb === "claim" && words.includes("--for");
722
- if (!isSendSpawn && !isClaimFor) continue;
702
+ const args = muArgs(words);
703
+ if (args === void 0) continue;
704
+ const claim = claimOf(args);
705
+ if (claim !== void 0) {
706
+ if (claim.ws !== "scratch") found.add(claim.ws);
707
+ continue;
708
+ }
709
+ if (args[0] !== "agent" || args[1] !== "send" && args[1] !== "spawn") continue;
723
710
  let ws = "";
724
- for (let k = at + 3; k < words.length; k++) {
725
- const w = words[k] ?? "";
726
- if (w === "-w" || w === "--workstream") ws = words[k + 1] ?? "";
711
+ for (let k = 2; k < args.length; k++) {
712
+ const w = args[k] ?? "";
713
+ if (w === "-w" || w === "--workstream") ws = args[k + 1] ?? "";
727
714
  else if (w.startsWith("--workstream=")) ws = w.slice("--workstream=".length);
728
715
  }
729
- if (ws === "" && isClaimFor) {
730
- const ref = words[at + 3] ?? "";
731
- if (ref.includes("/")) ws = ref.split("/")[0] ?? "";
732
- }
733
716
  if (ws !== "scratch") found.add(ws);
734
717
  }
735
718
  return found.size > 0 ? [...found] : void 0;
@@ -739,6 +722,8 @@ function shellSegments(command) {
739
722
  const segs = [];
740
723
  let words = [];
741
724
  let word;
725
+ const heredocs = [];
726
+ let arithEnd = -1;
742
727
  const endWord = () => {
743
728
  if (word !== void 0) words.push(word);
744
729
  word = void 0;
@@ -748,6 +733,18 @@ function shellSegments(command) {
748
733
  if (words.length > 0) segs.push(words);
749
734
  words = [];
750
735
  };
736
+ const skipHeredocs = (i) => {
737
+ for (const h of heredocs.splice(0)) {
738
+ while (i < command.length) {
739
+ const eol = command.indexOf("\n", i + 1);
740
+ const end = eol < 0 ? command.length : eol;
741
+ const line = command.slice(i + 1, end);
742
+ i = end;
743
+ if ((h.strip ? line.replace(/^\t+/, "") : line) === h.delim) break;
744
+ }
745
+ }
746
+ return i;
747
+ };
751
748
  for (let i = 0; i < command.length; i++) {
752
749
  const c = command[i] ?? "";
753
750
  if (c === "'" || c === '"') {
@@ -755,11 +752,34 @@ function shellSegments(command) {
755
752
  const end = close < 0 ? command.length : close;
756
753
  word = (word ?? "") + command.slice(i + 1, end);
757
754
  i = end;
755
+ } else if (c === "\\" && command[i + 1] === "\n") {
756
+ i++;
758
757
  } else if (c === "\\" && i + 1 < command.length) {
759
758
  word = (word ?? "") + command[++i];
759
+ } else if (c === "#" && word === void 0) {
760
+ const eol = command.indexOf("\n", i);
761
+ i = (eol < 0 ? command.length : eol) - 1;
762
+ } else if (c === "(" && command[i + 1] === "(" && i > arithEnd) {
763
+ arithEnd = arithmeticEnd(command, i);
764
+ word = `${word ?? ""}((`;
765
+ i++;
766
+ } else if (command.startsWith("<<<", i)) {
767
+ endWord();
768
+ i += 2;
769
+ } else if (c === "<" && command[i + 1] === "<" && i > arithEnd) {
770
+ endWord();
771
+ const m = /^<<(-?)[ \t]*('([^']*)'|"([^"]*)"|[^\s;&|<>()]+)/.exec(command.slice(i));
772
+ if (!m) {
773
+ i++;
774
+ continue;
775
+ }
776
+ const delim = m[3] ?? m[4] ?? (m[2] ?? "").replace(/\\/g, "");
777
+ heredocs.push({ delim, strip: m[1] === "-" });
778
+ i += m[0].length - 1;
760
779
  } else if (c === ";" || c === "|" || c === "\n" || c === "&" && command[i + 1] === "&") {
761
780
  if (c !== ";" && c !== "\n" && command[i + 1] === c) i++;
762
781
  endSeg();
782
+ if (c === "\n" && heredocs.length > 0) i = skipHeredocs(i);
763
783
  } else if (/\s/.test(c)) {
764
784
  endWord();
765
785
  } else {
@@ -769,30 +789,53 @@ function shellSegments(command) {
769
789
  endSeg();
770
790
  return segs;
771
791
  }
792
+ function arithmeticEnd(command, open) {
793
+ let depth = 0;
794
+ for (let i = open + 2; i < command.length; i++) {
795
+ const c = command[i];
796
+ if (c === "'" || c === '"') {
797
+ const close = command.indexOf(c, i + 1);
798
+ if (close < 0) return -1;
799
+ i = close;
800
+ } else if (c === "\\") {
801
+ i++;
802
+ } else if (c === "(") {
803
+ depth++;
804
+ } else if (c === ")") {
805
+ if (depth > 0) depth--;
806
+ else return command[i + 1] === ")" ? i + 1 : -1;
807
+ }
808
+ }
809
+ return -1;
810
+ }
811
+ function claimOf(args) {
812
+ if (args[0] !== "task" || args[1] !== "claim") return void 0;
813
+ let ws = "";
814
+ let id;
815
+ let isFor = false;
816
+ for (let k = 2; k < args.length; k++) {
817
+ const w = args[k] ?? "";
818
+ const [opt, eq] = w.startsWith("--") && w.includes("=") ? w.split("=", 2) : [w, void 0];
819
+ if (opt === "--for" || opt === "-f") isFor = true;
820
+ if (opt === "-w" || opt === "--workstream") ws = eq ?? args[k + 1] ?? "";
821
+ if (CLAIM_VALUE_OPTS.has(opt ?? "")) {
822
+ if (eq === void 0) k++;
823
+ } else if (id === void 0 && !w.startsWith("-")) id = w;
824
+ }
825
+ if (!isFor || id === void 0) return void 0;
826
+ const slash = id.indexOf("/");
827
+ if (slash >= 0) {
828
+ if (ws === "") ws = id.slice(0, slash);
829
+ id = id.slice(slash + 1);
830
+ }
831
+ return { ws, id };
832
+ }
772
833
  function dispatchedTasks(command) {
773
834
  const out = [];
774
835
  for (const words of shellSegments(command)) {
775
- if (words[0] !== "mu" && !words[0]?.endsWith("/mu")) continue;
776
- if (words[1] !== "task" || words[2] !== "claim") continue;
777
- let ws = "";
778
- let id;
779
- let isFor = false;
780
- for (let k = 3; k < words.length; k++) {
781
- const w = words[k] ?? "";
782
- const [opt, eq] = w.startsWith("--") && w.includes("=") ? w.split("=", 2) : [w, void 0];
783
- if (opt === "--for" || opt === "-f") isFor = true;
784
- if (opt === "-w" || opt === "--workstream") ws = eq ?? words[k + 1] ?? "";
785
- if (CLAIM_VALUE_OPTS.has(opt ?? "")) {
786
- if (eq === void 0) k++;
787
- } else if (id === void 0 && !w.startsWith("-")) id = w;
788
- }
789
- if (!isFor || id === void 0) continue;
790
- const slash = id.indexOf("/");
791
- if (slash >= 0) {
792
- if (ws === "") ws = id.slice(0, slash);
793
- id = id.slice(slash + 1);
794
- }
795
- if (ws !== "scratch") out.push({ ws, id });
836
+ const args = muArgs(words);
837
+ const claim = args === void 0 ? void 0 : claimOf(args);
838
+ if (claim !== void 0 && claim.ws !== "scratch") out.push(claim);
796
839
  }
797
840
  return out;
798
841
  }
@@ -826,6 +869,54 @@ function nudgeText(rule, refs) {
826
869
  `${refs.length} task(s) IN_PROGRESS. Next: mu task wait ${shown} --first --on-stall exit --json${more}`
827
870
  ].join("\n");
828
871
  }
872
+ function breadcrumb(run, args) {
873
+ void run(args).catch(() => {
874
+ });
875
+ }
876
+ function parallelSettle(pi) {
877
+ const handlers = [];
878
+ const api = {
879
+ on(event, handler) {
880
+ if (event === "agent_before_settle") handlers.push(handler);
881
+ else pi.on(event, handler);
882
+ }
883
+ };
884
+ let errors = [];
885
+ return {
886
+ api,
887
+ flush() {
888
+ if (handlers.length === 0) return;
889
+ pi.on("agent_before_settle", async (event, ctx) => {
890
+ errors = handlers.map(() => void 0);
891
+ const results = await Promise.all(
892
+ handlers.map(async (h, i) => {
893
+ try {
894
+ return await h(event, ctx);
895
+ } catch (err) {
896
+ errors[i] = [err];
897
+ return void 0;
898
+ }
899
+ })
900
+ );
901
+ const fired = results.filter((r) => r !== void 0);
902
+ if (fired.length === 0) return void 0;
903
+ const prior = event?.entries ?? [];
904
+ return {
905
+ entries: [...prior, ...fired.flatMap((r) => r.entries ?? [])],
906
+ ...fired.some((r) => r.continue === true) ? { continue: true } : {}
907
+ };
908
+ });
909
+ handlers.forEach((_, i) => {
910
+ pi.on("agent_before_settle", () => {
911
+ const err = errors[i];
912
+ errors[i] = void 0;
913
+ if (err !== void 0) throw err[0];
914
+ return void 0;
915
+ });
916
+ });
917
+ }
918
+ };
919
+ }
829
920
  function outcomeOf(event) {
830
921
  return typeof event === "object" && event !== null ? event.outcome : void 0;
831
922
  }
@@ -857,7 +948,7 @@ function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested
857
948
  if (refs === void 0 || refs.length === 0) return;
858
949
  const text = nudgeText(rule, refs);
859
950
  const logWs = [...armed].find((w) => w !== "");
860
- await run([
951
+ breadcrumb(run, [
861
952
  "log",
862
953
  ...logWs ? ["-w", logWs] : [],
863
954
  "--kind",
@@ -913,7 +1004,7 @@ function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested
913
1004
  fired = true;
914
1005
  const names = await ownedInProgress(run, me.agent, me.workstream);
915
1006
  if (names === void 0 || names.length === 0) return;
916
- await run([
1007
+ breadcrumb(run, [
917
1008
  "log",
918
1009
  "-w",
919
1010
  me.workstream,
@@ -967,13 +1058,12 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
967
1058
  if (fired || armed.size === 0 || nested() || noUI(ctx)) return;
968
1059
  if (outcomeOf(event) !== "completed") return;
969
1060
  fired = true;
970
- const refs = [];
971
- for (const [ref, t] of armed) {
972
- if (await briefRefuted(run, t.ws, t.id) === false) refs.push(ref);
973
- }
1061
+ const tasks = [...armed];
1062
+ const refuted = await Promise.all(tasks.map(([, t]) => briefRefuted(run, t.ws, t.id)));
1063
+ const refs = tasks.flatMap(([ref], i) => refuted[i] === false ? [ref] : []);
974
1064
  if (refs.length === 0) return;
975
1065
  const logWs = [...armed.values()].find((t) => t.ws !== "")?.ws;
976
- await run([
1066
+ breadcrumb(run, [
977
1067
  "log",
978
1068
  ...logWs ? ["-w", logWs] : [],
979
1069
  "--kind",
@@ -994,7 +1084,7 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
994
1084
  }
995
1085
 
996
1086
  // extension/mu-pi.ts
997
- var EXT_VERSION = true ? "3.8.1" : void 0;
1087
+ var EXT_VERSION = true ? "3.10.0" : void 0;
998
1088
  var FRESH_COMMAND = "mu-fresh";
999
1089
  var FRESH_TIMEOUT_MS = 3e4;
1000
1090
  function commandName(name) {
@@ -1137,9 +1227,11 @@ function muPi(pi, run = defaultRunner()) {
1137
1227
  registerDelegate(pi, run);
1138
1228
  registerPrompts(pi);
1139
1229
  const nested = serveCtl(pi);
1140
- registerNudge(pi, run, void 0, nested);
1141
- registerCloseNudge(pi, run, process.env, nested);
1142
- registerRefuteNudge(pi, run, nested);
1230
+ const settle = parallelSettle(pi);
1231
+ registerNudge(settle.api, run, void 0, nested);
1232
+ registerCloseNudge(settle.api, run, process.env, nested);
1233
+ registerRefuteNudge(settle.api, run, nested);
1234
+ settle.flush();
1143
1235
  }
1144
1236
  function serveCtl(pi) {
1145
1237
  const sock = process.env.MU_CTL_SOCK;