@mu-crew/mu 3.11.2 → 3.12.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/AGENTS.md +2 -1
- package/dist/{chunk-JYZUNPPO.js → chunk-IRPTNVJC.js} +26 -23
- package/dist/chunk-IRPTNVJC.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-WYBOR4FX.js → chunk-R2SVBZAB.js} +20 -4
- package/dist/chunk-R2SVBZAB.js.map +1 -0
- package/dist/{chunk-2FJK6OOZ.js → chunk-TEGZOXML.js} +3 -3
- package/dist/{chunk-DXKJY3NT.js → chunk-XV7J56GD.js} +3 -3
- package/dist/{cli-GRAPF5VC.js → cli-MDCJEU74.js} +10 -8
- package/dist/cli-MDCJEU74.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/extension/mu-pi.js +204 -43
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -4
- package/dist/{tui-DGDEH4JX.js → tui-LO75XA3O.js} +5 -5
- package/dist/tui-sync-worker.js +2 -2
- package/docs/architecture/control-socket.md +2 -2
- package/docs/guide/delegate.md +12 -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-TEGZOXML.js.map} +0 -0
- /package/dist/{chunk-DXKJY3NT.js.map → chunk-XV7J56GD.js.map} +0 -0
- /package/dist/{tui-DGDEH4JX.js.map → tui-LO75XA3O.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-MDCJEU74.js");
|
|
51
51
|
await runCli(process.argv);
|
|
52
52
|
//# sourceMappingURL=cli.js.map
|
package/dist/extension/mu-pi.js
CHANGED
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
chmodSync,
|
|
4
4
|
existsSync as existsSync3,
|
|
5
5
|
linkSync,
|
|
6
|
-
mkdirSync,
|
|
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
|
|
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, readFileSync, 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;
|
|
@@ -106,6 +116,37 @@ function defaultRunner() {
|
|
|
106
116
|
);
|
|
107
117
|
});
|
|
108
118
|
}
|
|
119
|
+
function lastAssistantTextIn(sessionFile) {
|
|
120
|
+
let raw;
|
|
121
|
+
try {
|
|
122
|
+
raw = readFileSync(sessionFile, "utf8");
|
|
123
|
+
} catch {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
const lines = raw.split("\n");
|
|
127
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
128
|
+
const line = lines[i];
|
|
129
|
+
if (!line?.includes('"assistant"')) continue;
|
|
130
|
+
try {
|
|
131
|
+
const e = JSON.parse(line);
|
|
132
|
+
if (e.message?.role !== "assistant") continue;
|
|
133
|
+
const c = e.message.content;
|
|
134
|
+
const text = typeof c === "string" ? c : Array.isArray(c) ? c.map((p) => {
|
|
135
|
+
const q = p;
|
|
136
|
+
return q.type === "text" && typeof q.text === "string" ? q.text : "";
|
|
137
|
+
}).join("") : "";
|
|
138
|
+
if (text.trim()) return text;
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
144
|
+
function evidenceLines(x) {
|
|
145
|
+
return [
|
|
146
|
+
x.partial ? `Partial answer so far: ${x.partial}` : void 0,
|
|
147
|
+
x.sessionFile ? `Session: ${x.sessionFile}` : void 0
|
|
148
|
+
].filter((v) => v !== void 0);
|
|
149
|
+
}
|
|
109
150
|
function formatElapsed(ms) {
|
|
110
151
|
const t = Math.max(0, Math.round(ms / 1e3));
|
|
111
152
|
if (t < 60) return `${t}s`;
|
|
@@ -127,33 +168,61 @@ function delegateMessage(name, agent, pane, x = {}) {
|
|
|
127
168
|
Pane tail:
|
|
128
169
|
${x.tail.trimEnd()}` : "";
|
|
129
170
|
const ws = x.workspace ? ` Workspace: ${x.workspace}` : "";
|
|
171
|
+
const ev = evidenceLines(x);
|
|
172
|
+
const evBlock = ev.length > 0 ? `
|
|
173
|
+
${ev.join("\n")}` : "";
|
|
130
174
|
switch (agent?.outcome) {
|
|
131
175
|
case "done":
|
|
132
176
|
return `${who} finished${took}. ${fate}${ws}
|
|
133
177
|
|
|
134
178
|
${agent.lastText ?? ""}`;
|
|
135
179
|
case "empty":
|
|
136
|
-
return `${who} finished${took} without a text answer. ${fate}${ws}${tailBlock}`;
|
|
180
|
+
return `${who} finished${took} without a text answer. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
137
181
|
case "error":
|
|
138
182
|
return [
|
|
139
183
|
`${who} stopped on an API error${took}, after pi's own retries: ${(agent.lastError ?? "unknown error").replace(/[.\s]+$/, "")}. ${fate}${ws}`,
|
|
140
184
|
"Decide: re-issue the call, or record the check as UNVERIFIED.",
|
|
185
|
+
...ev,
|
|
141
186
|
...look,
|
|
142
187
|
`Close: mu agent close ${name} -w ${W}`
|
|
143
188
|
].join("\n");
|
|
144
189
|
case "died":
|
|
145
|
-
return `${who} died${took} before answering. ${fate}${ws}${tailBlock}`;
|
|
190
|
+
return `${who} died${took} before answering. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
146
191
|
case "timeout":
|
|
147
192
|
case "pending":
|
|
148
193
|
return [
|
|
149
194
|
`${who} is still running after ${timeoutS}s; stopped waiting, so its answer will not arrive here. ${fate}${ws}`,
|
|
195
|
+
...ev,
|
|
150
196
|
...look,
|
|
151
197
|
`Wait again: mu agent wait ${name} -w ${W} --json`
|
|
152
198
|
].join("\n");
|
|
153
199
|
default:
|
|
154
|
-
return `${who}: mu agent wait gave no result. ${fate}${ws}${tailBlock}`;
|
|
200
|
+
return `${who}: mu agent wait gave no result. ${fate}${ws}${evBlock}${tailBlock}`;
|
|
155
201
|
}
|
|
156
202
|
}
|
|
203
|
+
function droppedAnswersDir() {
|
|
204
|
+
return join2(defaultCacheDir(), "delegate-answers");
|
|
205
|
+
}
|
|
206
|
+
function droppedNote(dropped) {
|
|
207
|
+
const n = dropped.length;
|
|
208
|
+
const lines = dropped.map((d) => {
|
|
209
|
+
const how = [
|
|
210
|
+
d.outcome ?? "no result",
|
|
211
|
+
d.elapsedMs !== void 0 ? formatElapsed(d.elapsedMs) : void 0
|
|
212
|
+
].filter((x) => x !== void 0).join(", ");
|
|
213
|
+
const where = [
|
|
214
|
+
d.copy ? `answer: ${d.copy}` : void 0,
|
|
215
|
+
d.sessionFile ? `session: ${d.sessionFile}` : void 0
|
|
216
|
+
].filter((x) => x !== void 0);
|
|
217
|
+
if (where.length === 0) where.push(`read: mu agent read ${d.name} -n 50 -w ${W}`);
|
|
218
|
+
return `- ${W}/${d.name} (${how}) ${where.join(" \xB7 ")}`;
|
|
219
|
+
});
|
|
220
|
+
return [
|
|
221
|
+
`The interrupt dropped ${n} delegate answer${n === 1 ? "" : "s"} before ${n === 1 ? "it" : "they"} arrived:`,
|
|
222
|
+
...lines,
|
|
223
|
+
"The answer file holds the message that would have arrived; in a session file the answer is the last assistant message."
|
|
224
|
+
].join("\n");
|
|
225
|
+
}
|
|
157
226
|
var RECORD_NOTE_MAX = 4e3;
|
|
158
227
|
var RECORD_FALLBACK_TAIL = 1500;
|
|
159
228
|
var VERDICT_LINE = /^[\s>*_`-]*VERDICT:/;
|
|
@@ -227,6 +296,27 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
227
296
|
const track = (ctx) => {
|
|
228
297
|
if (ctx?.hasUI !== false && ctx?.ui) ui = ctx.ui;
|
|
229
298
|
};
|
|
299
|
+
const markQueued = (delivery) => {
|
|
300
|
+
const a = arriving.get(delivery);
|
|
301
|
+
if (a) a.queued = true;
|
|
302
|
+
};
|
|
303
|
+
const saveCopy = (name, content, kind = "") => {
|
|
304
|
+
try {
|
|
305
|
+
const dir = droppedAnswersDir();
|
|
306
|
+
mkdirSync(dir, { recursive: true });
|
|
307
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
308
|
+
const path = join2(dir, `${stamp}_${name}${kind}.md`);
|
|
309
|
+
writeFileSync(path, `${content}
|
|
310
|
+
`);
|
|
311
|
+
return path;
|
|
312
|
+
} catch {
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
const partialCopy = (name, sessionFile) => {
|
|
317
|
+
const text = lastAssistantTextIn(sessionFile);
|
|
318
|
+
return text ? saveCopy(name, text, ".partial") : void 0;
|
|
319
|
+
};
|
|
230
320
|
const forget = (name) => {
|
|
231
321
|
inflight.delete(name);
|
|
232
322
|
drain();
|
|
@@ -319,7 +409,8 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
319
409
|
// extension's reply carries no runs.
|
|
320
410
|
runs: typeof sent.runs === "number" ? sent.runs : 0,
|
|
321
411
|
...typeof attach === "string" ? { attach } : {},
|
|
322
|
-
...typeof wsPath === "string" ? { workspace: wsPath } : {}
|
|
412
|
+
...typeof wsPath === "string" ? { workspace: wsPath } : {},
|
|
413
|
+
...typeof sent.sessionFile === "string" ? { sessionFile: sent.sessionFile } : {}
|
|
323
414
|
};
|
|
324
415
|
}
|
|
325
416
|
const recordLabel = (params, name) => typeof params.label === "string" && params.label.trim() ? params.label.trim() : name;
|
|
@@ -365,18 +456,36 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
365
456
|
failed.add(name);
|
|
366
457
|
showStatus();
|
|
367
458
|
}
|
|
459
|
+
if (outcome !== "done") {
|
|
460
|
+
const sessionFile = agent?.sessionFile ?? extras.sessionFile;
|
|
461
|
+
const partial = sessionFile ? partialCopy(name, sessionFile) : void 0;
|
|
462
|
+
extras = {
|
|
463
|
+
...extras,
|
|
464
|
+
...sessionFile ? { sessionFile } : {},
|
|
465
|
+
...partial ? { partial } : {}
|
|
466
|
+
};
|
|
467
|
+
}
|
|
368
468
|
const recorded = record ? await writeRecord(
|
|
369
469
|
record.target,
|
|
370
470
|
name,
|
|
371
471
|
recordNote(record.label, name, outcome, agent?.lastText, extras.elapsedMs ?? 0)
|
|
372
472
|
) : void 0;
|
|
373
473
|
const message = delegateMessage(name, agent, pane, { ...extras, ...tail ? { tail } : {} });
|
|
474
|
+
const content = recorded ? `${message}
|
|
475
|
+
|
|
476
|
+
${recorded}` : message;
|
|
477
|
+
const a = arriving.get(delivery);
|
|
478
|
+
if (a)
|
|
479
|
+
Object.assign(a, {
|
|
480
|
+
content,
|
|
481
|
+
...outcome ? { outcome } : {},
|
|
482
|
+
...extras.elapsedMs !== void 0 ? { elapsedMs: extras.elapsedMs } : {},
|
|
483
|
+
...agent?.sessionFile ? { sessionFile: agent.sessionFile } : {}
|
|
484
|
+
});
|
|
374
485
|
await pi.sendMessage(
|
|
375
486
|
{
|
|
376
487
|
customType: DELEGATE_MESSAGE_TYPE,
|
|
377
|
-
content
|
|
378
|
-
|
|
379
|
-
${recorded}` : message,
|
|
488
|
+
content,
|
|
380
489
|
display: true,
|
|
381
490
|
details: {
|
|
382
491
|
name,
|
|
@@ -386,6 +495,8 @@ ${recorded}` : message,
|
|
|
386
495
|
answer: outcome === "done" ? agent?.lastText ?? null : null,
|
|
387
496
|
elapsedMs: extras.elapsedMs ?? null,
|
|
388
497
|
workspace: extras.workspace ?? null,
|
|
498
|
+
sessionFile: agent?.sessionFile ?? extras.sessionFile ?? null,
|
|
499
|
+
partial: extras.partial ?? null,
|
|
389
500
|
delivery
|
|
390
501
|
}
|
|
391
502
|
},
|
|
@@ -417,7 +528,7 @@ ${recorded}` : message,
|
|
|
417
528
|
cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
418
529
|
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
419
530
|
}
|
|
420
|
-
const { name, runs, attach, workspace } = await spawn(
|
|
531
|
+
const { name, runs, attach, workspace, sessionFile } = await spawn(
|
|
421
532
|
params,
|
|
422
533
|
brief ? `${brief}
|
|
423
534
|
|
|
@@ -428,6 +539,7 @@ ${task}` : task,
|
|
|
428
539
|
const entry = {
|
|
429
540
|
abort: new AbortController(),
|
|
430
541
|
cancelling: false,
|
|
542
|
+
...sessionFile ? { sessionFile } : {},
|
|
431
543
|
...record ? { record: { target: record, label: recordLabel(params, name) } } : {}
|
|
432
544
|
};
|
|
433
545
|
inflight.set(name, entry);
|
|
@@ -451,7 +563,7 @@ ${task}` : task,
|
|
|
451
563
|
);
|
|
452
564
|
const settle = async (r) => {
|
|
453
565
|
const delivery = ++deliverySeq;
|
|
454
|
-
arriving.set(delivery, false);
|
|
566
|
+
arriving.set(delivery, { queued: false, name });
|
|
455
567
|
forget(name);
|
|
456
568
|
try {
|
|
457
569
|
await deliver(
|
|
@@ -463,27 +575,34 @@ ${task}` : task,
|
|
|
463
575
|
elapsedMs: Date.now() - started,
|
|
464
576
|
...queuedAs ? { queuedAs } : {},
|
|
465
577
|
...attach ? { attach } : {},
|
|
466
|
-
...workspace ? { workspace } : {}
|
|
578
|
+
...workspace ? { workspace } : {},
|
|
579
|
+
...entry.sessionFile ? { sessionFile: entry.sessionFile } : {}
|
|
467
580
|
},
|
|
468
581
|
delivery,
|
|
469
582
|
entry.record
|
|
470
583
|
);
|
|
471
|
-
|
|
584
|
+
markQueued(delivery);
|
|
472
585
|
} catch (e) {
|
|
586
|
+
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}`;
|
|
587
|
+
const a = arriving.get(delivery);
|
|
588
|
+
if (a) a.content = content;
|
|
473
589
|
await Promise.resolve(
|
|
474
590
|
pi.sendMessage(
|
|
475
591
|
{
|
|
476
592
|
customType: DELEGATE_MESSAGE_TYPE,
|
|
477
|
-
content
|
|
593
|
+
content,
|
|
478
594
|
display: true,
|
|
479
595
|
details: { name, workstream: W, outcome: null, closed: false, delivery }
|
|
480
596
|
},
|
|
481
597
|
{ deliverAs: "followUp", triggerTurn: true }
|
|
482
598
|
)
|
|
483
|
-
).
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
599
|
+
).then(
|
|
600
|
+
() => markQueued(delivery),
|
|
601
|
+
() => {
|
|
602
|
+
arriving.delete(delivery);
|
|
603
|
+
showStatus();
|
|
604
|
+
}
|
|
605
|
+
);
|
|
487
606
|
}
|
|
488
607
|
};
|
|
489
608
|
void waiting.then(async (r) => {
|
|
@@ -668,6 +787,12 @@ ${task}` : task,
|
|
|
668
787
|
}
|
|
669
788
|
failed.delete(name);
|
|
670
789
|
let text = `Aborted ${W}/${name}.`;
|
|
790
|
+
const sessionFile = entry?.sessionFile;
|
|
791
|
+
const partial = sessionFile ? partialCopy(name, sessionFile) : void 0;
|
|
792
|
+
const evidence = evidenceLines({
|
|
793
|
+
...sessionFile ? { sessionFile } : {},
|
|
794
|
+
...partial ? { partial } : {}
|
|
795
|
+
});
|
|
671
796
|
if (entry?.record)
|
|
672
797
|
text += ` ${await writeRecord(entry.record.target, name, recordNote(entry.record.label, name, "cancelled", void 0, 0))}`;
|
|
673
798
|
if (params.keep === true) text += " Pane kept.";
|
|
@@ -675,6 +800,8 @@ ${task}` : task,
|
|
|
675
800
|
const c = await mu(["agent", "close", name, "-w", W]);
|
|
676
801
|
text += c.code === 0 ? " Pane closed." : ` Pane kept: close refused: ${(c.stderr || c.stdout).trim()}`;
|
|
677
802
|
}
|
|
803
|
+
if (evidence.length > 0) text += `
|
|
804
|
+
${evidence.join("\n")}`;
|
|
678
805
|
return { content: [{ type: "text", text }], details: { name, workstream: W } };
|
|
679
806
|
}
|
|
680
807
|
});
|
|
@@ -686,13 +813,32 @@ ${task}` : task,
|
|
|
686
813
|
});
|
|
687
814
|
pi.on("agent_settled", (e) => {
|
|
688
815
|
if (e.aborted !== true) return;
|
|
689
|
-
|
|
690
|
-
for (const [id,
|
|
691
|
-
if (queued)
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
816
|
+
const dropped = [];
|
|
817
|
+
for (const [id, a] of arriving) {
|
|
818
|
+
if (!a.queued) continue;
|
|
819
|
+
arriving.delete(id);
|
|
820
|
+
dropped.push({
|
|
821
|
+
name: a.name,
|
|
822
|
+
...a.outcome ? { outcome: a.outcome } : {},
|
|
823
|
+
...a.elapsedMs !== void 0 ? { elapsedMs: a.elapsedMs } : {},
|
|
824
|
+
...a.sessionFile ? { sessionFile: a.sessionFile } : {},
|
|
825
|
+
...a.content ? { copy: saveCopy(a.name, a.content) } : {}
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
if (dropped.length === 0) return;
|
|
829
|
+
showStatus();
|
|
830
|
+
void Promise.resolve(
|
|
831
|
+
pi.sendMessage(
|
|
832
|
+
{
|
|
833
|
+
customType: DELEGATE_MESSAGE_TYPE,
|
|
834
|
+
content: droppedNote(dropped),
|
|
835
|
+
display: true,
|
|
836
|
+
details: { dropped }
|
|
837
|
+
},
|
|
838
|
+
{ triggerTurn: false }
|
|
839
|
+
)
|
|
840
|
+
).catch(() => {
|
|
841
|
+
});
|
|
696
842
|
});
|
|
697
843
|
pi.on("session_shutdown", (_e, ctx) => {
|
|
698
844
|
if (arriving.size > 0) {
|
|
@@ -701,6 +847,9 @@ ${task}` : task,
|
|
|
701
847
|
}
|
|
702
848
|
if (inflight.size === 0 && queue.length === 0) return;
|
|
703
849
|
const names = [...inflight.keys()];
|
|
850
|
+
const sessions = [...inflight].flatMap(
|
|
851
|
+
([n, e]) => e.sessionFile ? [`${n}: ${e.sessionFile}`] : []
|
|
852
|
+
);
|
|
704
853
|
const never = queue.splice(0).map((q) => q.handle);
|
|
705
854
|
for (const e of inflight.values()) e.abort.abort();
|
|
706
855
|
inflight.clear();
|
|
@@ -711,6 +860,7 @@ ${task}` : task,
|
|
|
711
860
|
parts.push(
|
|
712
861
|
`${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.`
|
|
713
862
|
);
|
|
863
|
+
if (sessions.length > 0) parts.push(`Sessions: ${sessions.join("; ")}.`);
|
|
714
864
|
if (never.length > 0)
|
|
715
865
|
parts.push(`${never.length} queued, never started: ${never.join(", ")}. Re-issue them.`);
|
|
716
866
|
const msg = parts.join(" ");
|
|
@@ -721,8 +871,8 @@ ${task}` : task,
|
|
|
721
871
|
}
|
|
722
872
|
|
|
723
873
|
// extension/nudge.ts
|
|
724
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
725
|
-
import { join as
|
|
874
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
875
|
+
import { join as join3 } from "path";
|
|
726
876
|
var NUDGE_MESSAGE_TYPE = "mu-keep-driving";
|
|
727
877
|
var NUDGE_LOG_KIND = "nudge";
|
|
728
878
|
var CLOSE_NUDGE_MESSAGE_TYPE = "mu-close-task";
|
|
@@ -746,8 +896,8 @@ function keepDrivingRule(skillMd) {
|
|
|
746
896
|
}
|
|
747
897
|
function readSkill() {
|
|
748
898
|
for (const up of ["..", "../.."]) {
|
|
749
|
-
const p =
|
|
750
|
-
if (existsSync2(p)) return
|
|
899
|
+
const p = join3(import.meta.dirname ?? "", up, "skills", "mu", "SKILL.md");
|
|
900
|
+
if (existsSync2(p)) return readFileSync2(p, "utf8");
|
|
751
901
|
}
|
|
752
902
|
return void 0;
|
|
753
903
|
}
|
|
@@ -1147,7 +1297,7 @@ function registerRefuteNudge(pi, run = defaultRunner(), nested = notNested) {
|
|
|
1147
1297
|
}
|
|
1148
1298
|
|
|
1149
1299
|
// extension/mu-pi.ts
|
|
1150
|
-
var EXT_VERSION = true ? "3.
|
|
1300
|
+
var EXT_VERSION = true ? "3.12.0" : void 0;
|
|
1151
1301
|
var FRESH_COMMAND = "mu-fresh";
|
|
1152
1302
|
var FRESH_TIMEOUT_MS = 3e4;
|
|
1153
1303
|
function commandName(name) {
|
|
@@ -1167,9 +1317,9 @@ function detectPiVersion() {
|
|
|
1167
1317
|
if (!entry) return void 0;
|
|
1168
1318
|
let dir = dirname(realpathSync(entry));
|
|
1169
1319
|
for (let i = 0; i < 6; i++) {
|
|
1170
|
-
const pkgPath =
|
|
1320
|
+
const pkgPath = join4(dir, "package.json");
|
|
1171
1321
|
if (existsSync3(pkgPath)) {
|
|
1172
|
-
const pkg = JSON.parse(
|
|
1322
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
1173
1323
|
if (typeof pkg === "object" && pkg !== null) {
|
|
1174
1324
|
const { name, version } = pkg;
|
|
1175
1325
|
if (typeof name === "string" && /pi/.test(name) && typeof version === "string") {
|
|
@@ -1273,8 +1423,8 @@ function promptsDir(from = import.meta.url) {
|
|
|
1273
1423
|
return void 0;
|
|
1274
1424
|
}
|
|
1275
1425
|
for (const up of ["..", "../.."]) {
|
|
1276
|
-
const d =
|
|
1277
|
-
if (existsSync3(
|
|
1426
|
+
const d = join4(here, up, "prompts");
|
|
1427
|
+
if (existsSync3(join4(d, "ultrathink.md"))) return d;
|
|
1278
1428
|
}
|
|
1279
1429
|
return void 0;
|
|
1280
1430
|
}
|
|
@@ -1282,7 +1432,7 @@ function registerPrompts(pi) {
|
|
|
1282
1432
|
pi.on("resources_discover", () => {
|
|
1283
1433
|
const d = promptsDir();
|
|
1284
1434
|
if (!d) return {};
|
|
1285
|
-
const paths = readdirSync(d).filter((f) => f.endsWith(".md")).sort().map((f) =>
|
|
1435
|
+
const paths = readdirSync(d).filter((f) => f.endsWith(".md")).sort().map((f) => join4(d, f));
|
|
1286
1436
|
return { promptPaths: paths };
|
|
1287
1437
|
});
|
|
1288
1438
|
}
|
|
@@ -1320,7 +1470,8 @@ function serveCtl(pi) {
|
|
|
1320
1470
|
state: g.state,
|
|
1321
1471
|
since: g.since,
|
|
1322
1472
|
runs: g.runs,
|
|
1323
|
-
pending: g.ctx?.hasPendingMessages() ?? false
|
|
1473
|
+
pending: g.ctx?.hasPendingMessages() ?? false,
|
|
1474
|
+
...sessionFileOf(g.ctx)
|
|
1324
1475
|
});
|
|
1325
1476
|
const settleFresh = (r) => {
|
|
1326
1477
|
const f = g.fresh;
|
|
@@ -1344,6 +1495,14 @@ function serveCtl(pi) {
|
|
|
1344
1495
|
g.endText = lastAssistantText(e);
|
|
1345
1496
|
g.endError = lastAssistantError(e);
|
|
1346
1497
|
});
|
|
1498
|
+
function sessionFileOf(c) {
|
|
1499
|
+
try {
|
|
1500
|
+
const f = c?.sessionManager?.getSessionFile();
|
|
1501
|
+
return f ? { sessionFile: f } : {};
|
|
1502
|
+
} catch {
|
|
1503
|
+
return {};
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1347
1506
|
pi.on("agent_settled", (_e, c) => {
|
|
1348
1507
|
g.ctx = c;
|
|
1349
1508
|
g.state = "idle";
|
|
@@ -1353,6 +1512,7 @@ function serveCtl(pi) {
|
|
|
1353
1512
|
g.endText = void 0;
|
|
1354
1513
|
g.lastError = g.endError;
|
|
1355
1514
|
g.endError = void 0;
|
|
1515
|
+
g.sessionFile = sessionFileOf(c).sessionFile;
|
|
1356
1516
|
for (const w of [...g.waiters]) w();
|
|
1357
1517
|
});
|
|
1358
1518
|
pi.registerCommand(FRESH_COMMAND, {
|
|
@@ -1512,7 +1672,8 @@ function serveCtl(pi) {
|
|
|
1512
1672
|
}
|
|
1513
1673
|
const settledRun = () => ({
|
|
1514
1674
|
lastText: g.lastText,
|
|
1515
|
-
...g.lastError !== void 0 ? { lastError: g.lastError } : {}
|
|
1675
|
+
...g.lastError !== void 0 ? { lastError: g.lastError } : {},
|
|
1676
|
+
...g.sessionFile !== void 0 ? { sessionFile: g.sessionFile } : {}
|
|
1516
1677
|
});
|
|
1517
1678
|
function wait(afterRuns, timeoutMs, conn) {
|
|
1518
1679
|
if (afterRuns !== void 0 && g.runs > afterRuns && g.state === "idle") {
|
|
@@ -1570,7 +1731,7 @@ function serveCtl(pi) {
|
|
|
1570
1731
|
});
|
|
1571
1732
|
}
|
|
1572
1733
|
async function bind() {
|
|
1573
|
-
|
|
1734
|
+
mkdirSync2(dirname(sockPath), { recursive: true, mode: 448 });
|
|
1574
1735
|
if (await socketIsLive(sockPath)) {
|
|
1575
1736
|
g.nested = true;
|
|
1576
1737
|
process.stderr.write(
|
|
@@ -1580,7 +1741,7 @@ function serveCtl(pi) {
|
|
|
1580
1741
|
return;
|
|
1581
1742
|
}
|
|
1582
1743
|
rmSync(sockPath, { force: true });
|
|
1583
|
-
const tmp =
|
|
1744
|
+
const tmp = join4(dirname(sockPath), `.${process.pid.toString(36)}${(++bindSeq).toString(36)}`);
|
|
1584
1745
|
rmSync(tmp, { force: true });
|
|
1585
1746
|
const s = createServer(onConnection);
|
|
1586
1747
|
await new Promise((resolve, reject) => {
|