@mu-crew/mu 3.3.0 → 3.5.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 +812 -429
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +221 -55
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.js +76 -5
- package/dist/index.js.map +1 -1
- package/docs/VISION.md +5 -1
- package/docs/VOCABULARY.md +4 -1
- package/docs/architecture/dag.md +3 -3
- package/docs/architecture/ops-log.md +26 -7
- package/docs/guide/cleanup.md +19 -0
- package/docs/guide/delegate.md +43 -4
- 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 +44 -27
- package/skills/mu/recipes/plan.md +8 -3
- package/skills/mu/recipes/recovery.md +5 -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 +71 -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/index.js
CHANGED
|
@@ -221,6 +221,11 @@ function fullOldPayload(cols) {
|
|
|
221
221
|
const pairs = cols.map((c) => `'${c}', OLD.${c}`).join(", ");
|
|
222
222
|
return `json_object(${pairs})`;
|
|
223
223
|
}
|
|
224
|
+
function noteTombstonePayload(keyExpr, cols) {
|
|
225
|
+
return `CASE WHEN EXISTS (
|
|
226
|
+
SELECT 1 FROM ops WHERE entity = 'note' AND key = ${keyExpr} AND op = 'put'
|
|
227
|
+
) THEN '{}' ELSE ${fullOldPayload(cols)} END`;
|
|
228
|
+
}
|
|
224
229
|
function anyChanged(cols) {
|
|
225
230
|
return cols.map((c) => `NEW.${c} IS NOT OLD.${c}`).join("\n OR ");
|
|
226
231
|
}
|
|
@@ -321,7 +326,7 @@ END;
|
|
|
321
326
|
CREATE TEMP TRIGGER IF NOT EXISTS _cap_task_notes_del
|
|
322
327
|
BEFORE DELETE ON task_notes WHEN ${NOT_APPLYING}
|
|
323
328
|
BEGIN
|
|
324
|
-
${emitOp("note", "del", `${taskKey("OLD.task_id")} || '#' || OLD.id`,
|
|
329
|
+
${emitOp("note", "del", `${taskKey("OLD.task_id")} || '#' || OLD.id`, noteTombstonePayload(`${taskKey("OLD.task_id")} || '#' || OLD.id`, noteCols))}
|
|
325
330
|
END;
|
|
326
331
|
|
|
327
332
|
-- \u2500\u2500\u2500 task_edges \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -359,7 +364,7 @@ function isTaskStatus(s) {
|
|
|
359
364
|
}
|
|
360
365
|
var TASK_STATUS_LIST = TASK_STATUSES.join(" | ");
|
|
361
366
|
var TASK_SUBSTATES = {
|
|
362
|
-
OPEN: ["todo", "parked"],
|
|
367
|
+
OPEN: ["todo", "parked", "triage"],
|
|
363
368
|
IN_PROGRESS: ["active"],
|
|
364
369
|
CLOSED: ["done", "rejected", "wontfix", "duplicate", "superseded"]
|
|
365
370
|
};
|
|
@@ -590,7 +595,7 @@ CREATE VIEW ready AS
|
|
|
590
595
|
SELECT t.*
|
|
591
596
|
FROM tasks t
|
|
592
597
|
WHERE t.status = 'OPEN'
|
|
593
|
-
AND t.substate
|
|
598
|
+
AND t.substate NOT IN ('parked', 'triage')
|
|
594
599
|
AND NOT EXISTS (
|
|
595
600
|
SELECT 1
|
|
596
601
|
FROM task_edges e
|
|
@@ -4560,6 +4565,30 @@ var TaskParkStateError = class extends Error {
|
|
|
4560
4565
|
];
|
|
4561
4566
|
}
|
|
4562
4567
|
};
|
|
4568
|
+
var TaskInTriageError = class extends Error {
|
|
4569
|
+
constructor(taskId, workstream) {
|
|
4570
|
+
super(`task ${taskId} is in triage (OPEN/triage); accept it or claim with --force`);
|
|
4571
|
+
this.taskId = taskId;
|
|
4572
|
+
this.workstream = workstream;
|
|
4573
|
+
}
|
|
4574
|
+
taskId;
|
|
4575
|
+
workstream;
|
|
4576
|
+
name = "TaskInTriageError";
|
|
4577
|
+
errorNextSteps() {
|
|
4578
|
+
const ws = this.workstream;
|
|
4579
|
+
return [
|
|
4580
|
+
{
|
|
4581
|
+
intent: "Accept it as work, then claim",
|
|
4582
|
+
command: `mu task accept ${this.taskId} -w ${ws}`
|
|
4583
|
+
},
|
|
4584
|
+
{
|
|
4585
|
+
intent: "Decline it",
|
|
4586
|
+
command: `mu task close ${this.taskId} --as rejected --why "<reason>" -w ${ws}`
|
|
4587
|
+
},
|
|
4588
|
+
{ intent: "Claim it anyway", command: `mu task claim ${this.taskId} --force -w ${ws}` }
|
|
4589
|
+
];
|
|
4590
|
+
}
|
|
4591
|
+
};
|
|
4563
4592
|
var TaskParkedError = class extends Error {
|
|
4564
4593
|
constructor(taskId, workstream) {
|
|
4565
4594
|
super(`task ${taskId} is parked (OPEN/parked); unpark it or claim with --force`);
|
|
@@ -5015,8 +5044,17 @@ function addTaskImpl(db, opts) {
|
|
|
5015
5044
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5016
5045
|
const insertResult = db.prepare(
|
|
5017
5046
|
`INSERT INTO tasks (workstream_id, local_id, title, status, substate, impact, effort_days, created_at, updated_at)
|
|
5018
|
-
VALUES (?, ?, ?, 'OPEN',
|
|
5019
|
-
).run(
|
|
5047
|
+
VALUES (?, ?, ?, 'OPEN', ?, ?, ?, ?, ?)`
|
|
5048
|
+
).run(
|
|
5049
|
+
wsId,
|
|
5050
|
+
opts.localId,
|
|
5051
|
+
opts.title,
|
|
5052
|
+
opts.triage === true ? "triage" : "todo",
|
|
5053
|
+
opts.impact,
|
|
5054
|
+
opts.effortDays,
|
|
5055
|
+
now,
|
|
5056
|
+
now
|
|
5057
|
+
);
|
|
5020
5058
|
const newTaskId = Number(insertResult.lastInsertRowid);
|
|
5021
5059
|
if (opts.blockedBy && opts.blockedBy.length > 0) {
|
|
5022
5060
|
const blockerLookupSameWs = db.prepare(
|
|
@@ -5291,6 +5329,28 @@ function parkTask(db, localId, opts) {
|
|
|
5291
5329
|
})()
|
|
5292
5330
|
);
|
|
5293
5331
|
}
|
|
5332
|
+
function acceptTask(db, localId, opts) {
|
|
5333
|
+
return withOpContext(
|
|
5334
|
+
db,
|
|
5335
|
+
{ intent: "task.accept", group: "new" },
|
|
5336
|
+
() => db.transaction(() => {
|
|
5337
|
+
const before = getTask(db, localId, opts.workstream);
|
|
5338
|
+
if (!before) throw new TaskNotFoundError(localId);
|
|
5339
|
+
if (before.status !== "OPEN" || before.substate !== "triage") {
|
|
5340
|
+
return {
|
|
5341
|
+
previousStatus: before.status,
|
|
5342
|
+
status: before.status,
|
|
5343
|
+
previousSubstate: before.substate,
|
|
5344
|
+
substate: before.substate,
|
|
5345
|
+
changed: false
|
|
5346
|
+
};
|
|
5347
|
+
}
|
|
5348
|
+
const r = setTaskStatus(db, localId, "OPEN", { workstream: opts.workstream });
|
|
5349
|
+
recordEvidenceNote(db, localId, before.workstreamName, "ACCEPT", opts);
|
|
5350
|
+
return r;
|
|
5351
|
+
})()
|
|
5352
|
+
);
|
|
5353
|
+
}
|
|
5294
5354
|
function unparkTask(db, localId, opts) {
|
|
5295
5355
|
return withOpContext(
|
|
5296
5356
|
db,
|
|
@@ -5421,6 +5481,9 @@ function assertNotParked(task, opts) {
|
|
|
5421
5481
|
if (task.status === "OPEN" && task.substate === "parked" && opts.force !== true) {
|
|
5422
5482
|
throw new TaskParkedError(task.name, task.workstreamName);
|
|
5423
5483
|
}
|
|
5484
|
+
if (task.status === "OPEN" && task.substate === "triage" && opts.force !== true) {
|
|
5485
|
+
throw new TaskInTriageError(task.name, task.workstreamName);
|
|
5486
|
+
}
|
|
5424
5487
|
}
|
|
5425
5488
|
async function resolveActorIdentity() {
|
|
5426
5489
|
const worker = await resolveWorkerIdentity();
|
|
@@ -10022,6 +10085,10 @@ async function loadWorkstreamSnapshotFast(db, workstream, opts = {}) {
|
|
|
10022
10085
|
blocked: listBlocked(db, workstream),
|
|
10023
10086
|
recentClosed: listRecentClosed(db, workstream),
|
|
10024
10087
|
parkedCount: listTasks(db, workstream, { status: "OPEN", substate: "parked" }).length,
|
|
10088
|
+
triage: listTasks(db, workstream, { status: "OPEN", substate: "triage" }),
|
|
10089
|
+
taskCount: db.prepare(
|
|
10090
|
+
"SELECT count(*) AS n FROM tasks t JOIN workstreams w ON w.id = t.workstream_id WHERE w.name = ?"
|
|
10091
|
+
).get(workstream).n,
|
|
10025
10092
|
allTasks: opts.withAllTasks === true ? listTasks(db, workstream) : [],
|
|
10026
10093
|
workspaces: listWorkspaces2(db, workstream),
|
|
10027
10094
|
workspaceOrphans: listWorkspaceOrphans(db, workstream),
|
|
@@ -10095,6 +10162,8 @@ function minimalSnapshot(workstream) {
|
|
|
10095
10162
|
blocked: [],
|
|
10096
10163
|
recentClosed: [],
|
|
10097
10164
|
parkedCount: 0,
|
|
10165
|
+
triage: [],
|
|
10166
|
+
taskCount: 0,
|
|
10098
10167
|
allTasks: [],
|
|
10099
10168
|
workspaces: [],
|
|
10100
10169
|
workspaceOrphans: [],
|
|
@@ -10991,6 +11060,7 @@ export {
|
|
|
10991
11060
|
TASK_SUBSTATE_ROWS,
|
|
10992
11061
|
TaskAlreadyOwnedError,
|
|
10993
11062
|
TaskExistsError,
|
|
11063
|
+
TaskInTriageError,
|
|
10994
11064
|
TaskNotFoundError,
|
|
10995
11065
|
TaskNotInWorkstreamError,
|
|
10996
11066
|
TaskParkStateError,
|
|
@@ -11007,6 +11077,7 @@ export {
|
|
|
11007
11077
|
WorkstreamExistsError,
|
|
11008
11078
|
WorkstreamNameInvalidError,
|
|
11009
11079
|
abortAgent,
|
|
11080
|
+
acceptTask,
|
|
11010
11081
|
activeMux,
|
|
11011
11082
|
addBlockEdge,
|
|
11012
11083
|
addNote,
|