@mu-crew/mu 3.3.0 → 3.4.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/README.md +45 -31
- package/dist/cli.js +186 -20
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +103 -74
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.js +70 -4
- package/dist/index.js.map +1 -1
- package/docs/VISION.md +3 -1
- package/docs/VOCABULARY.md +4 -1
- package/docs/architecture/dag.md +3 -3
- package/docs/guide/delegate.md +30 -3
- package/docs/reference/env.md +1 -0
- package/docs/reference/naming.md +18 -0
- package/docs/specs/2026-09-29-task-substates.md +1 -1
- package/package.json +1 -1
- package/prompts/mu-debug.md +8 -0
- package/prompts/mu-sweep.md +8 -0
- package/prompts/mu-until.md +8 -0
- package/prompts/ultrathink.md +2 -1
- package/skills/mu/SKILL.md +70 -31
- package/skills/mu/recipes/adversarial-review.md +27 -19
- package/skills/mu/recipes/{triage.md → backlog-triage.md} +9 -4
- package/skills/mu/recipes/codemode-driver.md +68 -20
- package/skills/mu/recipes/deep-research.md +23 -8
- package/skills/mu/recipes/fan-out.md +15 -11
- package/skills/mu/recipes/findings.md +103 -0
- package/skills/mu/recipes/hypothesis-panel.md +18 -13
- package/skills/mu/recipes/long-run.md +4 -4
- package/skills/mu/recipes/loop-until-done.md +7 -3
- package/skills/mu/recipes/orchestrator-loop.md +38 -27
- package/skills/mu/recipes/plan.md +8 -3
- package/skills/mu/recipes/recovery.md +2 -0
- package/skills/mu/recipes/refute.md +38 -36
- package/skills/mu/recipes/remote-workers.md +7 -2
- package/skills/mu/recipes/review-panel.md +36 -31
- package/skills/mu/recipes/rules-audit.md +30 -17
- package/skills/mu/recipes/tasks-or-calls.md +67 -0
- package/skills/mu/recipes/tournament.md +13 -10
- package/skills/mu/recipes/ultrathink.md +20 -11
- package/skills/mu/recipes/watcher.md +4 -1
- package/skills/mu/recipes/waves.md +6 -5
- package/skills/mu/recipes/worker.md +3 -1
package/dist/extension/mu-pi.js
CHANGED
|
@@ -55,6 +55,11 @@ function delegateStatus(n) {
|
|
|
55
55
|
return n > 0 ? `${n} delegate${n === 1 ? "" : "s"} running` : void 0;
|
|
56
56
|
}
|
|
57
57
|
var DELEGATE_TIMEOUT_S = 3600;
|
|
58
|
+
var DELEGATE_MAX_DEFAULT = 16;
|
|
59
|
+
function delegateMax(env = process.env) {
|
|
60
|
+
const n = Number(env.MU_DELEGATE_MAX);
|
|
61
|
+
return Number.isInteger(n) && n > 0 ? n : DELEGATE_MAX_DEFAULT;
|
|
62
|
+
}
|
|
58
63
|
var W = DELEGATE_WORKSTREAM;
|
|
59
64
|
function delegateEnabled(env = process.env) {
|
|
60
65
|
if (env.MU_MANAGED_AGENT) return false;
|
|
@@ -141,6 +146,7 @@ function labelStem(label) {
|
|
|
141
146
|
function registerDelegate(pi, run = defaultRunner()) {
|
|
142
147
|
if (!delegateEnabled()) return;
|
|
143
148
|
const inflight = /* @__PURE__ */ new Map();
|
|
149
|
+
let starting = 0;
|
|
144
150
|
const reserved = /* @__PURE__ */ new Set();
|
|
145
151
|
let ui;
|
|
146
152
|
const showStatus = () => {
|
|
@@ -253,7 +259,7 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
253
259
|
pi.registerTool({
|
|
254
260
|
name: DELEGATE_TOOL,
|
|
255
261
|
label: "mu delegate",
|
|
256
|
-
description: `Subagent: run one self-contained task in a fresh pi agent (its own mux pane in mu's ${W} workstream) while you keep working. Use it whenever you would reach for a subagent: research, a review, a draft, an investigation; call it several times to fan out in parallel. The subagent starts with no context, in your working directory: put everything it needs in task. The call returns at once and the answer arrives later as a follow-up message: carry on with other work, or end your turn if your next step needs the answer (the follow-up resumes you). The pane closes after a clean finish; keep: true leaves it open.`,
|
|
262
|
+
description: `Subagent: run one self-contained task in a fresh pi agent (its own mux pane in mu's ${W} workstream) while you keep working. Use it whenever you would reach for a subagent: research, a review, a draft, an investigation; call it several times to fan out in parallel (at most ${delegateMax()} in flight). The subagent starts with no context, in your working directory: put everything it needs in task. The call returns at once and the answer arrives later as a follow-up message: carry on with other work, or end your turn if your next step needs the answer (the follow-up resumes you). The pane closes after a clean finish; keep: true leaves it open.`,
|
|
257
263
|
promptSnippet: "Subagent: delegate a self-contained task to a background pi agent; its answer arrives later as a follow-up",
|
|
258
264
|
parameters: {
|
|
259
265
|
type: "object",
|
|
@@ -296,83 +302,106 @@ function registerDelegate(pi, run = defaultRunner()) {
|
|
|
296
302
|
track(ctx);
|
|
297
303
|
const task = typeof params.task === "string" ? params.task.trim() : "";
|
|
298
304
|
if (!task) throw new Error("mu_delegate needs a non-empty task");
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
const t = params.timeout;
|
|
302
|
-
if (t !== void 0 && !(typeof t === "number" && Number.isFinite(t) && t > 0))
|
|
305
|
+
const max = delegateMax();
|
|
306
|
+
if (inflight.size + starting >= max)
|
|
303
307
|
throw new Error(
|
|
304
|
-
`mu_delegate:
|
|
308
|
+
`mu_delegate: ${inflight.size + starting} delegates already running (MU_DELEGATE_MAX=${max}). End your turn; issue the rest as answers arrive (each answer resumes you).`
|
|
305
309
|
);
|
|
306
|
-
|
|
307
|
-
let
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
const { name, attach, workspace } = await spawn(params, cwd, signal);
|
|
313
|
-
const entry = { abort: new AbortController(), cancelling: false };
|
|
314
|
-
inflight.set(name, entry);
|
|
315
|
-
showStatus();
|
|
316
|
-
const started = Date.now();
|
|
317
|
-
const waiting = mu(
|
|
318
|
-
["agent", "wait", name, "-w", W, "--json", "--timeout", String(timeoutS)],
|
|
319
|
-
entry.abort.signal
|
|
320
|
-
);
|
|
321
|
-
const sent = await mu(["agent", "send", name, brief ? `${brief}
|
|
322
|
-
|
|
323
|
-
${task}` : task, "-w", W]);
|
|
324
|
-
if (sent.code !== 0) {
|
|
325
|
-
entry.abort.abort();
|
|
326
|
-
forget(name);
|
|
327
|
-
const c = await mu(["agent", "close", name, "-w", W]);
|
|
328
|
-
const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
|
|
329
|
-
throw new Error(`${failure(`mu agent send to ${W}/${name}`, sent).message}. ${pane}`);
|
|
330
|
-
}
|
|
331
|
-
const settle = async (r) => {
|
|
332
|
-
forget(name);
|
|
333
|
-
try {
|
|
334
|
-
await deliver(name, r, keep, {
|
|
335
|
-
timeoutS,
|
|
336
|
-
elapsedMs: Date.now() - started,
|
|
337
|
-
...attach ? { attach } : {},
|
|
338
|
-
...workspace ? { workspace } : {}
|
|
339
|
-
});
|
|
340
|
-
} catch (e) {
|
|
341
|
-
await Promise.resolve(
|
|
342
|
-
pi.sendMessage(
|
|
343
|
-
{
|
|
344
|
-
customType: DELEGATE_MESSAGE_TYPE,
|
|
345
|
-
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}`,
|
|
346
|
-
display: true,
|
|
347
|
-
details: { name, workstream: W, outcome: null, closed: false }
|
|
348
|
-
},
|
|
349
|
-
{ deliverAs: "followUp", triggerTurn: true }
|
|
350
|
-
)
|
|
351
|
-
).catch(() => {
|
|
352
|
-
});
|
|
353
|
-
}
|
|
310
|
+
starting++;
|
|
311
|
+
let slotHeld = true;
|
|
312
|
+
const freeSlot = () => {
|
|
313
|
+
if (slotHeld) starting--;
|
|
314
|
+
slotHeld = false;
|
|
354
315
|
};
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
316
|
+
try {
|
|
317
|
+
const brief = typeof params.brief === "string" ? params.brief.trim() : "";
|
|
318
|
+
const keep = params.keep === true;
|
|
319
|
+
const t = params.timeout;
|
|
320
|
+
if (t !== void 0 && !(typeof t === "number" && Number.isFinite(t) && t > 0))
|
|
321
|
+
throw new Error(
|
|
322
|
+
`mu_delegate: timeout must be a positive number of seconds (got ${JSON.stringify(t)})`
|
|
323
|
+
);
|
|
324
|
+
const timeoutS = typeof t === "number" ? Math.ceil(t) : DELEGATE_TIMEOUT_S;
|
|
325
|
+
let cwd;
|
|
326
|
+
if (params.workspace !== true) {
|
|
327
|
+
cwd = typeof params.cwd === "string" && params.cwd ? params.cwd : ctx?.cwd ?? process.cwd();
|
|
328
|
+
if (!isDir(cwd)) throw new Error(`mu_delegate: cwd ${cwd} is not a directory`);
|
|
329
|
+
}
|
|
330
|
+
const { name, attach, workspace } = await spawn(params, cwd, signal);
|
|
331
|
+
const entry = { abort: new AbortController(), cancelling: false };
|
|
332
|
+
inflight.set(name, entry);
|
|
333
|
+
freeSlot();
|
|
334
|
+
showStatus();
|
|
335
|
+
const started = Date.now();
|
|
336
|
+
const waiting = mu(
|
|
337
|
+
["agent", "wait", name, "-w", W, "--json", "--timeout", String(timeoutS)],
|
|
338
|
+
entry.abort.signal
|
|
339
|
+
);
|
|
340
|
+
const sent = await mu([
|
|
341
|
+
"agent",
|
|
342
|
+
"send",
|
|
369
343
|
name,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
344
|
+
brief ? `${brief}
|
|
345
|
+
|
|
346
|
+
${task}` : task,
|
|
347
|
+
"-w",
|
|
348
|
+
W
|
|
349
|
+
]);
|
|
350
|
+
if (sent.code !== 0) {
|
|
351
|
+
entry.abort.abort();
|
|
352
|
+
forget(name);
|
|
353
|
+
const c = await mu(["agent", "close", name, "-w", W]);
|
|
354
|
+
const pane = c.code === 0 ? "Pane closed." : `Pane kept; close it with: mu agent close ${name} -w ${W}`;
|
|
355
|
+
throw new Error(`${failure(`mu agent send to ${W}/${name}`, sent).message}. ${pane}`);
|
|
374
356
|
}
|
|
375
|
-
|
|
357
|
+
const settle = async (r) => {
|
|
358
|
+
forget(name);
|
|
359
|
+
try {
|
|
360
|
+
await deliver(name, r, keep, {
|
|
361
|
+
timeoutS,
|
|
362
|
+
elapsedMs: Date.now() - started,
|
|
363
|
+
...attach ? { attach } : {},
|
|
364
|
+
...workspace ? { workspace } : {}
|
|
365
|
+
});
|
|
366
|
+
} catch (e) {
|
|
367
|
+
await Promise.resolve(
|
|
368
|
+
pi.sendMessage(
|
|
369
|
+
{
|
|
370
|
+
customType: DELEGATE_MESSAGE_TYPE,
|
|
371
|
+
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}`,
|
|
372
|
+
display: true,
|
|
373
|
+
details: { name, workstream: W, outcome: null, closed: false }
|
|
374
|
+
},
|
|
375
|
+
{ deliverAs: "followUp", triggerTurn: true }
|
|
376
|
+
)
|
|
377
|
+
).catch(() => {
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
void waiting.then(async (r) => {
|
|
382
|
+
if (inflight.get(name) !== entry) return;
|
|
383
|
+
if (entry.cancelling) entry.parked = () => settle(r);
|
|
384
|
+
else await settle(r);
|
|
385
|
+
});
|
|
386
|
+
const lines = [
|
|
387
|
+
`Delegated to ${W}/${name}. Its answer arrives as a follow-up message when it finishes; do not wait or poll.`,
|
|
388
|
+
workspace ? `Workspace: ${workspace}` : void 0,
|
|
389
|
+
attach ? `Attach: ${attach}` : void 0,
|
|
390
|
+
`Cancel: ${DELEGATE_CANCEL_TOOL} { name: "${name}" }`
|
|
391
|
+
].filter((x) => x !== void 0);
|
|
392
|
+
return {
|
|
393
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
394
|
+
details: {
|
|
395
|
+
name,
|
|
396
|
+
workstream: W,
|
|
397
|
+
attach: attach ?? null,
|
|
398
|
+
workspace: workspace ?? null,
|
|
399
|
+
keep
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
} finally {
|
|
403
|
+
freeSlot();
|
|
404
|
+
}
|
|
376
405
|
}
|
|
377
406
|
});
|
|
378
407
|
pi.registerTool({
|
|
@@ -561,7 +590,7 @@ function registerNudge(pi, run = defaultRunner(), skillMd = readSkill()) {
|
|
|
561
590
|
}
|
|
562
591
|
|
|
563
592
|
// extension/mu-pi.ts
|
|
564
|
-
var EXT_VERSION = true ? "3.
|
|
593
|
+
var EXT_VERSION = true ? "3.4.0" : void 0;
|
|
565
594
|
var FRESH_COMMAND = "mu-fresh";
|
|
566
595
|
var FRESH_TIMEOUT_MS = 3e4;
|
|
567
596
|
function commandName(name) {
|