@mu-crew/mu 4.0.0 → 4.1.1

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 (35) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-5HECDBK3.js → chunk-B74N2EAS.js} +16 -16
  3. package/dist/{chunk-GQNHIPJN.js → chunk-DEYBQDTO.js} +21 -421
  4. package/dist/chunk-DEYBQDTO.js.map +1 -0
  5. package/dist/{chunk-S424D5EP.js → chunk-L7I3BLXP.js} +635 -142
  6. package/dist/chunk-L7I3BLXP.js.map +1 -0
  7. package/dist/{chunk-AW2NONYU.js → chunk-LBBZAG5C.js} +81 -7
  8. package/dist/chunk-LBBZAG5C.js.map +1 -0
  9. package/dist/{cli-GB2CAVVW.js → cli-H2PWJAJN.js} +346 -44
  10. package/dist/cli-H2PWJAJN.js.map +1 -0
  11. package/dist/cli.js +1 -1
  12. package/dist/{errors-KHOYKD7D.js → errors-G5IVXSMY.js} +2 -2
  13. package/dist/extension/mu-pi.js +28 -14
  14. package/dist/extension/mu-pi.js.map +1 -1
  15. package/dist/index.d.ts +63 -11
  16. package/dist/index.js +15 -15
  17. package/dist/{tui-ALPHYTA2.js → tui-EN2CDP6G.js} +102 -27
  18. package/dist/tui-EN2CDP6G.js.map +1 -0
  19. package/docs/ARCHITECTURE.md +5 -4
  20. package/docs/VOCABULARY.md +6 -5
  21. package/docs/guide/cleanup.md +8 -0
  22. package/docs/guide/delegate.md +11 -3
  23. package/docs/guide/remote.md +19 -12
  24. package/docs/guide/sql.md +1 -0
  25. package/docs/reference/env.md +1 -0
  26. package/docs/reference/naming.md +2 -0
  27. package/package.json +1 -1
  28. package/skills/mu/recipes/remote-workers.md +7 -6
  29. package/dist/chunk-AW2NONYU.js.map +0 -1
  30. package/dist/chunk-GQNHIPJN.js.map +0 -1
  31. package/dist/chunk-S424D5EP.js.map +0 -1
  32. package/dist/cli-GB2CAVVW.js.map +0 -1
  33. package/dist/tui-ALPHYTA2.js.map +0 -1
  34. /package/dist/{chunk-5HECDBK3.js.map → chunk-B74N2EAS.js.map} +0 -0
  35. /package/dist/{errors-KHOYKD7D.js.map → errors-G5IVXSMY.js.map} +0 -0
package/README.md CHANGED
@@ -83,7 +83,7 @@ package), or spawn into the reserved `scratch` workstream:
83
83
  Run `mu` with no arguments for the read-only dashboard. It has five tabs
84
84
  (Overview, Tasks, DAG, Agents, Log), with what needs a human on top: a
85
85
  dead or stalled worker, one waiting on a permission or on input, a
86
- `human-needed` task.
86
+ `human-needed` task, a refused or failed delegate call.
87
87
 
88
88
  ![The mu dashboard: a payments workstream with a dead worker, one waiting on a permission, one stalled on a tool, and a human-needed task.](docs/img/tui-dashboard.png)
89
89
 
@@ -1,10 +1,6 @@
1
1
  import { createRequire as __muCreateRequire } from "node:module"; const require = __muCreateRequire(import.meta.url);
