@mu-crew/mu 3.11.3 → 3.13.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/dist/chunk-3BARPJLY.js +44 -0
- package/dist/{chunk-R2SVBZAB.js → chunk-45KQLMEL.js} +193 -93
- package/dist/chunk-45KQLMEL.js.map +1 -0
- package/dist/{chunk-3L5KO3PX.js → chunk-54WJCMJR.js} +12 -10
- package/dist/chunk-54WJCMJR.js.map +1 -0
- package/dist/{chunk-LEORAGKV.js → chunk-EPCEEDHG.js} +4 -3
- package/dist/{chunk-LEORAGKV.js.map → chunk-EPCEEDHG.js.map} +1 -1
- package/dist/{chunk-77GBZ2KR.js → chunk-QITLNZEM.js} +3 -1
- package/dist/{chunk-77GBZ2KR.js.map → chunk-QITLNZEM.js.map} +1 -1
- package/dist/{chunk-F7ZBF6I7.js → chunk-TXV34VWT.js} +8616 -6030
- package/dist/chunk-TXV34VWT.js.map +1 -0
- package/dist/{chunk-L2ABBTYG.js → chunk-WI6AWCMK.js} +3 -1
- package/dist/{chunk-L2ABBTYG.js.map → chunk-WI6AWCMK.js.map} +1 -1
- package/dist/{cli-GJIO7GWD.js → cli-GMJUOXPW.js} +3582 -107
- package/dist/cli-GMJUOXPW.js.map +1 -0
- package/dist/cli.js +4 -3
- package/dist/cli.js.map +1 -1
- package/dist/devtools-LS4ZEPWM.js +3772 -0
- package/dist/devtools-LS4ZEPWM.js.map +1 -0
- package/dist/extension/mu-pi.js +294 -78
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +311 -228
- package/dist/index.js +12 -5
- package/dist/tui-WSDDTA4K.js +40956 -0
- package/dist/tui-WSDDTA4K.js.map +1 -0
- package/dist/tui-sync-worker.js +4 -3
- package/dist/tui-sync-worker.js.map +1 -1
- package/dist/yank-XDOONQSL.js +13 -0
- package/docs/ARCHITECTURE.md +4 -1
- package/docs/ROADMAP.md +43 -38
- package/docs/VISION.md +8 -0
- package/docs/VOCABULARY.md +3 -1
- package/docs/architecture/control-socket.md +1 -1
- package/docs/architecture/dag.md +4 -0
- package/docs/architecture/sync.md +8 -0
- package/docs/architecture/tui.md +11 -2
- package/docs/guide/delegate.md +11 -4
- package/docs/guide/recovery.md +4 -0
- package/docs/reference/env.md +2 -2
- package/docs/reference/naming.md +1 -1
- package/package.json +2 -1
- package/skills/mu/SKILL.md +12 -2
- package/skills/mu/recipes/adversarial-review.md +3 -0
- package/skills/mu/recipes/backlog-triage.md +2 -0
- package/skills/mu/recipes/findings.md +7 -0
- package/skills/mu/recipes/long-run.md +3 -1
- package/skills/mu/recipes/loop-until-done.md +3 -1
- package/skills/mu/recipes/orchestrator-loop.md +4 -0
- package/skills/mu/recipes/ultrathink.md +3 -1
- package/skills/mu/recipes/watcher.md +6 -1
- package/dist/chunk-3L5KO3PX.js.map +0 -1
- package/dist/chunk-F7ZBF6I7.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-R2SVBZAB.js.map +0 -1
- package/dist/cli-GJIO7GWD.js.map +0 -1
- package/dist/tui-WHCLVCYE.js +0 -6452
- package/dist/tui-WHCLVCYE.js.map +0 -1
- package/dist/yank-T3AYQTVR.js +0 -12
- /package/dist/{chunk-PZ5AY32C.js.map → chunk-3BARPJLY.js.map} +0 -0
- /package/dist/{yank-T3AYQTVR.js.map → yank-XDOONQSL.js.map} +0 -0
package/dist/extension/mu-pi.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
linkSync,
|
|
6
6
|
mkdirSync as mkdirSync2,
|
|
7
7
|
readdirSync,
|
|
8
|
-
readFileSync as
|
|
8
|
+
readFileSync as readFileSync3,
|
|
9
9
|
realpathSync,
|
|
10
10
|
rmSync,
|
|
11
11
|
statSync as statSync2
|
|
@@ -44,7 +44,7 @@ var LineDecoder = class {
|
|
|
44
44
|
|
|
45
45
|
// extension/delegate.ts
|
|
46
46
|
import { execFile } from "child_process";
|
|
47
|
-
import { existsSync, mkdirSync, statSync, writeFileSync } from "fs";
|
|
47
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
48
48
|
import { delimiter, join as join2 } from "path";
|
|
49
49
|
import { fileURLToPath } from "url";
|
|
50
50
|
|
|
@@ -75,6 +75,7 @@ function delegateStatus(running, starting = 0, queued = 0, failed = 0, pending =
|
|
|
75
75
|
var DELEGATE_TIMEOUT_S = 3600;
|
|
76
76
|
var DELEGATE_MAX_DEFAULT = 16;
|
|
77
77
|
var DELEGATE_QUEUE_FACTOR = 4;
|
|
78
|
+
var PRUNE_FAILED_MS = 3e4;
|
|
78
79
|
function delegateMax(env = process.env) {
|
|
79
80
|
const n = Number(env.MU_DELEGATE_MAX);
|
|
80
81
|
return Number.isInteger(n) && n > 0 ? n : DELEGATE_MAX_DEFAULT;
|
|
@@ -116,6 +117,37 @@ function defaultRunner() {
|
|
|
116
117
|
);
|
|
117
118
|
});
|
|
118
119
|
}
|
|
120
|
+
function lastAssistantTextIn(sessionFile) {
|
|
121
|
+
let raw;
|
|
122
|
+
try {
|
|
123
|
+
raw = readFileSync(sessionFile, "utf8");
|
|
124
|
+
} catch {
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
const lines = raw.split("\n");
|
|
128
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
129
|
+
const line = lines[i];
|
|
130
|
+
if (!line?.includes('"assistant"')) continue;
|
|
131
|
+
try {
|
|
132
|
+
const e = JSON.parse(line);
|
|
133
|
+
if (e.message?.role !== "assistant") continue;
|
|
134
|
+
const c = e.message.content;
|
|
135
|
+
const text = typeof c === "string" ? c : Array.isArray(c) ? c.map((p) => {
|
|
136
|
+
const q = p;
|
|
137
|
+
return q.type === "text" && typeof q.text === "string" ? q.text : "";
|
|
138
|
+
}).join("") : "";
|
|
139
|
+
if (text.trim()) return text;
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
function evidenceLines(x) {
|
|
146
|
+
return [
|
|
147
|
+
x.partial ? `Partial answer so far: ${x.partial}` : void 0,
|
|
148
|
+
x.sessionFile ? `Session: ${x.sessionFile}` : void 0
|
|
149
|
+
].filter((v) => v !== void 0);
|
|
150
|
+
}
|
|
119
151
|
function formatElapsed(ms) {
|
|
120
152
|
const t = Math.max(0, Math.round(ms / 1e3));
|
|
121
153
|
if (t < 60) return `${t}s`;
|
|
@@ -137,31 +169,49 @@ function delegateMessage(name, agent, pane, x = {}) {
|
|
|
137
169
|
Pane tail:
|
|
138
170
|
${x.tail.trimEnd()}` : "";
|
|
139
171
|
const ws = x.workspace ? ` Workspace: ${x.workspace}` : "";
|
|
172
|
+
const ev = evidenceLines(x);
|
|
173
|
+
const evBlock = ev.length > 0 ? `
|
|
174
|
+
${ev.join("\n")}` : "";
|
|
140
175
|
switch (agent?.outcome) {
|
|
141
176
|
case "done":
|
|
142
177
|
return `${who} finished${took}. ${fate}${ws}
|
|
143
178
|
|
|
144
179
|
${agent.lastText ?? ""}`;
|
|
145
180
|
case "empty":
|
|
146
|
-
return `${who} finished${took} without a text answer. ${fate}${ws}${tailBlock}`;
|
|
181
|
+
return `${who} finished${took} without a text answer. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
147
182
|
case "error":
|
|
148
183
|
return [
|
|
149
184
|
`${who} stopped on an API error${took}, after pi's own retries: ${(agent.lastError ?? "unknown error").replace(/[.\s]+$/, "")}. ${fate}${ws}`,
|
|
150
185
|
"Decide: re-issue the call, or record the check as UNVERIFIED.",
|
|
186
|
+
...ev,
|
|
151
187
|
...look,
|
|
152
188
|
`Close: mu agent close ${name} -w ${W}`
|
|
153
189
|
].join("\n");
|
|
154
190
|
case "died":
|
|
155
|
-
return `${who} died${took} before answering. ${fate}${ws}${tailBlock}`;
|
|
191
|
+
return `${who} died${took} before answering. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
192
|
+
case "blocked": {
|
|
193
|
+
const b = agent.blocked;
|
|
194
|
+
const dialog = `${b?.kind ?? "dialog"}${b?.title ? ` "${b.title}"` : ""}`;
|
|
195
|
+
const lines = [
|
|
196
|
+
`${who} is blocked on a ${dialog} dialog${took} and has NOT finished; stopped waiting, so its answer will not arrive here. ${fate}${ws}`,
|
|
197
|
+
"Answer the dialog in its pane (attach), then wait again; or close it and record the check as UNVERIFIED.",
|
|
198
|
+
...ev,
|
|
199
|
+
...look,
|
|
200
|
+
`Wait again: mu agent wait ${name} -w ${W} --json${agent.afterRuns !== void 0 ? ` --after-runs ${agent.afterRuns}` : ""}`,
|
|
201
|
+
`Close: mu agent close ${name} -w ${W}`
|
|
202
|
+
];
|
|
203
|
+
return `${lines.join("\n")}${tailBlock}`;
|
|
204
|
+
}
|
|
156
205
|
case "timeout":
|
|
157
206
|
case "pending":
|
|
158
207
|
return [
|
|
159
208
|
`${who} is still running after ${timeoutS}s; stopped waiting, so its answer will not arrive here. ${fate}${ws}`,
|
|
209
|
+
...ev,
|
|
160
210
|
...look,
|
|
161
|
-
`Wait again: mu agent wait ${name} -w ${W} --json`
|
|
211
|
+
`Wait again: mu agent wait ${name} -w ${W} --json${agent.afterRuns !== void 0 ? ` --after-runs ${agent.afterRuns}` : ""}`
|
|
162
212
|
].join("\n");
|
|
163
213
|
default:
|
|
164
|
-
return `${who}: mu agent wait gave no result. ${fate}${ws}${tailBlock}`;
|
|
214
|
+
return `${who}: mu agent wait gave no result. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
165
215
|
}
|
|
166
216
|
}
|
|
167
217
|
function droppedAnswersDir() {
|
|
@@ -228,12 +278,13 @@ function modelCommand(cli, model, env = process.env) {
|
|
|
228
278
|
return `${base} --model ${shellArg(model)}`;
|
|
229
279
|
}
|
|
230
280
|
function registerDelegate(pi, run = defaultRunner()) {
|
|
231
|
-
if (!delegateEnabled()) return;
|
|
281
|
+
if (!delegateEnabled()) return { answerPending: () => false };
|
|
232
282
|
const inflight = /* @__PURE__ */ new Map();
|
|
233
283
|
let starting = 0;
|
|
234
284
|
const queue = [];
|
|
235
285
|
let queueSeq = 0;
|
|
236
286
|
const failed = /* @__PURE__ */ new Set();
|
|
287
|
+
let lastPruneAt = 0;
|
|
237
288
|
const arriving = /* @__PURE__ */ new Map();
|
|
238
289
|
let deliverySeq = 0;
|
|
239
290
|
let ui;
|
|
@@ -264,12 +315,12 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
264
315
|
const a = arriving.get(delivery);
|
|
265
316
|
if (a) a.queued = true;
|
|
266
317
|
};
|
|
267
|
-
const saveCopy = (name, content) => {
|
|
318
|
+
const saveCopy = (name, content, kind = "") => {
|
|
268
319
|
try {
|
|
269
320
|
const dir = droppedAnswersDir();
|
|
270
321
|
mkdirSync(dir, { recursive: true });
|
|
271
322
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
272
|
-
const path = join2(dir, `${stamp}_${name}.md`);
|
|
323
|
+
const path = join2(dir, `${stamp}_${name}${kind}.md`);
|
|
273
324
|
writeFileSync(path, `${content}
|
|
274
325
|
`);
|
|
275
326
|
return path;
|
|
@@ -277,6 +328,10 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
277
328
|
return void 0;
|
|
278
329
|
}
|
|
279
330
|
};
|
|
331
|
+
const partialCopy = (name, sessionFile) => {
|
|
332
|
+
const text = lastAssistantTextIn(sessionFile);
|
|
333
|
+
return text ? saveCopy(name, text, ".partial") : void 0;
|
|
334
|
+
};
|
|
280
335
|
const forget = (name) => {
|
|
281
336
|
inflight.delete(name);
|
|
282
337
|
drain();
|
|
@@ -319,6 +374,9 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
319
374
|
const failure = (what, r) => new Error(`${what} failed (exit ${r.code}): ${(r.stderr || r.stdout).trim()}`);
|
|
320
375
|
function pruneFailed() {
|
|
321
376
|
if (failed.size === 0) return;
|
|
377
|
+
const now = Date.now();
|
|
378
|
+
if (now - lastPruneAt < PRUNE_FAILED_MS) return;
|
|
379
|
+
lastPruneAt = now;
|
|
322
380
|
void mu(["agent", "list", "-w", W, "--json"]).then((r) => {
|
|
323
381
|
const agents = json(r)?.agents;
|
|
324
382
|
if (!Array.isArray(agents)) return;
|
|
@@ -354,6 +412,12 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
354
412
|
);
|
|
355
413
|
}
|
|
356
414
|
const sent = out.send;
|
|
415
|
+
if (sent?.ok !== true && sent?.error === "AgentSendIndeterminateError") {
|
|
416
|
+
const why = typeof sent.message === "string" ? sent.message : "no reply";
|
|
417
|
+
throw new Error(
|
|
418
|
+
`mu agent send to ${W}/${name}: delivery unknown (${why}). Pane kept; do NOT resend blindly. Check with: mu agent read ${name} -w ${W} -n 20 (or attach), then close it with: mu agent close ${name} -w ${W}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
357
421
|
if (sent?.ok !== true) {
|
|
358
422
|
const c = await mu(["agent", "close", name, "-w", W]);
|
|
359
423
|
const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
|
|
@@ -369,7 +433,8 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
369
433
|
// extension's reply carries no runs.
|
|
370
434
|
runs: typeof sent.runs === "number" ? sent.runs : 0,
|
|
371
435
|
...typeof attach === "string" ? { attach } : {},
|
|
372
|
-
...typeof wsPath === "string" ? { workspace: wsPath } : {}
|
|
436
|
+
...typeof wsPath === "string" ? { workspace: wsPath } : {},
|
|
437
|
+
...typeof sent.sessionFile === "string" ? { sessionFile: sent.sessionFile } : {}
|
|
373
438
|
};
|
|
374
439
|
}
|
|
375
440
|
const recordLabel = (params, name) => typeof params.label === "string" && params.label.trim() ? params.label.trim() : name;
|
|
@@ -405,21 +470,32 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
405
470
|
const outcome = agent?.outcome;
|
|
406
471
|
const tail = outcome === "done" || outcome === "timeout" || outcome === "pending" || outcome === "error" ? void 0 : (await mu(["agent", "read", name, "-n", "50", "-w", W])).stdout;
|
|
407
472
|
let pane = { closed: false, why: "keep: true" };
|
|
408
|
-
|
|
473
|
+
let closing;
|
|
474
|
+
if (outcome === "blocked") pane = { closed: false, why: "waiting on a dialog" };
|
|
475
|
+
else if (outcome !== "done" && outcome !== "empty")
|
|
409
476
|
pane = { closed: false, why: "kept as evidence" };
|
|
410
|
-
else if (!keep)
|
|
411
|
-
|
|
412
|
-
pane = c.code === 0 ? { closed: true } : { closed: false, why: `close refused: ${(c.stderr || c.stdout).trim()}` };
|
|
413
|
-
}
|
|
414
|
-
if (outcome === "error" && !pane.closed) {
|
|
415
|
-
failed.add(name);
|
|
416
|
-
showStatus();
|
|
417
|
-
}
|
|
418
|
-
const recorded = record ? await writeRecord(
|
|
477
|
+
else if (!keep) closing = mu(["agent", "close", name, "-w", W]);
|
|
478
|
+
const recording = record ? writeRecord(
|
|
419
479
|
record.target,
|
|
420
480
|
name,
|
|
421
481
|
recordNote(record.label, name, outcome, agent?.lastText, extras.elapsedMs ?? 0)
|
|
422
482
|
) : void 0;
|
|
483
|
+
const [closed, recorded] = await Promise.all([closing, recording]);
|
|
484
|
+
if (closed)
|
|
485
|
+
pane = closed.code === 0 ? { closed: true } : { closed: false, why: `close refused: ${(closed.stderr || closed.stdout).trim()}` };
|
|
486
|
+
if (outcome === "error" && !pane.closed) {
|
|
487
|
+
failed.add(name);
|
|
488
|
+
showStatus();
|
|
489
|
+
}
|
|
490
|
+
if (outcome !== "done") {
|
|
491
|
+
const sessionFile = agent?.sessionFile ?? extras.sessionFile;
|
|
492
|
+
const partial = sessionFile && outcome !== "blocked" ? partialCopy(name, sessionFile) : void 0;
|
|
493
|
+
extras = {
|
|
494
|
+
...extras,
|
|
495
|
+
...sessionFile ? { sessionFile } : {},
|
|
496
|
+
...partial ? { partial } : {}
|
|
497
|
+
};
|
|
498
|
+
}
|
|
423
499
|
const message = delegateMessage(name, agent, pane, { ...extras, ...tail ? { tail } : {} });
|
|
424
500
|
const content = recorded ? `${message}
|
|
425
501
|
|
|
@@ -445,6 +521,8 @@ ${recorded}` : message;
|
|
|
445
521
|
answer: outcome === "done" ? agent?.lastText ?? null : null,
|
|
446
522
|
elapsedMs: extras.elapsedMs ?? null,
|
|
447
523
|
workspace: extras.workspace ?? null,
|
|
524
|
+
sessionFile: agent?.sessionFile ?? extras.sessionFile ?? null,
|
|
525
|
+
partial: extras.partial ?? null,
|
|
448
526
|
delivery
|
|
449
527
|
}
|
|
450
528
|
},
|
|
@@ -476,7 +554,7 @@ ${recorded}` : message;
|
|
|
476
554
|
cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
477
555
|
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
478
556
|
}
|
|
479
|
-
const { name, runs, attach, workspace } = await spawn(
|
|
557
|
+
const { name, runs, attach, workspace, sessionFile } = await spawn(
|
|
480
558
|
params,
|
|
481
559
|
brief ? `${brief}
|
|
482
560
|
|
|
@@ -487,6 +565,7 @@ ${task}` : task,
|
|
|
487
565
|
const entry = {
|
|
488
566
|
abort: new AbortController(),
|
|
489
567
|
cancelling: false,
|
|
568
|
+
...sessionFile ? { sessionFile } : {},
|
|
490
569
|
...record ? { record: { target: record, label: recordLabel(params, name) } } : {}
|
|
491
570
|
};
|
|
492
571
|
inflight.set(name, entry);
|
|
@@ -522,7 +601,8 @@ ${task}` : task,
|
|
|
522
601
|
elapsedMs: Date.now() - started,
|
|
523
602
|
...queuedAs ? { queuedAs } : {},
|
|
524
603
|
...attach ? { attach } : {},
|
|
525
|
-
...workspace ? { workspace } : {}
|
|
604
|
+
...workspace ? { workspace } : {},
|
|
605
|
+
...entry.sessionFile ? { sessionFile: entry.sessionFile } : {}
|
|
526
606
|
},
|
|
527
607
|
delivery,
|
|
528
608
|
entry.record
|
|
@@ -733,6 +813,12 @@ ${task}` : task,
|
|
|
733
813
|
}
|
|
734
814
|
failed.delete(name);
|
|
735
815
|
let text = `Aborted ${W}/${name}.`;
|
|
816
|
+
const sessionFile = entry?.sessionFile;
|
|
817
|
+
const partial = sessionFile ? partialCopy(name, sessionFile) : void 0;
|
|
818
|
+
const evidence = evidenceLines({
|
|
819
|
+
...sessionFile ? { sessionFile } : {},
|
|
820
|
+
...partial ? { partial } : {}
|
|
821
|
+
});
|
|
736
822
|
if (entry?.record)
|
|
737
823
|
text += ` ${await writeRecord(entry.record.target, name, recordNote(entry.record.label, name, "cancelled", void 0, 0))}`;
|
|
738
824
|
if (params.keep === true) text += " Pane kept.";
|
|
@@ -740,6 +826,8 @@ ${task}` : task,
|
|
|
740
826
|
const c = await mu(["agent", "close", name, "-w", W]);
|
|
741
827
|
text += c.code === 0 ? " Pane closed." : ` Pane kept: close refused: ${(c.stderr || c.stdout).trim()}`;
|
|
742
828
|
}
|
|
829
|
+
if (evidence.length > 0) text += `
|
|
830
|
+
${evidence.join("\n")}`;
|
|
743
831
|
return { content: [{ type: "text", text }], details: { name, workstream: W } };
|
|
744
832
|
}
|
|
745
833
|
});
|
|
@@ -785,6 +873,9 @@ ${task}` : task,
|
|
|
785
873
|
}
|
|
786
874
|
if (inflight.size === 0 && queue.length === 0) return;
|
|
787
875
|
const names = [...inflight.keys()];
|
|
876
|
+
const sessions = [...inflight].flatMap(
|
|
877
|
+
([n, e]) => e.sessionFile ? [`${n}: ${e.sessionFile}`] : []
|
|
878
|
+
);
|
|
788
879
|
const never = queue.splice(0).map((q) => q.handle);
|
|
789
880
|
for (const e of inflight.values()) e.abort.abort();
|
|
790
881
|
inflight.clear();
|
|
@@ -795,6 +886,7 @@ ${task}` : task,
|
|
|
795
886
|
parts.push(
|
|
796
887
|
`${names.length} delegate${names.length === 1 ? "" : "s"} still running: ${names.join(", ")}. Their answers will not come back here; use mu agent wait <name> -w ${W} --json.`
|
|
797
888
|
);
|
|
889
|
+
if (sessions.length > 0) parts.push(`Sessions: ${sessions.join("; ")}.`);
|
|
798
890
|
if (never.length > 0)
|
|
799
891
|
parts.push(`${never.length} queued, never started: ${never.join(", ")}. Re-issue them.`);
|
|
800
892
|
const msg = parts.join(" ");
|
|
@@ -802,10 +894,11 @@ ${task}` : task,
|
|
|
802
894
|
else process.stderr.write(`mu: ${msg}
|
|
803
895
|
`);
|
|
804
896
|
});
|
|
897
|
+
return { answerPending: () => arriving.size > 0 };
|
|
805
898
|
}
|
|
806
899
|
|
|
807
900
|
// extension/nudge.ts
|
|
808
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
901
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
809
902
|
import { join as join3 } from "path";
|
|
810
903
|
var NUDGE_MESSAGE_TYPE = "mu-keep-driving";
|
|
811
904
|
var NUDGE_LOG_KIND = "nudge";
|
|
@@ -815,6 +908,10 @@ var MARK_START = "<!-- mu:keep-driving -->";
|
|
|
815
908
|
var MARK_END = "<!-- /mu:keep-driving -->";
|
|
816
909
|
var WAIT_HINT_MAX = 8;
|
|
817
910
|
var notNested = () => false;
|
|
911
|
+
var noHold = () => void 0;
|
|
912
|
+
function withQueuedInput(hold) {
|
|
913
|
+
return (ctx) => ctx?.hasPendingMessages?.() ? "answer" : hold(ctx);
|
|
914
|
+
}
|
|
818
915
|
function noUI(ctx) {
|
|
819
916
|
return ctx?.hasUI === false;
|
|
820
917
|
}
|
|
@@ -831,7 +928,7 @@ function keepDrivingRule(skillMd) {
|
|
|
831
928
|
function readSkill() {
|
|
832
929
|
for (const up of ["..", "../.."]) {
|
|
833
930
|
const p = join3(import.meta.dirname ?? "", up, "skills", "mu", "SKILL.md");
|
|
834
|
-
if (existsSync2(p)) return
|
|
931
|
+
if (existsSync2(p)) return readFileSync2(p, "utf8");
|
|
835
932
|
}
|
|
836
933
|
return void 0;
|
|
837
934
|
}
|
|
@@ -987,25 +1084,29 @@ function dispatchedTasks(command) {
|
|
|
987
1084
|
return out;
|
|
988
1085
|
}
|
|
989
1086
|
async function inProgress(run, workstreams) {
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1087
|
+
const results = await Promise.all(
|
|
1088
|
+
workstreams.map(async (w) => {
|
|
1089
|
+
const r = await run([
|
|
1090
|
+
"task",
|
|
1091
|
+
"list",
|
|
1092
|
+
"--status",
|
|
1093
|
+
"IN_PROGRESS",
|
|
1094
|
+
"--json",
|
|
1095
|
+
"--sort",
|
|
1096
|
+
"recency",
|
|
1097
|
+
...w ? ["-w", w] : []
|
|
1098
|
+
]);
|
|
1099
|
+
if (r.code !== 0) return void 0;
|
|
1100
|
+
try {
|
|
1101
|
+
const items = JSON.parse(r.stdout).items ?? [];
|
|
1102
|
+
return items.flatMap((t) => t.name ? [`${t.workstreamName ?? w}/${t.name}`] : []);
|
|
1103
|
+
} catch {
|
|
1104
|
+
return void 0;
|
|
1105
|
+
}
|
|
1106
|
+
})
|
|
1107
|
+
);
|
|
1108
|
+
if (results.some((r) => r === void 0)) return void 0;
|
|
1109
|
+
return [...new Set(results.flatMap((r) => r ?? []))];
|
|
1009
1110
|
}
|
|
1010
1111
|
function nudgeText(rule, refs) {
|
|
1011
1112
|
const shown = refs.slice(0, WAIT_HINT_MAX).join(" ");
|
|
@@ -1020,7 +1121,7 @@ function breadcrumb(run, args) {
|
|
|
1020
1121
|
void run(args).catch(() => {
|
|
1021
1122
|
});
|
|
1022
1123
|
}
|
|
1023
|
-
function parallelSettle(pi) {
|
|
1124
|
+
function parallelSettle(pi, hold = noHold) {
|
|
1024
1125
|
const handlers = [];
|
|
1025
1126
|
const api = {
|
|
1026
1127
|
on(event, handler) {
|
|
@@ -1045,7 +1146,15 @@ function parallelSettle(pi) {
|
|
|
1045
1146
|
}
|
|
1046
1147
|
})
|
|
1047
1148
|
);
|
|
1048
|
-
const
|
|
1149
|
+
const late = hold(ctx);
|
|
1150
|
+
const fired = results.flatMap((r) => {
|
|
1151
|
+
if (r === void 0) return [];
|
|
1152
|
+
if (late === "answer" || late === "blocked" && r.continue === true) {
|
|
1153
|
+
r.yielded?.();
|
|
1154
|
+
return [];
|
|
1155
|
+
}
|
|
1156
|
+
return [r];
|
|
1157
|
+
});
|
|
1049
1158
|
if (fired.length === 0) return void 0;
|
|
1050
1159
|
const prior = event?.entries ?? [];
|
|
1051
1160
|
return {
|
|
@@ -1072,7 +1181,7 @@ function bashCommand(event) {
|
|
|
1072
1181
|
const e = event;
|
|
1073
1182
|
return e.toolName === "bash" && typeof e.input?.command === "string" ? e.input.command : void 0;
|
|
1074
1183
|
}
|
|
1075
|
-
function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested = notNested) {
|
|
1184
|
+
function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested = notNested, hold = noHold) {
|
|
1076
1185
|
if (!nudgeEnabled()) return;
|
|
1077
1186
|
const rule = skillMd === void 0 ? void 0 : keepDrivingRule(skillMd);
|
|
1078
1187
|
if (rule === void 0) return;
|
|
@@ -1087,12 +1196,16 @@ function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested
|
|
|
1087
1196
|
if (cmd === void 0) return;
|
|
1088
1197
|
for (const ws of dispatchedWorkstreams(cmd) ?? []) armed.add(ws);
|
|
1089
1198
|
});
|
|
1090
|
-
pi.on("agent_before_settle", async (event) => {
|
|
1091
|
-
if (fired || armed.size === 0 || nested()) return;
|
|
1199
|
+
pi.on("agent_before_settle", async (event, ctx) => {
|
|
1200
|
+
if (fired || armed.size === 0 || nested() || hold(ctx)) return;
|
|
1092
1201
|
if (outcomeOf(event) !== "completed") return;
|
|
1093
1202
|
fired = true;
|
|
1094
1203
|
const refs = await inProgress(run, [...armed]);
|
|
1095
1204
|
if (refs === void 0 || refs.length === 0) return;
|
|
1205
|
+
if (hold(ctx)) {
|
|
1206
|
+
fired = false;
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1096
1209
|
const text = nudgeText(rule, refs);
|
|
1097
1210
|
const logWs = [...armed].find((w) => w !== "");
|
|
1098
1211
|
breadcrumb(run, [
|
|
@@ -1106,7 +1219,10 @@ function registerNudge(pi, run = defaultRunner(), skillMd = readSkill(), nested
|
|
|
1106
1219
|
entries: [
|
|
1107
1220
|
{ type: "custom_message", customType: NUDGE_MESSAGE_TYPE, content: text, display: true }
|
|
1108
1221
|
],
|
|
1109
|
-
continue: true
|
|
1222
|
+
continue: true,
|
|
1223
|
+
yielded: () => {
|
|
1224
|
+
fired = false;
|
|
1225
|
+
}
|
|
1110
1226
|
};
|
|
1111
1227
|
});
|
|
1112
1228
|
}
|
|
@@ -1137,7 +1253,7 @@ function closeNudgeText(workstream, names) {
|
|
|
1137
1253
|
"If you are blocked or need an answer, say so in one line and stop; the orchestrator will read your pane."
|
|
1138
1254
|
].join("\n");
|
|
1139
1255
|
}
|
|
1140
|
-
function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested = notNested) {
|
|
1256
|
+
function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested = notNested, hold = noHold) {
|
|
1141
1257
|
if (!nudgeEnabled(env)) return;
|
|
1142
1258
|
const me = workerIdentity(env);
|
|
1143
1259
|
if (me === void 0) return;
|
|
@@ -1146,11 +1262,15 @@ function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested
|
|
|
1146
1262
|
fired = false;
|
|
1147
1263
|
});
|
|
1148
1264
|
pi.on("agent_before_settle", async (event, ctx) => {
|
|
1149
|
-
if (fired || nested() || noUI(ctx)) return;
|
|
1265
|
+
if (fired || nested() || noUI(ctx) || hold(ctx)) return;
|
|
1150
1266
|
if (outcomeOf(event) !== "completed") return;
|
|
1151
1267
|
fired = true;
|
|
1152
1268
|
const names = await ownedInProgress(run, me.agent, me.workstream);
|
|
1153
1269
|
if (names === void 0 || names.length === 0) return;
|
|
1270
|
+
if (hold(ctx)) {
|
|
1271
|
+
fired = false;
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1154
1274
|
breadcrumb(run, [
|
|
1155
1275
|
"log",
|
|
1156
1276
|
"-w",
|
|
@@ -1168,7 +1288,10 @@ function registerCloseNudge(pi, run = defaultRunner(), env = process.env, nested
|
|
|
1168
1288
|
display: true
|
|
1169
1289
|
}
|
|
1170
1290
|
],
|
|
1171
|
-
continue: true
|
|
1291
|
+
continue: true,
|
|
1292
|
+
yielded: () => {
|
|
1293
|
+
fired = false;
|
|
1294
|
+
}
|
|
1172
1295
|
};
|
|
1173
1296
|
});
|
|
1174
1297
|
}
|
|
@@ -1186,8 +1309,9 @@ async function briefRefuted(run, ws, id) {
|
|
|
1186
1309
|
function refuteNudgeText(refs) {
|
|
1187
1310
|
return `[mu] dispatched ${refs.join(", ")} with an unrefuted brief: refute it (delegate, record) or note REFUTE-EXEMPT: <why>`;
|
|
1188
1311
|
}
|
|
1189
|
-
function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
1312
|
+
function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested, hold = noHold) {
|
|
1190
1313
|
if (!nudgeEnabled()) return;
|
|
1314
|
+
const answerDue = (ctx) => hold(ctx) === "answer";
|
|
1191
1315
|
const armed = /* @__PURE__ */ new Map();
|
|
1192
1316
|
let fired = false;
|
|
1193
1317
|
pi.on("input", () => {
|
|
@@ -1202,13 +1326,17 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1202
1326
|
}
|
|
1203
1327
|
});
|
|
1204
1328
|
pi.on("agent_before_settle", async (event, ctx) => {
|
|
1205
|
-
if (fired || armed.size === 0 || nested() || noUI(ctx)) return;
|
|
1329
|
+
if (fired || armed.size === 0 || nested() || noUI(ctx) || answerDue(ctx)) return;
|
|
1206
1330
|
if (outcomeOf(event) !== "completed") return;
|
|
1207
1331
|
fired = true;
|
|
1208
1332
|
const tasks = [...armed];
|
|
1209
1333
|
const refuted = await Promise.all(tasks.map(([, t]) => briefRefuted(run, t.ws, t.id)));
|
|
1210
1334
|
const refs = tasks.flatMap(([ref], i) => refuted[i] === false ? [ref] : []);
|
|
1211
1335
|
if (refs.length === 0) return;
|
|
1336
|
+
if (answerDue(ctx)) {
|
|
1337
|
+
fired = false;
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1212
1340
|
const logWs = [...armed.values()].find((t) => t.ws !== "")?.ws;
|
|
1213
1341
|
breadcrumb(run, [
|
|
1214
1342
|
"log",
|
|
@@ -1225,13 +1353,16 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1225
1353
|
content: refuteNudgeText(refs),
|
|
1226
1354
|
display: true
|
|
1227
1355
|
}
|
|
1228
|
-
]
|
|
1356
|
+
],
|
|
1357
|
+
yielded: () => {
|
|
1358
|
+
fired = false;
|
|
1359
|
+
}
|
|
1229
1360
|
};
|
|
1230
1361
|
});
|
|
1231
1362
|
}
|
|
1232
1363
|
|
|
1233
1364
|
// extension/mu-pi.ts
|
|
1234
|
-
var EXT_VERSION = true ? "3.
|
|
1365
|
+
var EXT_VERSION = true ? "3.13.0" : void 0;
|
|
1235
1366
|
var FRESH_COMMAND = "mu-fresh";
|
|
1236
1367
|
var FRESH_TIMEOUT_MS = 3e4;
|
|
1237
1368
|
function commandName(name) {
|
|
@@ -1253,7 +1384,7 @@ function detectPiVersion() {
|
|
|
1253
1384
|
for (let i = 0; i < 6; i++) {
|
|
1254
1385
|
const pkgPath = join4(dir, "package.json");
|
|
1255
1386
|
if (existsSync3(pkgPath)) {
|
|
1256
|
-
const pkg = JSON.parse(
|
|
1387
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
1257
1388
|
if (typeof pkg === "object" && pkg !== null) {
|
|
1258
1389
|
const { name, version } = pkg;
|
|
1259
1390
|
if (typeof name === "string" && /pi/.test(name) && typeof version === "string") {
|
|
@@ -1321,6 +1452,50 @@ function capText(text) {
|
|
|
1321
1452
|
return `${cut.replace(/\uFFFD$/, "")}
|
|
1322
1453
|
${LAST_TEXT_TRUNCATED}`;
|
|
1323
1454
|
}
|
|
1455
|
+
var UI_PROMPTS = /* @__PURE__ */ Symbol.for("mu.pi.uiPrompts");
|
|
1456
|
+
function uiPrompts() {
|
|
1457
|
+
const g = globalThis;
|
|
1458
|
+
g[UI_PROMPTS] ??= { open: [], since: 0 };
|
|
1459
|
+
return g[UI_PROMPTS];
|
|
1460
|
+
}
|
|
1461
|
+
function uiBlocked() {
|
|
1462
|
+
const u = uiPrompts();
|
|
1463
|
+
const top = u.open[u.open.length - 1];
|
|
1464
|
+
if (!top) return void 0;
|
|
1465
|
+
return {
|
|
1466
|
+
kind: top.kind,
|
|
1467
|
+
...top.title !== void 0 ? { title: top.title } : {},
|
|
1468
|
+
since: u.since
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
function isUiBlocked() {
|
|
1472
|
+
return uiPrompts().open.length > 0;
|
|
1473
|
+
}
|
|
1474
|
+
function promptOf(event) {
|
|
1475
|
+
const e = typeof event === "object" && event !== null ? event : {};
|
|
1476
|
+
const kind = typeof e.kind === "string" ? e.kind : "custom";
|
|
1477
|
+
const title = typeof e.title === "string" && e.title !== "" ? e.title : void 0;
|
|
1478
|
+
return { kind, ...title !== void 0 ? { title } : {} };
|
|
1479
|
+
}
|
|
1480
|
+
function trackUiPrompts(pi, onStart = () => {
|
|
1481
|
+
}) {
|
|
1482
|
+
pi.on("ui_prompt_start", (e) => {
|
|
1483
|
+
const u = uiPrompts();
|
|
1484
|
+
if (u.open.length === 0) u.since = Date.now();
|
|
1485
|
+
u.open.push(promptOf(e));
|
|
1486
|
+
onStart();
|
|
1487
|
+
});
|
|
1488
|
+
pi.on("session_start", () => {
|
|
1489
|
+
uiPrompts().open.length = 0;
|
|
1490
|
+
});
|
|
1491
|
+
pi.on("ui_prompt_end", (e) => {
|
|
1492
|
+
const u = uiPrompts();
|
|
1493
|
+
const { kind } = promptOf(e);
|
|
1494
|
+
let i = u.open.length - 1;
|
|
1495
|
+
while (i >= 0 && u.open[i]?.kind !== kind) i--;
|
|
1496
|
+
u.open.splice(i >= 0 ? i : u.open.length - 1, 1);
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1324
1499
|
function inodeOf(path) {
|
|
1325
1500
|
try {
|
|
1326
1501
|
return statSync2(path).ino;
|
|
@@ -1371,18 +1546,24 @@ function registerPrompts(pi) {
|
|
|
1371
1546
|
});
|
|
1372
1547
|
}
|
|
1373
1548
|
function muPi(pi, run = defaultRunner()) {
|
|
1374
|
-
registerDelegate(pi, run);
|
|
1549
|
+
const delegates = registerDelegate(pi, run);
|
|
1375
1550
|
registerPrompts(pi);
|
|
1376
1551
|
const nested = serveCtl(pi);
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1552
|
+
const hold = withQueuedInput(
|
|
1553
|
+
() => delegates.answerPending() ? "answer" : isUiBlocked() ? "blocked" : void 0
|
|
1554
|
+
);
|
|
1555
|
+
const settle = parallelSettle(pi, hold);
|
|
1556
|
+
registerNudge(settle.api, run, void 0, nested, hold);
|
|
1557
|
+
registerCloseNudge(settle.api, run, process.env, nested, hold);
|
|
1558
|
+
registerRefuteNudge(settle.api, run, nested, hold);
|
|
1381
1559
|
settle.flush();
|
|
1382
1560
|
}
|
|
1383
1561
|
function serveCtl(pi) {
|
|
1384
1562
|
const sock = process.env.MU_CTL_SOCK;
|
|
1385
|
-
if (!sock)
|
|
1563
|
+
if (!sock) {
|
|
1564
|
+
trackUiPrompts(pi);
|
|
1565
|
+
return () => false;
|
|
1566
|
+
}
|
|
1386
1567
|
const sockPath = sock;
|
|
1387
1568
|
const piVersion = detectPiVersion();
|
|
1388
1569
|
const map = sharedMap();
|
|
@@ -1404,7 +1585,16 @@ function serveCtl(pi) {
|
|
|
1404
1585
|
state: g.state,
|
|
1405
1586
|
since: g.since,
|
|
1406
1587
|
runs: g.runs,
|
|
1407
|
-
pending: g.ctx?.hasPendingMessages() ?? false
|
|
1588
|
+
pending: g.ctx?.hasPendingMessages() ?? false,
|
|
1589
|
+
...sessionFileOf(g.ctx),
|
|
1590
|
+
...blockedField()
|
|
1591
|
+
});
|
|
1592
|
+
const blockedField = () => {
|
|
1593
|
+
const b = uiBlocked();
|
|
1594
|
+
return b ? { blocked: b } : {};
|
|
1595
|
+
};
|
|
1596
|
+
trackUiPrompts(pi, () => {
|
|
1597
|
+
for (const w of [...g.waiters]) w("blocked");
|
|
1408
1598
|
});
|
|
1409
1599
|
const settleFresh = (r) => {
|
|
1410
1600
|
const f = g.fresh;
|
|
@@ -1428,6 +1618,14 @@ function serveCtl(pi) {
|
|
|
1428
1618
|
g.endText = lastAssistantText(e);
|
|
1429
1619
|
g.endError = lastAssistantError(e);
|
|
1430
1620
|
});
|
|
1621
|
+
function sessionFileOf(c) {
|
|
1622
|
+
try {
|
|
1623
|
+
const f = c?.sessionManager?.getSessionFile();
|
|
1624
|
+
return f ? { sessionFile: f } : {};
|
|
1625
|
+
} catch {
|
|
1626
|
+
return {};
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1431
1629
|
pi.on("agent_settled", (_e, c) => {
|
|
1432
1630
|
g.ctx = c;
|
|
1433
1631
|
g.state = "idle";
|
|
@@ -1437,12 +1635,8 @@ function serveCtl(pi) {
|
|
|
1437
1635
|
g.endText = void 0;
|
|
1438
1636
|
g.lastError = g.endError;
|
|
1439
1637
|
g.endError = void 0;
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
} catch {
|
|
1443
|
-
g.sessionFile = void 0;
|
|
1444
|
-
}
|
|
1445
|
-
for (const w of [...g.waiters]) w();
|
|
1638
|
+
g.sessionFile = sessionFileOf(c).sessionFile;
|
|
1639
|
+
for (const w of [...g.waiters]) w("settle");
|
|
1446
1640
|
});
|
|
1447
1641
|
pi.registerCommand(FRESH_COMMAND, {
|
|
1448
1642
|
description: "mu internal: new session + the prompt mu queued (run by mu agent send --fresh)",
|
|
@@ -1572,11 +1766,19 @@ function serveCtl(pi) {
|
|
|
1572
1766
|
case "command":
|
|
1573
1767
|
return command(req);
|
|
1574
1768
|
case "wait":
|
|
1575
|
-
return wait(
|
|
1769
|
+
return wait(
|
|
1770
|
+
num(req, "afterRuns"),
|
|
1771
|
+
num(req, "timeoutMs"),
|
|
1772
|
+
conn,
|
|
1773
|
+
req.returnOnBlocked === true
|
|
1774
|
+
);
|
|
1576
1775
|
case "abort":
|
|
1577
1776
|
if (!g.ctx) return fail("no pi context yet");
|
|
1578
|
-
|
|
1579
|
-
|
|
1777
|
+
{
|
|
1778
|
+
const wasBusy = !g.ctx.isIdle();
|
|
1779
|
+
if (wasBusy) g.ctx.abort();
|
|
1780
|
+
return { v: V, ok: true, state: g.state, wasBusy };
|
|
1781
|
+
}
|
|
1580
1782
|
case "interrupt":
|
|
1581
1783
|
return interrupt(req, conn);
|
|
1582
1784
|
default:
|
|
@@ -1604,10 +1806,18 @@ function serveCtl(pi) {
|
|
|
1604
1806
|
...g.lastError !== void 0 ? { lastError: g.lastError } : {},
|
|
1605
1807
|
...g.sessionFile !== void 0 ? { sessionFile: g.sessionFile } : {}
|
|
1606
1808
|
});
|
|
1607
|
-
function wait(afterRuns, timeoutMs, conn) {
|
|
1809
|
+
function wait(afterRuns, timeoutMs, conn, onBlocked = false) {
|
|
1608
1810
|
if (afterRuns !== void 0 && g.runs > afterRuns && g.state === "idle") {
|
|
1609
|
-
return Promise.resolve({
|
|
1811
|
+
return Promise.resolve({
|
|
1812
|
+
v: V,
|
|
1813
|
+
ok: true,
|
|
1814
|
+
...status(),
|
|
1815
|
+
...settledRun(),
|
|
1816
|
+
ended: "settled"
|
|
1817
|
+
});
|
|
1610
1818
|
}
|
|
1819
|
+
const blockedReply = () => ({ v: V, ok: true, ...status(), ended: "blocked" });
|
|
1820
|
+
if (onBlocked && isUiBlocked()) return Promise.resolve(blockedReply());
|
|
1611
1821
|
return new Promise((resolve) => {
|
|
1612
1822
|
let timer;
|
|
1613
1823
|
const done = (r) => {
|
|
@@ -1616,9 +1826,13 @@ function serveCtl(pi) {
|
|
|
1616
1826
|
conn.off("close", onClose);
|
|
1617
1827
|
resolve(r);
|
|
1618
1828
|
};
|
|
1619
|
-
const waiter = () => {
|
|
1829
|
+
const waiter = (why) => {
|
|
1830
|
+
if (why === "blocked") {
|
|
1831
|
+
if (onBlocked) done(blockedReply());
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1620
1834
|
if (afterRuns !== void 0 && g.runs <= afterRuns) return;
|
|
1621
|
-
done({ v: V, ok: true, ...status(), ...settledRun() });
|
|
1835
|
+
done({ v: V, ok: true, ...status(), ...settledRun(), ended: "settled" });
|
|
1622
1836
|
};
|
|
1623
1837
|
const onClose = () => done(fail("client closed"));
|
|
1624
1838
|
g.waiters.add(waiter);
|
|
@@ -1740,8 +1954,10 @@ export {
|
|
|
1740
1954
|
LIVE_PROBE_MS,
|
|
1741
1955
|
commandName,
|
|
1742
1956
|
muPi as default,
|
|
1957
|
+
isUiBlocked,
|
|
1743
1958
|
lastAssistantError,
|
|
1744
1959
|
lastAssistantText,
|
|
1745
|
-
promptsDir
|
|
1960
|
+
promptsDir,
|
|
1961
|
+
uiBlocked
|
|
1746
1962
|
};
|
|
1747
1963
|
//# sourceMappingURL=mu-pi.js.map
|