2
2
  import {
3
- DelegateCallConflictError,
4
- DelegateNotFoundError,
5
- DelegateStateError,
6
3
  IN_FLIGHT_STATES,
7
- TERMINAL_DELEGATE_STATES,
8
4
  ambientFlush,
9
5
  ambientIngest,
10
6
  authorisedReady,
@@ -13,15 +9,10 @@ import {
13
9
  currentCallers,
14
10
  deliveredOf,
15
11
  endAttempt,
16
- finishDelegate,
17
12
  foreignVersionMessage,
18
13
  getAutoConfig,
19
- getDelegateCall,
20
- listDelegates,
21
- listDelegatesOf,
22
14
  liveAgentToOutput,
23
15
  localMachineId,
24
- markDelegate,
25
16
  openHumanNeeds,
26
17
  ownSegmentForeignLine,
27
18
  pendingAttempts,
@@ -30,12 +21,9 @@ import {
30
21
  projectLog,
31
22
  readAttempt,
32
23
  recordHumanNeeded,
33
- registerDelegateCall,
34
24
  reserveAttempt,
35
- reserveRetry,
36
- tallyCalls,
37
- verdictTally
38
- } from "./chunk-GQNHIPJN.js";
25
+ reserveRetry
26
+ } from "./chunk-DEYBQDTO.js";
39
27
  import {
40
28
  AgentLockBusyError,
41
29
  AgentNotFoundError,
@@ -46,11 +34,15 @@ import {
46
34
  CtlWriteVetoedError,
47
35
  DEFAULT_SUBSTATE,
48
36
  DELEGATE_TOKEN,
37
+ DelegateCallConflictError,
38
+ DelegateNotFoundError,
39
+ DelegateStateError,
49
40
  NoMultiplexerError,
50
41
  RemoteRecoveryRefusedError,
51
42
  SYNCED_ENTITIES,
52
43
  SpawnAttemptBusyError,
53
44
  SpawnAttemptGuardError,
45
+ TERMINAL_DELEGATE_STATES,
54
46
  TaskNotFoundError,
55
47
  WorkstreamNotFoundError,
56
48
  activeMux,
@@ -77,7 +69,9 @@ import {
77
69
  endWait,
78
70
  expectsCtl,
79
71
  fenceAgentRef,
72
+ finishDelegate,
80
73
  getAgent,
74
+ getDelegateCall,
81
75
  getReceipt,
82
76
  getTask,
83
77
  getTaskNote,
@@ -87,6 +81,8 @@ import {
87
81
  isConsumed,
88
82
  isValidTaskId,
89
83
  listBlocked,
84
+ listDelegates,
85
+ listDelegatesOf,
90
86
  listInProgress,
91
87
  listReady,
92
88
  listTasks,
@@ -94,6 +90,7 @@ import {
94
90
  localPaneAlive,
95
91
  locksDir,
96
92
  logStallOnce,
93
+ markDelegate,
97
94
  newMsgId,
98
95
  observeAgentStates,
99
96
  openDb,
@@ -106,6 +103,7 @@ import {
106
103
  recordSend,
107
104
  recoveryGone,
108
105
  recoveryHolds,
106
+ registerDelegateCall,
109
107
  registerOwnedWait,
110
108
  releaseTask,
111
109
  resolveCliCommand,
@@ -120,16 +118,18 @@ import {
120
118
  spawnAutoAttempt,
121
119
  spawnForTask,
122
120
  speaksMuCtl,
121
+ tallyCalls,
123
122
  taskIdFor,
124
123
  taskRevision,
125
124
  tryResolveLiveWorkstreamId,
125
+ verdictTally,
126
126
  watchAgentRun,
127
127
  withAgentLock,
128
128
  withCaptureSuppressed,
129
129
  withFileLock,
130
130
  withHostChannel,
131
131
  withOpContext
132
- } from "./chunk-S424D5EP.js";
132
+ } from "./chunk-L7I3BLXP.js";
133
133
 
134
134
  // src/rebuild.ts
135
135
  import { existsSync, mkdirSync, rmSync, statSync } from "fs";
@@ -4479,4 +4479,4 @@ export {
4479
4479
  saveResume,
4480
4480
  loadResume
4481
4481
  };
4482
- //# sourceMappingURL=chunk-5HECDBK3.js.map
4482
+ //# sourceMappingURL=chunk-B74N2EAS.js.map
@@ -15,10 +15,7 @@ import {
15
15
  TASK_FROM_JOIN,
16
16
  TASK_KINDS,
17
17
  TaskNotFoundError,
18
- addNote,
19
- addTask,
20
18
  addTasks,
21
- closeTask,
22
19
  compareHlc,
23
20
  compareStrings,
24
21
  decodeLine,
@@ -48,7 +45,6 @@ import {
48
45
  rowFromDb,
49
46
  savedIdentity,
50
47
  say,
51
- setTaskStatus,
52
48
  shellWord,
53
49
  taskIdFor,
54
50
  taskRevision,
@@ -56,7 +52,7 @@ import {
56
52
  withCaptureSuppressed,
57
53
  withFileLock,
58
54
  withOpContext
59
- } from "./chunk-S424D5EP.js";
55
+ } from "./chunk-L7I3BLXP.js";
60
56
 
61
57
  // src/fold.ts
62
58
  function fieldsOf(payload) {
@@ -1034,8 +1030,8 @@ function recordedFingerprint(db, watermarkKey) {
1034
1030
  function segmentCaughtUp(db, watermarkKey, path, lines) {
1035
1031
  const recorded = recordedFingerprint(db, watermarkKey);
1036
1032
  if (recorded === null) return false;
1037
- const now2 = segmentFingerprint(path);
1038
- return now2 !== null && now2.count === lines && now2.key === decodeFingerprint(recorded).key;
1033
+ const now = segmentFingerprint(path);
1034
+ return now !== null && now.count === lines && now.key === decodeFingerprint(recorded).key;
1039
1035
  }
1040
1036
  function resumePoint(db, watermarkKey, lines) {
1041
1037
  const recorded = recordedFingerprint(db, watermarkKey);
@@ -1415,14 +1411,14 @@ function getWatermark(db, watermarkKey) {
1415
1411
  return row?.n ?? 0;
1416
1412
  }
1417
1413
  function setWatermark(db, watermarkKey, value, fingerprint) {
1418
- const now2 = (/* @__PURE__ */ new Date()).toISOString();
1414
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1419
1415
  prepareCached(
1420
1416
  db,
1421
1417
  `INSERT INTO sync_peers (machine_id, last_applied_seq, last_seen_at)
1422
1418
  VALUES (@machineId, @value, @seenAt)
1423
1419
  ON CONFLICT (machine_id) DO UPDATE
1424
1420
  SET last_applied_seq = @value, last_seen_at = @seenAt`
1425
- ).run({ machineId: watermarkKey, value, seenAt: now2 });
1421
+ ).run({ machineId: watermarkKey, value, seenAt: now });
1426
1422
  if (fingerprint == null) {
1427
1423
  prepareCached(db, "DELETE FROM sync_fingerprints WHERE machine_id = ?").run(watermarkKey);
1428
1424
  } else {
@@ -1768,7 +1764,7 @@ function authorizeTasks(db, ids, opts) {
1768
1764
  if (!opts.off) refuseUnauthorisable(task, me);
1769
1765
  plan.push({ task, id });
1770
1766
  }
1771
- const now2 = (/* @__PURE__ */ new Date()).toISOString();
1767
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1772
1768
  let changed = false;
1773
1769
  for (const { task, id } of plan) {
1774
1770
  const row = db.prepare("SELECT cli, worktree, max_runs, enabled FROM task_auto WHERE task_id = ?").get(id);
@@ -1778,7 +1774,7 @@ function authorizeTasks(db, ids, opts) {
1778
1774
  changed = true;
1779
1775
  }
1780
1776
  if (task.dispatchHost === me) {
1781
- setHost(db, id, null, now2);
1777
+ setHost(db, id, null, now);
1782
1778
  changed = true;
1783
1779
  }
1784
1780
  continue;
@@ -1787,7 +1783,7 @@ function authorizeTasks(db, ids, opts) {
1787
1783
  if (row === void 0) {
1788
1784
  db.prepare(
1789
1785
  "INSERT INTO task_auto (task_id, cli, worktree, max_runs, created_at) VALUES (?, ?, ?, ?, ?)"
1790
- ).run(id, opts.cli, wt, opts.maxRuns, now2);
1786
+ ).run(id, opts.cli, wt, opts.maxRuns, now);
1791
1787
  changed = true;
1792
1788
  } else if (row.cli !== opts.cli || row.worktree !== wt || row.max_runs !== opts.maxRuns || row.enabled !== 1) {
1793
1789
  db.prepare(
@@ -1796,7 +1792,7 @@ function authorizeTasks(db, ids, opts) {
1796
1792
  changed = true;
1797
1793
  }
1798
1794
  if (task.dispatchHost !== me) {
1799
- setHost(db, id, me, now2);
1795
+ setHost(db, id, me, now);
1800
1796
  changed = true;
1801
1797
  }
1802
1798
  }
@@ -1809,10 +1805,10 @@ function tidOf(db, task) {
1809
1805
  if (id === null) throw new TaskNotFoundError(task.name, task.workstreamName);
1810
1806
  return id;
1811
1807
  }
1812
- function setHost(db, taskId, host, now2) {
1808
+ function setHost(db, taskId, host, now) {
1813
1809
  db.prepare("UPDATE tasks SET dispatch_host = ?, updated_at = ? WHERE id = ?").run(
1814
1810
  host,
1815
- now2,
1811
+ now,
1816
1812
  taskId
1817
1813
  );
1818
1814
  }
@@ -2618,390 +2614,6 @@ function okEnvelope(data) {
2618
2614
  }
2619
2615
  var RESULT_BYTES = 4096;
2620
2616
 
2621
- // src/delegate-verdict.ts
2622
- var VERDICT_LABELS = ["CONFIRMED", "REFUTED", "UNVERIFIED"];
2623
- function formatElapsed(ms) {
2624
- const t = Math.max(0, Math.round(ms / 1e3));
2625
- if (t < 60) return `${t}s`;
2626
- const m = Math.floor(t / 60);
2627
- if (m < 60) return `${m}m ${String(t % 60).padStart(2, "0")}s`;
2628
- return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, "0")}m`;
2629
- }
2630
- var VERDICT_LINE = /^(?:\w+: )?VERDICT:/;
2631
- var LABEL_RE = new RegExp(`\\b(${VERDICT_LABELS.join("|")})\\b`);
2632
- function firstVerdictLine(lines) {
2633
- return lines.findIndex((l) => VERDICT_LINE.test(l));
2634
- }
2635
- function parseVerdict(answer) {
2636
- const lines = answer.trimEnd().split("\n");
2637
- const at = firstVerdictLine(lines);
2638
- if (at < 0) return void 0;
2639
- const after = (lines[at] ?? "").slice((lines[at] ?? "").indexOf("VERDICT:") + "VERDICT:".length);
2640
- return LABEL_RE.exec(after)?.[1];
2641
- }
2642
- function recordNote(label, name, outcome, lastText, elapsedMs) {
2643
- if (outcome !== "done" || !lastText?.trim())
2644
- return `REFUTER ${label}: no verdict (${outcome === "done" ? "empty" : outcome ?? "no result"})`;
2645
- const lines = lastText.trimEnd().split("\n");
2646
- const at = firstVerdictLine(lines);
2647
- const body = at >= 0 ? lines.slice(at).join("\n") : `NO VERDICT LINE: ${lastText.trimEnd()}`;
2648
- return `REFUTER ${label} (${name}, ${formatElapsed(elapsedMs)}):
2649
- ${body}`;
2650
- }
2651
-
2652
- // src/delegates.ts
2653
- import { createHash as createHash4 } from "crypto";
2654
- var TERMINAL_DELEGATE_STATES = ["done", "failed", "cancelled"];
2655
- var TERMINAL = TERMINAL_DELEGATE_STATES;
2656
- var isTerminal = (s) => TERMINAL.includes(s);
2657
- var DelegateCallConflictError = class extends Error {
2658
- constructor(callId, field) {
2659
- super(say("delegate.conflict", callId, field));
2660
- this.callId = callId;
2661
- this.field = field;
2662
- }
2663
- callId;
2664
- field;
2665
- name = "DelegateCallConflictError";
2666
- };
2667
- var DelegateStateError = class extends Error {
2668
- constructor(callId, from, to) {
2669
- super(say("delegate.state", callId, from, to));
2670
- this.callId = callId;
2671
- this.from = from;
2672
- this.to = to;
2673
- }
2674
- callId;
2675
- from;
2676
- to;
2677
- name = "DelegateStateError";
2678
- };
2679
- var DelegateNotFoundError = class extends Error {
2680
- constructor(callId) {
2681
- super(say("delegate.not_found", callId));
2682
- this.callId = callId;
2683
- }
2684
- callId;
2685
- name = "DelegateNotFoundError";
2686
- };
2687
- var SELECT_CALL = `SELECT d.*, t.local_id AS local_id, w.name AS workstream, t.wave AS wave
2688
- FROM delegate_calls d
2689
- JOIN tasks t ON t.id = d.task_id
2690
- JOIN workstreams w ON w.id = t.workstream_id`;
2691
- function rowOf(r) {
2692
- let request = { text: "" };
2693
- try {
2694
- if (r.request) request = JSON.parse(r.request);
2695
- } catch {
2696
- }
2697
- return {
2698
- callId: r.call_id,
2699
- task: r.local_id,
2700
- workstream: r.workstream,
2701
- caller: r.caller,
2702
- state: r.state,
2703
- wave: r.wave,
2704
- record: r.record_workstream !== null && r.record_task !== null ? { workstream: r.record_workstream, task: r.record_task, label: r.record_label } : null,
2705
- request,
2706
- agent: r.agent,
2707
- verdict: r.verdict ?? null,
2708
- error: r.error,
2709
- updatedAt: r.updated_at
2710
- };
2711
- }
2712
- function getDelegateCall(db, callId) {
2713
- const r = db.prepare(`${SELECT_CALL} WHERE d.call_id = ?`).get(callId);
2714
- return r ? rowOf(r) : void 0;
2715
- }
2716
- function mustGet(db, callId) {
2717
- const row = getDelegateCall(db, callId);
2718
- if (!row) throw new DelegateNotFoundError(callId);
2719
- return row;
2720
- }
2721
- function listDelegates(db, caller, workstream, opts = {}) {
2722
- const where = [];
2723
- const args = [];
2724
- if (caller !== void 0) {
2725
- where.push("d.caller = ?");
2726
- args.push(caller);
2727
- }
2728
- if (workstream !== void 0) {
2729
- where.push("w.name = ?");
2730
- args.push(workstream);
2731
- }
2732
- if (opts.wave !== void 0) {
2733
- where.push("t.wave = ?");
2734
- args.push(opts.wave);
2735
- }
2736
- if (opts.states !== void 0) {
2737
- where.push(`d.state IN (${opts.states.map(() => "?").join(",")})`);
2738
- args.push(...opts.states);
2739
- }
2740
- const sql = `${SELECT_CALL}${where.length ? ` WHERE ${where.join(" AND ")}` : ""} ORDER BY d.task_id`;
2741
- return db.prepare(sql).all(...args).map(rowOf);
2742
- }
2743
- function listDelegatesOf(db, callers, workstream, opts = {}) {
2744
- const set = [...new Set(callers)];
2745
- if (set.length === 0) return [];
2746
- const where = [`d.caller IN (${set.map(() => "?").join(",")})`];
2747
- const args = [...set];
2748
- if (workstream !== void 0) {
2749
- where.push("w.name = ?");
2750
- args.push(workstream);
2751
- }
2752
- if (opts.wave !== void 0) {
2753
- where.push("t.wave = ?");
2754
- args.push(opts.wave);
2755
- }
2756
- const sql = `${SELECT_CALL} WHERE ${where.join(" AND ")} ORDER BY d.task_id`;
2757
- return db.prepare(sql).all(...args).map(rowOf);
2758
- }
2759
- function canonical(v) {
2760
- if (Array.isArray(v)) return `[${v.map(canonical).join(",")}]`;
2761
- if (typeof v === "object" && v !== null) {
2762
- const o = v;
2763
- return `{${Object.keys(o).filter((k) => o[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${canonical(o[k])}`).join(",")}}`;
2764
- }
2765
- return JSON.stringify(v);
2766
- }
2767
- function taskIdFor2(callId, label) {
2768
- const stem = (label ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 20).replace(/-+$/, "");
2769
- const h = createHash4("sha256").update(callId).digest("hex").slice(0, 8);
2770
- return `delegate_${stem ? `${stem}_` : ""}${h}`;
2771
- }
2772
- var now = () => (/* @__PURE__ */ new Date()).toISOString();
2773
- function registerDelegateCall(db, opts) {
2774
- const state = opts.state ?? "queued";
2775
- return withOpContext(
2776
- db,
2777
- { intent: "delegate.register", actor: opts.caller, group: "new" },
2778
- () => db.transaction(() => {
2779
- const existing = getDelegateCall(db, opts.callId);
2780
- if (existing) {
2781
- const same = (field, a, b) => {
2782
- if (canonical(a) !== canonical(b))
2783
- throw new DelegateCallConflictError(opts.callId, field);
2784
- };
2785
- same("caller", existing.caller, opts.caller);
2786
- same("workstream", existing.workstream, opts.workstream);
2787
- same("wave", existing.wave, opts.wave ?? null);
2788
- same(
2789
- "record target",
2790
- existing.record ? { workstream: existing.record.workstream, task: existing.record.task } : null,
2791
- opts.record ?? null
2792
- );
2793
- same("request", existing.request, opts.request);
2794
- return { call: existing, created: false };
2795
- }
2796
- if (opts.record && !getTask(db, opts.record.task, opts.record.workstream))
2797
- throw new TaskNotFoundError(opts.record.task, opts.record.workstream);
2798
- const local = taskIdFor2(opts.callId, opts.request.label);
2799
- const headline = (opts.request.label ?? opts.request.text).replace(/\s+/g, " ").trim();
2800
- addTask(db, {
2801
- localId: local,
2802
- workstream: opts.workstream,
2803
- title: `delegate: ${headline.slice(0, 60)}`,
2804
- kind: "delegate",
2805
- ...opts.wave !== void 0 ? { wave: opts.wave } : {}
2806
- });
2807
- addNote(db, local, opts.request.text, {
2808
- workstream: opts.workstream,
2809
- kind: "brief",
2810
- author: opts.caller,
2811
- group: "inherit"
2812
- });
2813
- if (state !== "starting")
2814
- setTaskStatus(db, local, "OPEN", { workstream: opts.workstream, substate: "parked" });
2815
- const taskId = db.prepare(
2816
- "SELECT t.id AS id FROM tasks t JOIN workstreams w ON w.id = t.workstream_id WHERE w.name = ? AND t.local_id = ?"
2817
- ).get(opts.workstream, local).id;
2818
- db.prepare(
2819
- `INSERT INTO delegate_calls
2820
- (task_id, caller, call_id, state, record_workstream, record_task, record_label, updated_at, request)
2821
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
2822
- ).run(
2823
- taskId,
2824
- opts.caller,
2825
- opts.callId,
2826
- state,
2827
- opts.record?.workstream ?? null,
2828
- opts.record?.task ?? null,
2829
- opts.request.label ?? null,
2830
- now(),
2831
- canonical(opts.request)
2832
- );
2833
- return { call: mustGet(db, opts.callId), created: true };
2834
- }).immediate()
2835
- );
2836
- }
2837
- var MOVES = {
2838
- queued: ["refused"],
2839
- starting: ["queued", "refused"],
2840
- running: ["starting"],
2841
- refused: ["queued", "starting"]
2842
- };
2843
- function markDelegate(db, callId, to, extra = {}) {
2844
- const row = mustGet(db, callId);
2845
- const from = MOVES[to] ?? [];
2846
- if (!from.includes(row.state)) throw new DelegateStateError(callId, row.state, to);
2847
- return withOpContext(
2848
- db,
2849
- { intent: `delegate.${to}`, actor: row.caller, group: "new" },
2850
- () => db.transaction(() => {
2851
- const r = db.prepare(
2852
- `UPDATE delegate_calls
2853
- SET state = ?, updated_at = ?, agent = COALESCE(?, agent),
2854
- error = CASE WHEN ? = 'refused' THEN COALESCE(?, error) ELSE NULL END
2855
- WHERE call_id = ? AND state = ?`
2856
- ).run(to, now(), extra.agent ?? null, to, extra.error ?? null, callId, row.state);
2857
- if (r.changes !== 1) throw new DelegateStateError(callId, mustGet(db, callId).state, to);
2858
- if (to === "starting")
2859
- setTaskStatus(db, row.task, "OPEN", { workstream: row.workstream, substate: "todo" });
2860
- if (to === "refused")
2861
- setTaskStatus(db, row.task, "OPEN", { workstream: row.workstream, substate: "parked" });
2862
- return mustGet(db, callId);
2863
- }).immediate()
2864
- );
2865
- }
2866
- function closedBy(db, task, workstream) {
2867
- const row = db.prepare(
2868
- `SELECT n.author AS author FROM task_notes n
2869
- JOIN tasks t ON t.id = n.task_id JOIN workstreams w ON w.id = t.workstream_id
2870
- WHERE w.name = ? AND t.local_id = ? AND t.status = 'CLOSED' AND n.kind = 'close'
2871
- ORDER BY n.id DESC LIMIT 1`
2872
- ).get(workstream, task);
2873
- return row?.author ?? null;
2874
- }
2875
- function finishText(outcome, text) {
2876
- if (outcome === "done") return text ?? "";
2877
- return `no answer (${outcome})${text?.trim() ? `
2878
-
2879
- ${text.trimEnd()}` : ""}`;
2880
- }
2881
- function finishDelegate(db, callId, opts) {
2882
- const before = mustGet(db, callId);
2883
- const unchanged = (row) => ({
2884
- changed: false,
2885
- state: row.state,
2886
- task: row.task,
2887
- record: row.record ? { workstream: row.record.workstream, task: row.record.task } : null,
2888
- recorded: false,
2889
- verdict: row.verdict
2890
- });
2891
- if (isTerminal(before.state)) return unchanged(before);
2892
- db.prepare(
2893
- "UPDATE delegate_calls SET state = 'recording', updated_at = ? WHERE call_id = ? AND state NOT IN ('done','failed','cancelled')"
2894
- ).run(now(), callId);
2895
- const outcome = opts.outcome === "done" && !opts.text?.trim() ? "empty" : opts.outcome;
2896
- const answered = outcome === "done";
2897
- const cancelled = outcome === "cancelled";
2898
- const label = before.record?.label ?? before.request.label ?? opts.author;
2899
- const verdict = answered ? parseVerdict(opts.text ?? "") ?? null : null;
2900
- const record = before.record ? { workstream: before.record.workstream, task: before.record.task } : null;
2901
- const report = finishText(outcome, opts.text);
2902
- const wantRecord = opts.record !== false;
2903
- const write = (recordIt, error) => withOpContext(
2904
- db,
2905
- { intent: "delegate.finish", actor: opts.author, group: "new" },
2906
- () => db.transaction(() => {
2907
- const cur = mustGet(db, callId);
2908
- if (isTerminal(cur.state)) return unchanged(cur);
2909
- if (recordIt && record)
2910
- addNote(
2911
- db,
2912
- record.task,
2913
- recordNote(label, opts.author, outcome, opts.text, opts.elapsedMs ?? 0),
2914
- {
2915
- workstream: record.workstream,
2916
- kind: "verdict",
2917
- author: opts.author,
2918
- group: "inherit"
2919
- }
2920
- );
2921
- const ok = answered && error === void 0;
2922
- const state = ok ? "done" : cancelled ? "cancelled" : "failed";
2923
- const selfClosed = cur.agent !== null && closedBy(db, cur.task, cur.workstream) === cur.agent;
2924
- if (selfClosed)
2925
- addNote(db, cur.task, report, {
2926
- workstream: cur.workstream,
2927
- kind: "report",
2928
- author: opts.author,
2929
- group: "inherit"
2930
- });
2931
- closeTask(db, cur.task, {
2932
- workstream: cur.workstream,
2933
- author: opts.author,
2934
- group: "inherit",
2935
- ...selfClosed ? {} : { report },
2936
- as: ok ? "done" : cancelled ? "wontfix" : "rejected",
2937
- ...ok ? { evidence: `answered ${verdict ?? "with no VERDICT line"} (call ${callId})` } : { why: error ?? `${outcome}: no answer (call ${callId})` }
2938
- });
2939
- db.prepare(
2940
- "UPDATE delegate_calls SET state = ?, verdict = ?, error = ?, updated_at = ? WHERE call_id = ?"
2941
- ).run(state, ok ? verdict : null, error ?? null, now(), callId);
2942
- return {
2943
- changed: true,
2944
- state,
2945
- task: cur.task,
2946
- record,
2947
- recorded: recordIt && record !== null,
2948
- verdict: ok ? verdict : null,
2949
- ...error !== void 0 ? { error } : {}
2950
- };
2951
- }).immediate()
2952
- );
2953
- try {
2954
- return write(wantRecord);
2955
- } catch (e) {
2956
- const msg = e instanceof Error ? e.message : String(e);
2957
- return write(
2958
- false,
2959
- `record ${record ? `${record.workstream}/${record.task} ` : ""}failed: ${msg}`
2960
- );
2961
- }
2962
- }
2963
- function verdictTally(db, workstream, wave, callers) {
2964
- return tallyCalls(
2965
- callers === void 0 ? listDelegates(db, void 0, workstream, { wave }) : listDelegatesOf(db, callers, workstream, { wave })
2966
- );
2967
- }
2968
- function tallyCalls(calls) {
2969
- const out = { findings: [], queued: 0, running: 0, refused: [] };
2970
- const byId = /* @__PURE__ */ new Map();
2971
- for (const c of calls) {
2972
- const id = c.record ? `${c.record.workstream}/${c.record.task}` : `${c.workstream}/${c.task}`;
2973
- let f = byId.get(id);
2974
- if (!f) {
2975
- f = { id, confirmed: 0, refuted: 0, unverified: 0, pending: 0 };
2976
- byId.set(id, f);
2977
- out.findings.push(f);
2978
- }
2979
- switch (c.state) {
2980
- case "done":
2981
- if (c.verdict === "CONFIRMED") f.confirmed++;
2982
- else if (c.verdict === "REFUTED") f.refuted++;
2983
- else f.unverified++;
2984
- break;
2985
- case "failed":
2986
- case "cancelled":
2987
- f.unverified++;
2988
- break;
2989
- case "refused":
2990
- f.pending++;
2991
- out.refused.push(c.callId);
2992
- break;
2993
- case "queued":
2994
- f.pending++;
2995
- out.queued++;
2996
- break;
2997
- default:
2998
- f.pending++;
2999
- out.running++;
3000
- }
3001
- }
3002
- return out;
3003
- }
3004
-
3005
2617
  // src/human-needed.ts
3006
2618
  var HumanNeededInvalidError = class extends Error {
3007
2619
  name = "HumanNeededInvalidError";
@@ -3171,7 +2783,7 @@ function ownedWaitMove(db, callers, ws) {
3171
2783
  }
3172
2784
  var COURSE_CHECK_CLOSED = 10;
3173
2785
  var COURSE_CHECK_AGE_MS = 24 * 36e5;
3174
- function courseCheckHint(db, ws, now2 = Date.now()) {
2786
+ function courseCheckHint(db, ws, now = Date.now()) {
3175
2787
  const row = db.prepare(
3176
2788
  `WITH w AS (SELECT id, created_at FROM workstreams WHERE name = ? AND torn_down_at IS NULL),
3177
2789
  a AS (SELECT COALESCE(
@@ -3185,7 +2797,7 @@ function courseCheckHint(db, ws, now2 = Date.now()) {
3185
2797
  FROM a`
3186
2798
  ).get(ws);
3187
2799
  if (row === void 0 || row.closed === 0) return void 0;
3188
- const old = now2 - Date.parse(row.since) >= COURSE_CHECK_AGE_MS;
2800
+ const old = now - Date.parse(row.since) >= COURSE_CHECK_AGE_MS;
3189
2801
  if (row.closed < COURSE_CHECK_CLOSED && !old) return void 0;
3190
2802
  return `course check due: ${row.closed} closed since ${row.since.slice(0, 16)}Z. Stop dispatching: finish merging, then follow recipes/course-correct.md`;
3191
2803
  }
@@ -3204,13 +2816,13 @@ function computeNext(db, ctx) {
3204
2816
  }
3205
2817
  return capPlan(renderPlan("alt", moves)).next;
3206
2818
  }
3207
- function computeNotices(db, ctx, now2 = Date.now()) {
3208
- const hint = ctx.workstream === void 0 || isScratchWorkstream(ctx.workstream) ? void 0 : courseCheckHint(db, ctx.workstream, now2);
2819
+ function computeNotices(db, ctx, now = Date.now()) {
2820
+ const hint = ctx.workstream === void 0 || isScratchWorkstream(ctx.workstream) ? void 0 : courseCheckHint(db, ctx.workstream, now);
3209
2821
  return hint === void 0 ? [] : [hint];
3210
2822
  }
3211
- function noticesField(db, workstreams, now2 = Date.now()) {
2823
+ function noticesField(db, workstreams, now = Date.now()) {
3212
2824
  const notices = [...new Set(workstreams)].flatMap(
3213
- (workstream) => computeNotices(db, { callers: [], workstream }, now2)
2825
+ (workstream) => computeNotices(db, { callers: [], workstream }, now)
3214
2826
  );
3215
2827
  return notices.length > 0 ? { notices } : {};
3216
2828
  }
@@ -3260,7 +2872,7 @@ var PEER_STALE_MS = 24 * 60 * 60 * 1e3;
3260
2872
  var PEER_SHORT_LEN = 8;
3261
2873
  function peerStatuses(db, dir) {
3262
2874
  const self = localMachineId(db);
3263
- const now2 = Date.now();
2875
+ const now = Date.now();
3264
2876
  const rows = discoverPeers(dir, self).map((peer) => {
3265
2877
  let lastSeenMs = null;
3266
2878
  try {
@@ -3271,7 +2883,7 @@ function peerStatuses(db, dir) {
3271
2883
  const watermarkKey = peerWatermarkKey(peer);
3272
2884
  const watermark = getWatermark(db, watermarkKey);
3273
2885
  const total = segmentCaughtUp(db, watermarkKey, peer.path, watermark) ? watermark : segmentLineCount(peer.path);
3274
- const ageMs = lastSeenMs === null ? null : Math.max(0, now2 - lastSeenMs);
2886
+ const ageMs = lastSeenMs === null ? null : Math.max(0, now - lastSeenMs);
3275
2887
  return {
3276
2888
  machineId: peer.machineId,
3277
2889
  short: peer.machineId.slice(0, PEER_SHORT_LEN),
@@ -3491,6 +3103,7 @@ function agentToOutput(row, workstreamId2, live = {}) {
3491
3103
  spawner: row.spawner,
3492
3104
  host: row.host,
3493
3105
  collected_head: row.collectedHead,
3106
+ repo: row.repo,
3494
3107
  gate_token: row.gateToken,
3495
3108
  created_at: row.createdAt,
3496
3109
  updated_at: row.updatedAt,
@@ -4012,19 +3625,6 @@ export {
4012
3625
  logPage,
4013
3626
  logOut,
4014
3627
  logReceipt,
4015
- parseVerdict,
4016
- TERMINAL_DELEGATE_STATES,
4017
- DelegateCallConflictError,
4018
- DelegateStateError,
4019
- DelegateNotFoundError,
4020
- getDelegateCall,
4021
- listDelegates,
4022
- listDelegatesOf,
4023
- registerDelegateCall,
4024
- markDelegate,
4025
- finishDelegate,
4026
- verdictTally,
4027
- tallyCalls,
4028
3628
  HumanNeededInvalidError,
4029
3629
  recordHumanNeeded,
4030
3630
  openHumanNeeds,
@@ -4057,4 +3657,4 @@ export {
4057
3657
  ingestFromDb,
4058
3658
  currentCallers
4059
3659
  };
4060
- //# sourceMappingURL=chunk-GQNHIPJN.js.map
3660
+ //# sourceMappingURL=chunk-DEYBQDTO.js.map