@north-light/cli 0.3.524 → 0.3.526

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 (52) hide show
  1. package/dist/api/command-manifest/result.d.ts +4 -2
  2. package/dist/api/command-manifest/result.js +1 -1
  3. package/dist/api/command-manifest/schema.js +1 -1
  4. package/dist/api/plugin-manifest-schema.d.ts +3 -0
  5. package/dist/builtin-memory/crouter-plugin/deploying.md +2 -2
  6. package/dist/builtin-memory/crouter-plugin/output.md +3 -1
  7. package/dist/clients/attach/chrome/roster.d.ts +1 -1
  8. package/dist/clients/attach/chrome/roster.js +4 -4
  9. package/dist/clients/attach/render/chat-view.d.ts +9 -0
  10. package/dist/clients/attach/render/chat-view.js +3 -3
  11. package/dist/clients/attach/render/page-block.d.ts +2 -0
  12. package/dist/clients/attach/render/page-block.js +1 -1
  13. package/dist/clients/attach/session/connection.d.ts +1 -1
  14. package/dist/clients/attach/session/context.d.ts +1 -1
  15. package/dist/clients/attach/session/profile-files.d.ts +3 -3
  16. package/dist/clients/attach/session/profile-files.js +1 -1
  17. package/dist/clients/attach/viewer.js +633 -756
  18. package/dist/commands/pkg/browse/command-view.js +1 -1
  19. package/dist/core/canvas/db.d.ts +28 -2
  20. package/dist/core/canvas/db.js +2 -2
  21. package/dist/core/canvas/migrations.js +53 -53
  22. package/dist/core/canvas/nav-model.js +1 -1
  23. package/dist/core/canvas/recovery.d.ts +13 -0
  24. package/dist/core/canvas/recovery.js +2 -2
  25. package/dist/core/conversation-store/client.d.ts +2 -2
  26. package/dist/core/conversation-store/index.d.ts +30 -2
  27. package/dist/core/conversation-store/index.js +1 -1
  28. package/dist/core/conversation-store/patch.js +1 -1
  29. package/dist/core/graph/watches.d.ts +2 -0
  30. package/dist/core/graph/watches.js +9 -9
  31. package/dist/core/help.js +7 -7
  32. package/dist/core/llm/run.js +2 -2
  33. package/dist/core/runtime/broker/fault-retry.d.ts +9 -3
  34. package/dist/core/runtime/broker/fault-retry.js +1 -1
  35. package/dist/core/runtime/broker/rebind.d.ts +4 -0
  36. package/dist/core/runtime/broker/rebind.js +1 -1
  37. package/dist/core/runtime/broker/run-turn-queue.d.ts +2 -0
  38. package/dist/core/runtime/broker/run-turn-queue.js +1 -1
  39. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  40. package/dist/core/runtime/broker-persona-guidance.js +3 -3
  41. package/dist/core/runtime/broker.js +1 -1
  42. package/dist/core/runtime/close.d.ts +2 -2
  43. package/dist/core/runtime/close.js +1 -1
  44. package/dist/daemon/crtrd.js +8 -8
  45. package/dist/daemon/reconcilers/broker-supervision.d.ts +6 -2
  46. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  47. package/dist/daemon/runs/observer.js +2 -2
  48. package/docs/plugin/deploying.md +2 -2
  49. package/docs/plugin/output.md +3 -1
  50. package/package.json +2 -2
  51. package/packages/crouter-identity/package.json +1 -1
  52. package/runtime.lock.json +12 -12
@@ -1,4 +1,4 @@
1
- var Te=Object.defineProperty;var E=(e,t)=>Te(e,"name",{value:t,configurable:!0});import{randomBytes as P}from"node:crypto";import{parseScope as ae}from"@north-light/identity";import{importNodeSqlAuthority as de,recreateNodeRowsView as _e}from"./node-sql-migration.js";import{migrateRecoveryWitnesses as Ne}from"./recovery.js";import{migrateMessagingState as ce}from"./deliveries.js";import{migrateHumanRequestsState as Le}from"../human/requests.js";import{existsSync as U,readFileSync as M,readdirSync as k,realpathSync as le,statSync as ue}from"node:fs";import{basename as pe,join as j,resolve as Y}from"node:path";import{appSpace as Re}from"../layout.js";import{emitEvent as Ae}from"../events/emit.js";import{isSafeNodeId as Oe,nodesRoot as h,nodeMetaPath as x}from"./paths.js";import{convertLegacyEdges as Ie}from"../../migrations/004-canvas-documents/legacy-edges.js";import{customExtensionPaths as me}from"./extensions.js";import{readMetaObject as K,updateJsonFileDurably as q,withMetaLock as fe,writeMetaObjectLocked as Xe}from"./meta-file.js";function Ue(e){e.exec(`
1
+ var Te=Object.defineProperty;var E=(e,t)=>Te(e,"name",{value:t,configurable:!0});import{randomBytes as P}from"node:crypto";import{parseScope as ae}from"@north-light/identity";import{importNodeSqlAuthority as de,recreateNodeRowsView as _e}from"./node-sql-migration.js";import{addFaultNotifiedSince as Ne,migrateRecoveryWitnesses as ce}from"./recovery.js";import{migrateMessagingState as Le}from"./deliveries.js";import{migrateHumanRequestsState as le}from"../human/requests.js";import{existsSync as U,readFileSync as M,readdirSync as k,realpathSync as ue,statSync as pe}from"node:fs";import{basename as Re,join as j,resolve as Y}from"node:path";import{appSpace as Ae}from"../layout.js";import{emitEvent as Oe}from"../events/emit.js";import{isSafeNodeId as Ie,nodesRoot as h,nodeMetaPath as x}from"./paths.js";import{convertLegacyEdges as me}from"../../migrations/004-canvas-documents/legacy-edges.js";import{customExtensionPaths as fe}from"./extensions.js";import{readMetaObject as K,updateJsonFileDurably as q,withMetaLock as Xe,writeMetaObjectLocked as Ue}from"./meta-file.js";function Ce(e){e.exec(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  node_id TEXT PRIMARY KEY,
4
4
  name TEXT NOT NULL,
@@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS edges (
23
23
  CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(type, to_id);
24
24
  CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(type, from_id);
25
25
  CREATE INDEX IF NOT EXISTS idx_nodes_status ON nodes(status);
26
- `)}E(Ue,"baselineSchema");function b(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(n=>n.name))}E(b,"tableColumns");function $(e,t,n,o){t.has(n)||(e.exec(o),t.add(n))}E($,"addColumnIfMissing");function O(e){return b(e,"nodes")}E(O,"nodeColumns");const c=$;function Ce(e){const t=O(e);c(e,t,"intent","ALTER TABLE nodes ADD COLUMN intent TEXT;"),c(e,t,"pi_pid","ALTER TABLE nodes ADD COLUMN pi_pid INTEGER;"),c(e,t,"window","ALTER TABLE nodes ADD COLUMN window TEXT;"),c(e,t,"tmux_session","ALTER TABLE nodes ADD COLUMN tmux_session TEXT;")}E(Ce,"addRuntimeColumns");function Se(e){const t=h();if(!U(t))return;const n=e.prepare('UPDATE nodes SET intent = ?, pi_pid = ?, "window" = ?, tmux_session = ? WHERE node_id = ?');for(const o of k(t)){const T=x(o);if(!U(T))continue;let i;try{i=JSON.parse(M(T,"utf8"))}catch{continue}n.run(i.intent??null,i.pi_pid??null,i.window??null,i.tmux_session??null,o)}}E(Se,"backfillRuntime");function De(e){B(e,3,()=>{if(!(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'edges'").get()!==void 0)){e.exec(`
26
+ `)}E(Ce,"baselineSchema");function b(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(n=>n.name))}E(b,"tableColumns");function $(e,t,n,o){t.has(n)||(e.exec(o),t.add(n))}E($,"addColumnIfMissing");function O(e){return b(e,"nodes")}E(O,"nodeColumns");const c=$;function Se(e){const t=O(e);c(e,t,"intent","ALTER TABLE nodes ADD COLUMN intent TEXT;"),c(e,t,"pi_pid","ALTER TABLE nodes ADD COLUMN pi_pid INTEGER;"),c(e,t,"window","ALTER TABLE nodes ADD COLUMN window TEXT;"),c(e,t,"tmux_session","ALTER TABLE nodes ADD COLUMN tmux_session TEXT;")}E(Se,"addRuntimeColumns");function De(e){const t=h();if(!U(t))return;const n=e.prepare('UPDATE nodes SET intent = ?, pi_pid = ?, "window" = ?, tmux_session = ? WHERE node_id = ?');for(const o of k(t)){const T=x(o);if(!U(T))continue;let i;try{i=JSON.parse(M(T,"utf8"))}catch{continue}n.run(i.intent??null,i.pi_pid??null,i.window??null,i.tmux_session??null,o)}}E(De,"backfillRuntime");function ge(e){B(e,3,()=>{if(!(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'edges'").get()!==void 0)){e.exec(`
27
27
  CREATE TABLE edges (
28
28
  type TEXT NOT NULL,
29
29
  from_id TEXT NOT NULL,
@@ -57,14 +57,14 @@ DROP TABLE edges;
57
57
  ALTER TABLE edges_new RENAME TO edges;
58
58
  CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(type, to_id);
59
59
  CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(type, from_id);
60
- `);const o=e.prepare("SELECT COUNT(*) AS n FROM edges").get().n;if(o!==n)throw new Error(`edges FK rebuild lost rows: expected ${n} non-orphan edge(s), got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`edges FK rebuild left ${T.length} foreign-key violation(s)`)})}E(De,"edgesForeignKeyCascade");function ge(e){const t=O(e);c(e,t,"pane","ALTER TABLE nodes ADD COLUMN pane TEXT;")}E(ge,"addPaneColumn");function we(e){e.exec(`
60
+ `);const o=e.prepare("SELECT COUNT(*) AS n FROM edges").get().n;if(o!==n)throw new Error(`edges FK rebuild lost rows: expected ${n} non-orphan edge(s), got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`edges FK rebuild left ${T.length} foreign-key violation(s)`)})}E(ge,"edgesForeignKeyCascade");function we(e){const t=O(e);c(e,t,"pane","ALTER TABLE nodes ADD COLUMN pane TEXT;")}E(we,"addPaneColumn");function ye(e){e.exec(`
61
61
  CREATE TABLE IF NOT EXISTS focuses (
62
62
  focus_id TEXT PRIMARY KEY, -- stable internal id for the viewport
63
63
  pane TEXT, -- the durable %pane_id realizing the focus
64
64
  session TEXT, -- derived cache of the user session (reconciled from pane)
65
65
  node_id TEXT NOT NULL UNIQUE -- the node shown; UNIQUE \u2192 a node occupies <=1 focus
66
66
  );
67
- `)}E(we,"addFocusesTable");function ye(e){e.exec(`
67
+ `)}E(ye,"addFocusesTable");function ve(e){e.exec(`
68
68
  CREATE TABLE IF NOT EXISTS wakeups (
69
69
  wakeup_id TEXT PRIMARY KEY,
70
70
  node_id TEXT, -- TARGET + node-anchored cancel anchor; NULL = canvas-detached
@@ -80,7 +80,7 @@ CREATE INDEX IF NOT EXISTS idx_wakeups_fire ON wakeups(fire_at);
80
80
  CREATE INDEX IF NOT EXISTS idx_wakeups_node ON wakeups(node_id); -- by-node cancel / list
81
81
  CREATE INDEX IF NOT EXISTS idx_wakeups_owner ON wakeups(owner_id); -- by-owner reap (ruling A)
82
82
  CREATE UNIQUE INDEX IF NOT EXISTS idx_wakeups_deadline ON wakeups(node_id) WHERE kind = 'deadline';
83
- `)}E(ye,"appendWakeupsTable");function ve(e){e.exec(`
83
+ `)}E(ve,"appendWakeupsTable");function he(e){e.exec(`
84
84
  CREATE TABLE IF NOT EXISTS triggers (
85
85
  trigger_id TEXT PRIMARY KEY,
86
86
  owner_id TEXT NOT NULL,
@@ -131,12 +131,12 @@ SELECT
131
131
  FROM wakeups;
132
132
 
133
133
  DROP TABLE wakeups;
134
- `)}E(ve,"migrateWakeupsToTriggers");function he(e){const t=O(e);c(e,t,"host_kind","ALTER TABLE nodes ADD COLUMN host_kind TEXT;")}E(he,"addHostKindColumn");function xe(e){e.exec(`
134
+ `)}E(he,"migrateWakeupsToTriggers");function xe(e){const t=O(e);c(e,t,"host_kind","ALTER TABLE nodes ADD COLUMN host_kind TEXT;")}E(xe,"addHostKindColumn");function Fe(e){e.exec(`
135
135
  CREATE TABLE IF NOT EXISTS canvas_meta (
136
136
  key TEXT PRIMARY KEY,
137
137
  value TEXT NOT NULL
138
138
  );
139
- `)}E(xe,"addCanvasMetaTable");function Fe(e){const t=O(e);c(e,t,"profile_id","ALTER TABLE nodes ADD COLUMN profile_id TEXT;")}E(Fe,"addProfileIdColumn");function Me(e){const t=O(e);c(e,t,"pi_pid_identity","ALTER TABLE nodes ADD COLUMN pi_pid_identity TEXT;")}E(Me,"addPidIdentityColumn");function ke(e){const t=O(e);c(e,t,"waiting_for","ALTER TABLE nodes ADD COLUMN waiting_for TEXT;")}E(ke,"addMessageWaitColumn");function J(e){const t=O(e);if(t.size===0)return;c(e,t,"final_report","ALTER TABLE nodes ADD COLUMN final_report TEXT;"),c(e,t,"finalized_at","ALTER TABLE nodes ADD COLUMN finalized_at TEXT;");const n=e.prepare("SELECT node_id FROM nodes WHERE status = 'done' AND final_report IS NULL").all(),o=e.prepare("UPDATE nodes SET final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL");for(const{node_id:T}of n){const i=j(h(),T,"reports");if(!U(i))continue;let a=null;for(const N of k(i))if(N.endsWith(".md"))try{const L=M(j(i,N),"utf8"),l=/^---\nnode: [^\n]+\nkind: final\nts: ([^\n]+)\n---\n/.exec(L);if(l===null||Number.isNaN(Date.parse(l[1])))continue;const r={name:N,ts:l[1]};(a===null||r.ts>a.ts||r.ts===a.ts&&r.name>a.name)&&(a=r)}catch{}a!==null&&o.run(a.name,a.ts,T)}}E(J,"addCanonicalFinalColumns");function je(e){const t=h();if(U(t))for(const n of k(t)){const o=x(n);U(o)&&q(o,T=>{const i=T.launch;if(typeof i!="object"||i===null||Array.isArray(i))return!1;const a=i.extensions;if(!Array.isArray(a)||!a.every(L=>typeof L=="string"))return!1;const N=me(a);return N.length===a.length?!1:(i.extensions=N,!0)})}}E(je,"normalizePersistedLaunchExtensions");function He(e){const t=O(e);c(e,t,"waiting_for_generation","ALTER TABLE nodes ADD COLUMN waiting_for_generation INTEGER NOT NULL DEFAULT 0;")}E(He,"addMessageWaitGenerationColumn");function Ge(e){e.exec(`
139
+ `)}E(Fe,"addCanvasMetaTable");function Me(e){const t=O(e);c(e,t,"profile_id","ALTER TABLE nodes ADD COLUMN profile_id TEXT;")}E(Me,"addProfileIdColumn");function ke(e){const t=O(e);c(e,t,"pi_pid_identity","ALTER TABLE nodes ADD COLUMN pi_pid_identity TEXT;")}E(ke,"addPidIdentityColumn");function je(e){const t=O(e);c(e,t,"waiting_for","ALTER TABLE nodes ADD COLUMN waiting_for TEXT;")}E(je,"addMessageWaitColumn");function J(e){const t=O(e);if(t.size===0)return;c(e,t,"final_report","ALTER TABLE nodes ADD COLUMN final_report TEXT;"),c(e,t,"finalized_at","ALTER TABLE nodes ADD COLUMN finalized_at TEXT;");const n=e.prepare("SELECT node_id FROM nodes WHERE status = 'done' AND final_report IS NULL").all(),o=e.prepare("UPDATE nodes SET final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL");for(const{node_id:T}of n){const i=j(h(),T,"reports");if(!U(i))continue;let a=null;for(const N of k(i))if(N.endsWith(".md"))try{const L=M(j(i,N),"utf8"),l=/^---\nnode: [^\n]+\nkind: final\nts: ([^\n]+)\n---\n/.exec(L);if(l===null||Number.isNaN(Date.parse(l[1])))continue;const r={name:N,ts:l[1]};(a===null||r.ts>a.ts||r.ts===a.ts&&r.name>a.name)&&(a=r)}catch{}a!==null&&o.run(a.name,a.ts,T)}}E(J,"addCanonicalFinalColumns");function He(e){const t=h();if(U(t))for(const n of k(t)){const o=x(n);U(o)&&q(o,T=>{const i=T.launch;if(typeof i!="object"||i===null||Array.isArray(i))return!1;const a=i.extensions;if(!Array.isArray(a)||!a.every(L=>typeof L=="string"))return!1;const N=fe(a);return N.length===a.length?!1:(i.extensions=N,!0)})}}E(He,"normalizePersistedLaunchExtensions");function Ge(e){const t=O(e);c(e,t,"waiting_for_generation","ALTER TABLE nodes ADD COLUMN waiting_for_generation INTEGER NOT NULL DEFAULT 0;")}E(Ge,"addMessageWaitGenerationColumn");function be(e){e.exec(`
140
140
  CREATE TABLE IF NOT EXISTS consult_outbox (
141
141
  node_id TEXT PRIMARY KEY, -- legacy work node id
142
142
  dir TEXT NOT NULL, -- legacy ticket directory
@@ -150,15 +150,15 @@ CREATE INDEX IF NOT EXISTS idx_consult_outbox_status ON consult_outbox(status);
150
150
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_dir ON consult_outbox(dir);
151
151
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_dir_request_status ON consult_outbox(dir, request_id, status);
152
152
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_dir_status ON consult_outbox(dir, status);
153
- `)}E(Ge,"addHumanWorkOutboxTable");function be(e){const t=b(e,"consult_outbox"),n=E((o,T)=>$(e,t,o,T),"add");n("work_kind","ALTER TABLE consult_outbox ADD COLUMN work_kind TEXT NOT NULL DEFAULT 'follow_up';"),n("interaction_id","ALTER TABLE consult_outbox ADD COLUMN interaction_id TEXT;"),n("generation_id","ALTER TABLE consult_outbox ADD COLUMN generation_id TEXT;"),n("interaction_snapshot","ALTER TABLE consult_outbox ADD COLUMN interaction_snapshot TEXT;"),n("handler_command","ALTER TABLE consult_outbox ADD COLUMN handler_command TEXT;"),n("handler_args_json","ALTER TABLE consult_outbox ADD COLUMN handler_args_json TEXT;"),n("claim_token","ALTER TABLE consult_outbox ADD COLUMN claim_token TEXT;"),e.exec(`
153
+ `)}E(be,"addHumanWorkOutboxTable");function Be(e){const t=b(e,"consult_outbox"),n=E((o,T)=>$(e,t,o,T),"add");n("work_kind","ALTER TABLE consult_outbox ADD COLUMN work_kind TEXT NOT NULL DEFAULT 'follow_up';"),n("interaction_id","ALTER TABLE consult_outbox ADD COLUMN interaction_id TEXT;"),n("generation_id","ALTER TABLE consult_outbox ADD COLUMN generation_id TEXT;"),n("interaction_snapshot","ALTER TABLE consult_outbox ADD COLUMN interaction_snapshot TEXT;"),n("handler_command","ALTER TABLE consult_outbox ADD COLUMN handler_command TEXT;"),n("handler_args_json","ALTER TABLE consult_outbox ADD COLUMN handler_args_json TEXT;"),n("claim_token","ALTER TABLE consult_outbox ADD COLUMN claim_token TEXT;"),e.exec(`
154
154
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_human_work_status ON consult_outbox(work_kind, status);
155
155
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_human_work_dir_status ON consult_outbox(dir, work_kind, status);
156
156
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_human_work_request_status ON consult_outbox(dir, request_id, work_kind, status);
157
157
  CREATE UNIQUE INDEX IF NOT EXISTS idx_consult_outbox_visual_request ON consult_outbox(dir, request_id, work_kind) WHERE work_kind = 'visual';
158
- `)}E(be,"addHumanWorkColumns");function Be(e){e.exec(`
158
+ `)}E(Be,"addHumanWorkColumns");function We(e){e.exec(`
159
159
  CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent);
160
160
  CREATE INDEX IF NOT EXISTS idx_nodes_created ON nodes(created);
161
- `)}E(Be,"addNodeParentCreatedIndexes");function We(e){e.exec(`
161
+ `)}E(We,"addNodeParentCreatedIndexes");function Pe(e){e.exec(`
162
162
  CREATE TABLE IF NOT EXISTS crons (
163
163
  cron_id TEXT PRIMARY KEY,
164
164
  name TEXT NOT NULL, -- agent-legible label; how it shows in list
@@ -213,22 +213,22 @@ CREATE TABLE IF NOT EXISTS cron_runs ( -- bounded ring, last 20 p
213
213
  FOREIGN KEY (cron_id) REFERENCES crons(cron_id) ON DELETE CASCADE
214
214
  );
215
215
  CREATE INDEX IF NOT EXISTS idx_cron_runs_cron ON cron_runs(cron_id, started);
216
- `)}E(We,"addCronsTables");function g(e){return`'${e.replace(/'/g,`'"'"'`)}'`}E(g,"shellSingleQuote");function Pe(e,t){let n=0;for(;;){const o=`${t}_${n}`;if(!e.split(`
217
- `).includes(o))return o;n++}}E(Pe,"uniqueHeredocDelimiter");function Q(e,t,n){const o=Pe(t,n);return`${e} <<'${o}'
216
+ `)}E(Pe,"addCronsTables");function g(e){return`'${e.replace(/'/g,`'"'"'`)}'`}E(g,"shellSingleQuote");function Ye(e,t){let n=0;for(;;){const o=`${t}_${n}`;if(!e.split(`
217
+ `).includes(o))return o;n++}}E(Ye,"uniqueHeredocDelimiter");function Q(e,t,n){const o=Ye(t,n);return`${e} <<'${o}'
218
218
  ${t}
219
- ${o}`}E(Q,"heredocCommand");function Ye(e){if(typeof e!="string")return{};try{const t=JSON.parse(e);return typeof t!="object"||t===null||Array.isArray(t)?{}:t}catch{return{}}}E(Ye,"migrationPayload");function X(e,t,n){const o=e[t];if(typeof o!="string"||o.trim()==="")throw new Error(`trigger ${n} payload requires non-empty ${t}`);return o}E(X,"requiredString");function H(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(H,"optionalString");function w(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(w,"optionalColumn");function z(e,t,n,o){return Q(`crtr node message send --to ${g(e)} --tier ${g(t)}`,n,`CRTR_MIGRATED_${o.replace(/[^A-Za-z0-9]/g,"_")}`)}E(z,"migratedMessageCommand");function Ke(e,t){return`printf '%s\\n' "$CRTR_GATE_STDOUT" | crtr node message send --to ${g(e)} --tier ${g(t)}`}E(Ke,"migratedGateStdoutMessageCommand");function qe(e,t){const n=[`crtr node new --kind ${g(X(e,"kind",t))}`],o=[["mode","mode"],["cwd","cwd"],["name","name"],["parent","parent"],["worktreeBase","worktree"],["forkFrom","fork-from"],["model","model"],["profile","profile"],["situationalContext","situational-context"]];for(const[i,a]of o){const N=H(e,i);N!==void 0&&n.push(`--${a} ${g(N)}`)}e.root===!0&&n.push("--root");const T=X(e,"prompt",t);return Q(n.join(" "),T,`CRTR_MIGRATED_${t.replace(/[^A-Za-z0-9]/g,"_")}`)}E(qe,"migratedSpawnCommand");const V="migration.v22.skipped";function $e(e){const t=e.prepare("SELECT cwd FROM nodes WHERE parent IS NULL ORDER BY created LIMIT 1").get();return(t!==void 0?w(t,"cwd"):void 0)??process.cwd()}E($e,"ambientMigrationCwd");function Je(e){let t;try{t=e.prepare("SELECT eval_pid FROM triggers WHERE eval_state = 'running' AND eval_pid IS NOT NULL").all()}catch{return}for(const n of t){const o=n.eval_pid;if(!(typeof o!="number"||!Number.isInteger(o)||o<=1))try{process.kill(-o,"SIGTERM")}catch{}}}E(Je,"reapRunningPredicateEvaluations");function Qe(e){const t=[],n=e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'triggers'").get()!==void 0;n&&Je(e);let o=[];if(n)try{o=e.prepare("SELECT * FROM triggers ORDER BY created, trigger_id").all()}catch(a){t.push({trigger_id:"<unreadable table>",reason:`triggers table could not be read: ${a instanceof Error?a.message:String(a)}`})}const T=$e(e),i=e.prepare(`
219
+ ${o}`}E(Q,"heredocCommand");function Ke(e){if(typeof e!="string")return{};try{const t=JSON.parse(e);return typeof t!="object"||t===null||Array.isArray(t)?{}:t}catch{return{}}}E(Ke,"migrationPayload");function X(e,t,n){const o=e[t];if(typeof o!="string"||o.trim()==="")throw new Error(`trigger ${n} payload requires non-empty ${t}`);return o}E(X,"requiredString");function H(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(H,"optionalString");function w(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(w,"optionalColumn");function z(e,t,n,o){return Q(`crtr node message send --to ${g(e)} --tier ${g(t)}`,n,`CRTR_MIGRATED_${o.replace(/[^A-Za-z0-9]/g,"_")}`)}E(z,"migratedMessageCommand");function qe(e,t){return`printf '%s\\n' "$CRTR_GATE_STDOUT" | crtr node message send --to ${g(e)} --tier ${g(t)}`}E(qe,"migratedGateStdoutMessageCommand");function $e(e,t){const n=[`crtr node new --kind ${g(X(e,"kind",t))}`],o=[["mode","mode"],["cwd","cwd"],["name","name"],["parent","parent"],["worktreeBase","worktree"],["forkFrom","fork-from"],["model","model"],["profile","profile"],["situationalContext","situational-context"]];for(const[i,a]of o){const N=H(e,i);N!==void 0&&n.push(`--${a} ${g(N)}`)}e.root===!0&&n.push("--root");const T=X(e,"prompt",t);return Q(n.join(" "),T,`CRTR_MIGRATED_${t.replace(/[^A-Za-z0-9]/g,"_")}`)}E($e,"migratedSpawnCommand");const V="migration.v22.skipped";function Je(e){const t=e.prepare("SELECT cwd FROM nodes WHERE parent IS NULL ORDER BY created LIMIT 1").get();return(t!==void 0?w(t,"cwd"):void 0)??process.cwd()}E(Je,"ambientMigrationCwd");function Qe(e){let t;try{t=e.prepare("SELECT eval_pid FROM triggers WHERE eval_state = 'running' AND eval_pid IS NOT NULL").all()}catch{return}for(const n of t){const o=n.eval_pid;if(!(typeof o!="number"||!Number.isInteger(o)||o<=1))try{process.kill(-o,"SIGTERM")}catch{}}}E(Qe,"reapRunningPredicateEvaluations");function ze(e){const t=[],n=e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'triggers'").get()!==void 0;n&&Qe(e);let o=[];if(n)try{o=e.prepare("SELECT * FROM triggers ORDER BY created, trigger_id").all()}catch(a){t.push({trigger_id:"<unreadable table>",reason:`triggers table could not be read: ${a instanceof Error?a.message:String(a)}`})}const T=Je(e),i=e.prepare(`
220
220
  INSERT OR REPLACE INTO crons (
221
221
  cron_id, name, created_by, command, fire_at, recur, tz, expires_at,
222
222
  anchor_node, cancel_on_wake, cwd, env_json, profile, scope,
223
223
  run_timeout_s, overlap, on_output, sink, tier, created, updated
224
- ) VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, NULL, ?, 'profile', ?, 'skip', 'on-failure', '{}', ?, ?, ?)`);for(const a of o){const N=w(a,"trigger_id");if(N===void 0){t.push({trigger_id:"<unidentified row>",reason:"row carries no trigger_id"});continue}try{ze(e,i,a,N,T)}catch(L){t.push({trigger_id:N,reason:L instanceof Error?L.message:String(L)})}}t.length>0&&(e.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(V,JSON.stringify(t)),console.warn(`[canvas migration v22] ${t.length} retired schedule(s) could not be converted to crons and were dropped; see canvas_meta['${V}']: `+t.map(a=>`${a.trigger_id} (${a.reason})`).join("; "))),e.exec(`
224
+ ) VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, NULL, ?, 'profile', ?, 'skip', 'on-failure', '{}', ?, ?, ?)`);for(const a of o){const N=w(a,"trigger_id");if(N===void 0){t.push({trigger_id:"<unidentified row>",reason:"row carries no trigger_id"});continue}try{Ve(e,i,a,N,T)}catch(L){t.push({trigger_id:N,reason:L instanceof Error?L.message:String(L)})}}t.length>0&&(e.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(V,JSON.stringify(t)),console.warn(`[canvas migration v22] ${t.length} retired schedule(s) could not be converted to crons and were dropped; see canvas_meta['${V}']: `+t.map(a=>`${a.trigger_id} (${a.reason})`).join("; "))),e.exec(`
225
225
  DROP INDEX IF EXISTS idx_triggers_fire;
226
226
  DROP INDEX IF EXISTS idx_triggers_node;
227
227
  DROP INDEX IF EXISTS idx_triggers_owner;
228
228
  DROP INDEX IF EXISTS idx_triggers_eval;
229
229
  DROP INDEX IF EXISTS idx_triggers_deadline;
230
230
  DROP TABLE IF EXISTS triggers;
231
- `)}E(Qe,"migrateTriggersToCrons");function ze(e,t,n,o,T){const i=X(n,"owner_id",o),a=e.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(i),N=(a===void 0?void 0:w(a,"cwd"))??T,L=a===void 0?null:w(a,"profile_id")??null,l=w(n,"node_id")??null,r=X(n,"action",o),_=X(n,"action_mode",o),d=X(n,"trigger_type",o),u=Ye(n.payload),p=w(n,"created")??new Date().toISOString(),I=_==="deadline_message"?"urgent":H(u,"tier")??"normal",R=H(u,"label");let s,A,m=!1;if(r==="msg"&&(_==="inbox_message"||_==="deadline_message")){if(l===null)throw new Error("has no message target");const f=H(u,"body");f!==void 0?s=z(l,I,f,o):d==="when"?(m=!0,s=Ke(l,I)):s=z(l,I,R??"Scheduled message (no body was recorded when this schedule was armed).",o),A=R??(_==="deadline_message"?"deadline":"scheduled message")}else if(r==="msg"&&_==="fresh_revive"){if(l===null)throw new Error("has no revive target");s=`crtr node lifecycle revive ${g(l)} --fresh`,A=R??"scheduled fresh revive"}else if(r==="new"&&_==="node_birth")s=qe(u,o),A=H(u,"name")??`scheduled ${X(u,"kind",o)} node`;else throw new Error(`has unsupported action ${r}/${_}`);let D,y,G=null;if(d==="when"){D=X(n,"next_eval_at",o),y=X(n,"eval_every",o),G=w(n,"timeout_at")??null;const f=X(n,"when_script",o);s=`${m?`if ! CRTR_GATE_STDOUT="$(
231
+ `)}E(ze,"migrateTriggersToCrons");function Ve(e,t,n,o,T){const i=X(n,"owner_id",o),a=e.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(i),N=(a===void 0?void 0:w(a,"cwd"))??T,L=a===void 0?null:w(a,"profile_id")??null,l=w(n,"node_id")??null,r=X(n,"action",o),_=X(n,"action_mode",o),d=X(n,"trigger_type",o),u=Ke(n.payload),p=w(n,"created")??new Date().toISOString(),I=_==="deadline_message"?"urgent":H(u,"tier")??"normal",R=H(u,"label");let s,A,m=!1;if(r==="msg"&&(_==="inbox_message"||_==="deadline_message")){if(l===null)throw new Error("has no message target");const f=H(u,"body");f!==void 0?s=z(l,I,f,o):d==="when"?(m=!0,s=qe(l,I)):s=z(l,I,R??"Scheduled message (no body was recorded when this schedule was armed).",o),A=R??(_==="deadline_message"?"deadline":"scheduled message")}else if(r==="msg"&&_==="fresh_revive"){if(l===null)throw new Error("has no revive target");s=`crtr node lifecycle revive ${g(l)} --fresh`,A=R??"scheduled fresh revive"}else if(r==="new"&&_==="node_birth")s=$e(u,o),A=H(u,"name")??`scheduled ${X(u,"kind",o)} node`;else throw new Error(`has unsupported action ${r}/${_}`);let D,y,G=null;if(d==="when"){D=X(n,"next_eval_at",o),y=X(n,"eval_every",o),G=w(n,"timeout_at")??null;const f=X(n,"when_script",o);s=`${m?`if ! CRTR_GATE_STDOUT="$(
232
232
  ${f}
233
233
  )"; then`:`if ! (
234
234
  ${f}
@@ -237,14 +237,14 @@ ${f}
237
237
  fi
238
238
  {
239
239
  ${s}
240
- } && crtr cron cancel "$CRTR_CRON_ID"`}else if(d==="at"||d==="every"||d==="until")D=X(n,"fire_at",o),y=d==="every"?X(n,"recur",o):null;else throw new Error(`has unknown timing type ${d}`);if(_==="deadline_message"&&l!==null){const f=e.prepare("SELECT cron_id FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1 AND cron_id <> ?").get(l,o);if(f!==void 0)throw new Error(`node ${l} already has a migrated deadline (${String(f.cron_id)}); only one is allowed`)}t.run(o,A,i,s,D,y,G,l,_==="deadline_message"?1:0,N,L,300,I,p,p)}E(ze,"convertTriggerRow");function Ve(e){const t=b(e,"crons");t.size===0||t.has("run_pid_identity")||e.exec("ALTER TABLE crons ADD COLUMN run_pid_identity TEXT;")}E(Ve,"addCronRunPidIdentityColumn");function Ze(e){const t=b(e,"crons");t.size!==0&&(t.has("run_out_of_band")||e.exec("ALTER TABLE crons ADD COLUMN run_out_of_band INTEGER NOT NULL DEFAULT 0;"),t.has("queued")&&e.exec("ALTER TABLE crons DROP COLUMN queued;"))}E(Ze,"addCronOutOfBandColumn");function et(e){e.exec(`
240
+ } && crtr cron cancel "$CRTR_CRON_ID"`}else if(d==="at"||d==="every"||d==="until")D=X(n,"fire_at",o),y=d==="every"?X(n,"recur",o):null;else throw new Error(`has unknown timing type ${d}`);if(_==="deadline_message"&&l!==null){const f=e.prepare("SELECT cron_id FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1 AND cron_id <> ?").get(l,o);if(f!==void 0)throw new Error(`node ${l} already has a migrated deadline (${String(f.cron_id)}); only one is allowed`)}t.run(o,A,i,s,D,y,G,l,_==="deadline_message"?1:0,N,L,300,I,p,p)}E(Ve,"convertTriggerRow");function Ze(e){const t=b(e,"crons");t.size===0||t.has("run_pid_identity")||e.exec("ALTER TABLE crons ADD COLUMN run_pid_identity TEXT;")}E(Ze,"addCronRunPidIdentityColumn");function et(e){const t=b(e,"crons");t.size!==0&&(t.has("run_out_of_band")||e.exec("ALTER TABLE crons ADD COLUMN run_out_of_band INTEGER NOT NULL DEFAULT 0;"),t.has("queued")&&e.exec("ALTER TABLE crons DROP COLUMN queued;"))}E(et,"addCronOutOfBandColumn");function tt(e){e.exec(`
241
241
  CREATE TABLE IF NOT EXISTS warm_pool (
242
242
  node_id TEXT PRIMARY KEY REFERENCES nodes(node_id) ON DELETE CASCADE,
243
243
  recipe_key TEXT NOT NULL, -- frozen launch tuple this spare was minted for
244
244
  created TEXT NOT NULL -- ISO 8601, mint time (oldest spare claimed first)
245
245
  );
246
246
  CREATE INDEX IF NOT EXISTS idx_warm_pool_recipe ON warm_pool(recipe_key, created);
247
- `)}E(et,"addWarmPoolTable");function tt(e){const t=e.prepare("SELECT node_id, dir, root, request_id, work_kind, status, final_report, updated_at FROM consult_outbox").all();e.exec(`
247
+ `)}E(tt,"addWarmPoolTable");function nt(e){const t=e.prepare("SELECT node_id, dir, root, request_id, work_kind, status, final_report, updated_at FROM consult_outbox").all();e.exec(`
248
248
  CREATE TABLE consult_outbox_new (
249
249
  node_id TEXT PRIMARY KEY,
250
250
  ticket_node_id TEXT NOT NULL,
@@ -256,7 +256,7 @@ CREATE TABLE consult_outbox_new (
256
256
  );
257
257
  `);const n=e.prepare(`
258
258
  INSERT INTO consult_outbox_new (node_id, ticket_node_id, request_id, work_kind, status, final_report, updated_at)
259
- VALUES (?, ?, ?, ?, ?, ?, ?)`);let o=0;for(const T of t){const i=pe(T.dir);if(!(T.root===Y(T.root)&&T.dir===j(T.root,i))||!Oe(i)){o+=1;continue}n.run(T.node_id,i,T.request_id,T.work_kind,T.status,T.final_report,T.updated_at)}o>0&&console.warn(`[canvas migration v26] dropped ${o} consult_outbox row(s) whose legacy ticket path cannot safely map to a ticket node id`),e.exec(`
259
+ VALUES (?, ?, ?, ?, ?, ?, ?)`);let o=0;for(const T of t){const i=Re(T.dir);if(!(T.root===Y(T.root)&&T.dir===j(T.root,i))||!Ie(i)){o+=1;continue}n.run(T.node_id,i,T.request_id,T.work_kind,T.status,T.final_report,T.updated_at)}o>0&&console.warn(`[canvas migration v26] dropped ${o} consult_outbox row(s) whose legacy ticket path cannot safely map to a ticket node id`),e.exec(`
260
260
  DROP TABLE consult_outbox;
261
261
  ALTER TABLE consult_outbox_new RENAME TO consult_outbox;
262
262
 
@@ -265,7 +265,7 @@ CREATE INDEX IF NOT EXISTS idx_consult_outbox_human_work_status ON consult_outbo
265
265
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_ticket_status ON consult_outbox(ticket_node_id, work_kind, status);
266
266
  CREATE INDEX IF NOT EXISTS idx_consult_outbox_ticket_request_status ON consult_outbox(ticket_node_id, request_id, work_kind, status);
267
267
  CREATE UNIQUE INDEX IF NOT EXISTS idx_consult_outbox_visual_request ON consult_outbox(ticket_node_id, request_id, work_kind) WHERE work_kind = 'visual';
268
- `)}E(tt,"narrowHumanWorkOutbox");function nt(e){e.exec(`
268
+ `)}E(nt,"narrowHumanWorkOutbox");function Et(e){e.exec(`
269
269
  CREATE TABLE IF NOT EXISTS reviews (
270
270
  review_id TEXT PRIMARY KEY,
271
271
  idempotency_key TEXT NOT NULL UNIQUE,
@@ -309,7 +309,7 @@ CREATE INDEX IF NOT EXISTS idx_reviews_state ON reviews(state);
309
309
  CREATE INDEX IF NOT EXISTS idx_reviews_origin ON reviews(origin_node_id);
310
310
  CREATE INDEX IF NOT EXISTS idx_reviews_file ON reviews(file);
311
311
  CREATE INDEX IF NOT EXISTS idx_reviews_bridge ON reviews(bridge_node_id);
312
- `)}E(nt,"addReviewsTable");function Et(e){e.exec(`
312
+ `)}E(Et,"addReviewsTable");function ot(e){e.exec(`
313
313
  CREATE TABLE IF NOT EXISTS review_comments (
314
314
  comment_id TEXT PRIMARY KEY,
315
315
  review_id TEXT NOT NULL,
@@ -354,13 +354,13 @@ CREATE INDEX IF NOT EXISTS idx_review_comment_events_review_seq
354
354
  ON review_comment_events(review_id, seq);
355
355
  CREATE INDEX IF NOT EXISTS idx_review_comment_events_comment_seq
356
356
  ON review_comment_events(comment_id, seq);
357
- `)}E(Et,"addReviewCommentTables");function ot(e){e.exec(`
357
+ `)}E(ot,"addReviewCommentTables");function it(e){e.exec(`
358
358
  ALTER TABLE review_comments
359
359
  ADD COLUMN anchor_state TEXT NOT NULL DEFAULT 'live' CHECK (anchor_state IN ('live', 'detached'));
360
- `)}E(ot,"addReviewCommentAnchorState");function it(e){e.exec("DROP TABLE IF EXISTS consult_outbox")}E(it,"dropConsultOutbox");function st(e){e.exec("ALTER TABLE reviews ADD COLUMN submit_requested_at TEXT")}E(st,"addReviewSubmitRequested");function rt(e){e.exec(`
360
+ `)}E(it,"addReviewCommentAnchorState");function st(e){e.exec("DROP TABLE IF EXISTS consult_outbox")}E(st,"dropConsultOutbox");function rt(e){e.exec("ALTER TABLE reviews ADD COLUMN submit_requested_at TEXT")}E(rt,"addReviewSubmitRequested");function Tt(e){e.exec(`
361
361
  ALTER TABLE crons ADD COLUMN held INTEGER NOT NULL DEFAULT 0;
362
362
  ALTER TABLE crons ADD COLUMN last_poke_at TEXT;
363
- `)}E(rt,"addCronHeldColumns");function Tt(e){e.exec(`
363
+ `)}E(Tt,"addCronHeldColumns");function at(e){e.exec(`
364
364
  CREATE TABLE human_action_deliveries (
365
365
  request_id TEXT PRIMARY KEY,
366
366
  state TEXT NOT NULL,
@@ -378,7 +378,7 @@ CREATE TABLE human_action_deliveries (
378
378
  updated_at INTEGER NOT NULL
379
379
  );
380
380
  CREATE INDEX idx_human_action_deliveries_due ON human_action_deliveries(state, next_attempt_at);
381
- `)}E(Tt,"addHumanActionDeliveries");function at(e){const t=O(e);c(e,t,"pi_session_file","ALTER TABLE nodes ADD COLUMN pi_session_file TEXT;");for(const n of k(h(),{withFileTypes:!0}))if(n.isDirectory())try{const o=JSON.parse(M(x(n.name),"utf8"));typeof o.pi_session_file=="string"&&e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?").run(o.pi_session_file,n.name)}catch{}e.exec("CREATE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(at,"addNodeSessionFileIndex");function Z(e,t){const n=E(N=>{const L=Y(N);return U(L)?le(L):L},"canonical"),o=e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?");e.exec("DROP INDEX IF EXISTS idx_nodes_pi_session_file;");const T=e.prepare("SELECT node_id FROM nodes ORDER BY created ASC, node_id ASC").all();for(const{node_id:N}of T){const L=x(N);if(K(L)===null){o.run(null,N);continue}const l=fe(L,()=>{const r=K(L);if(r===null)throw new Error(`node ${N} session metadata changed during ownership migration`);if(typeof r.pi_session_file!="string")return null;const _=r.pi_session_file,d=n(_);return d!==_&&(r.pi_session_file=d,Xe(L,r)),d});o.run(l,N)}const i=e.prepare(`
381
+ `)}E(at,"addHumanActionDeliveries");function dt(e){const t=O(e);c(e,t,"pi_session_file","ALTER TABLE nodes ADD COLUMN pi_session_file TEXT;");for(const n of k(h(),{withFileTypes:!0}))if(n.isDirectory())try{const o=JSON.parse(M(x(n.name),"utf8"));typeof o.pi_session_file=="string"&&e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?").run(o.pi_session_file,n.name)}catch{}e.exec("CREATE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(dt,"addNodeSessionFileIndex");function Z(e,t){const n=E(N=>{const L=Y(N);return U(L)?ue(L):L},"canonical"),o=e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?");e.exec("DROP INDEX IF EXISTS idx_nodes_pi_session_file;");const T=e.prepare("SELECT node_id FROM nodes ORDER BY created ASC, node_id ASC").all();for(const{node_id:N}of T){const L=x(N);if(K(L)===null){o.run(null,N);continue}const l=Xe(L,()=>{const r=K(L);if(r===null)throw new Error(`node ${N} session metadata changed during ownership migration`);if(typeof r.pi_session_file!="string")return null;const _=r.pi_session_file,d=n(_);return d!==_&&(r.pi_session_file=d,Ue(L,r)),d});o.run(l,N)}const i=e.prepare(`
382
382
  SELECT pi_session_file
383
383
  FROM nodes
384
384
  WHERE pi_session_file IS NOT NULL
@@ -389,7 +389,7 @@ SELECT node_id
389
389
  FROM nodes
390
390
  WHERE pi_session_file = ?
391
391
  ORDER BY created ASC, node_id ASC
392
- `).all(N);for(const{node_id:l}of L.slice(1)){if(!q(x(l),_=>{const d=_.pi_session_file;if(typeof d!="string"||n(d)!==N)throw new Error(`node ${l} session metadata changed during ownership migration`);return _.pi_session_id=null,_.pi_session_file=null,!0}))throw new Error(`node ${l} session metadata changed during ownership migration`);a.run(l)}}e.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(Z,"reconcileNodeSessionFileOwners");function dt(e){Z(e,!0)}E(dt,"makeNodeSessionFileUnique");function _t(e){Z(e,!1)}E(_t,"repairNodeSessionFileUniqueIndex");function Nt(e){const t=O(e);c(e,t,"frozen_at","ALTER TABLE nodes ADD COLUMN frozen_at TEXT;"),c(e,t,"respawn_failures","ALTER TABLE nodes ADD COLUMN respawn_failures INTEGER NOT NULL DEFAULT 0;"),c(e,t,"respawn_not_before","ALTER TABLE nodes ADD COLUMN respawn_not_before TEXT;"),c(e,t,"launched_at","ALTER TABLE nodes ADD COLUMN launched_at TEXT;"),c(e,t,"last_settled_at","ALTER TABLE nodes ADD COLUMN last_settled_at TEXT;"),c(e,t,"terminal_reason","ALTER TABLE nodes ADD COLUMN terminal_reason TEXT;"),e.exec(`
392
+ `).all(N);for(const{node_id:l}of L.slice(1)){if(!q(x(l),_=>{const d=_.pi_session_file;if(typeof d!="string"||n(d)!==N)throw new Error(`node ${l} session metadata changed during ownership migration`);return _.pi_session_id=null,_.pi_session_file=null,!0}))throw new Error(`node ${l} session metadata changed during ownership migration`);a.run(l)}}e.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(Z,"reconcileNodeSessionFileOwners");function _t(e){Z(e,!0)}E(_t,"makeNodeSessionFileUnique");function Nt(e){Z(e,!1)}E(Nt,"repairNodeSessionFileUniqueIndex");function ct(e){const t=O(e);c(e,t,"frozen_at","ALTER TABLE nodes ADD COLUMN frozen_at TEXT;"),c(e,t,"respawn_failures","ALTER TABLE nodes ADD COLUMN respawn_failures INTEGER NOT NULL DEFAULT 0;"),c(e,t,"respawn_not_before","ALTER TABLE nodes ADD COLUMN respawn_not_before TEXT;"),c(e,t,"launched_at","ALTER TABLE nodes ADD COLUMN launched_at TEXT;"),c(e,t,"last_settled_at","ALTER TABLE nodes ADD COLUMN last_settled_at TEXT;"),c(e,t,"terminal_reason","ALTER TABLE nodes ADD COLUMN terminal_reason TEXT;"),e.exec(`
393
393
  UPDATE nodes SET terminal_reason = CASE
394
394
  WHEN status = 'done' AND final_report IS NOT NULL THEN 'finalized'
395
395
  WHEN status = 'done' AND intent = 'parked' THEN 'parked'
@@ -398,7 +398,7 @@ UPDATE nodes SET terminal_reason = CASE
398
398
  WHEN status = 'dead' THEN 'crashed'
399
399
  END
400
400
  WHERE status IN ('done','canceled','dead') AND terminal_reason IS NULL;
401
- `)}E(Nt,"addNodeLifecycleColumns");function ct(e){const t=O(e);c(e,t,"description","ALTER TABLE nodes ADD COLUMN description TEXT;"),c(e,t,"cycles","ALTER TABLE nodes ADD COLUMN cycles INTEGER;");const n=h();if(!U(n))return;const o=e.prepare("UPDATE nodes SET description = ?, cycles = ? WHERE node_id = ?");for(const T of k(n)){const i=x(T);if(!U(i))continue;let a;try{a=JSON.parse(M(i,"utf8"))}catch{continue}const N=typeof a.description=="string"?a.description:null,L=typeof a.cycles=="number"?a.cycles:null;o.run(N,L,T)}}E(ct,"addNodeLabelColumns");function Lt(e){const t=O(e);c(e,t,"outcome_kind","ALTER TABLE nodes ADD COLUMN outcome_kind TEXT;"),c(e,t,"outcome_reason","ALTER TABLE nodes ADD COLUMN outcome_reason TEXT;"),c(e,t,"outcome_at","ALTER TABLE nodes ADD COLUMN outcome_at TEXT;"),c(e,t,"outcome_revision","ALTER TABLE nodes ADD COLUMN outcome_revision INTEGER NOT NULL DEFAULT 0;"),c(e,t,"outcome_detail_json","ALTER TABLE nodes ADD COLUMN outcome_detail_json TEXT;"),c(e,t,"deadline_at","ALTER TABLE nodes ADD COLUMN deadline_at TEXT;"),e.exec(`
401
+ `)}E(ct,"addNodeLifecycleColumns");function Lt(e){const t=O(e);c(e,t,"description","ALTER TABLE nodes ADD COLUMN description TEXT;"),c(e,t,"cycles","ALTER TABLE nodes ADD COLUMN cycles INTEGER;");const n=h();if(!U(n))return;const o=e.prepare("UPDATE nodes SET description = ?, cycles = ? WHERE node_id = ?");for(const T of k(n)){const i=x(T);if(!U(i))continue;let a;try{a=JSON.parse(M(i,"utf8"))}catch{continue}const N=typeof a.description=="string"?a.description:null,L=typeof a.cycles=="number"?a.cycles:null;o.run(N,L,T)}}E(Lt,"addNodeLabelColumns");function lt(e){const t=O(e);c(e,t,"outcome_kind","ALTER TABLE nodes ADD COLUMN outcome_kind TEXT;"),c(e,t,"outcome_reason","ALTER TABLE nodes ADD COLUMN outcome_reason TEXT;"),c(e,t,"outcome_at","ALTER TABLE nodes ADD COLUMN outcome_at TEXT;"),c(e,t,"outcome_revision","ALTER TABLE nodes ADD COLUMN outcome_revision INTEGER NOT NULL DEFAULT 0;"),c(e,t,"outcome_detail_json","ALTER TABLE nodes ADD COLUMN outcome_detail_json TEXT;"),c(e,t,"deadline_at","ALTER TABLE nodes ADD COLUMN deadline_at TEXT;"),e.exec(`
402
402
  CREATE TABLE IF NOT EXISTS node_outcome_deliveries (
403
403
  node_id TEXT PRIMARY KEY,
404
404
  state TEXT NOT NULL,
@@ -431,17 +431,17 @@ UPDATE nodes SET outcome_kind='failure',
431
431
  outcome_reason=COALESCE(terminal_reason,'crashed'),
432
432
  outcome_at=COALESCE(finalized_at, created), outcome_revision=1
433
433
  WHERE final_report IS NULL AND status IN ('done','dead','canceled') AND outcome_at IS NULL;
434
- `)}E(Lt,"addNodeOutcomeAndDeadline");function lt(e){const t=O(e);c(e,t,"telemetry_tokens_in","ALTER TABLE nodes ADD COLUMN telemetry_tokens_in INTEGER;"),c(e,t,"telemetry_context_tokens","ALTER TABLE nodes ADD COLUMN telemetry_context_tokens INTEGER;"),c(e,t,"telemetry_last_activity","ALTER TABLE nodes ADD COLUMN telemetry_last_activity TEXT;"),c(e,t,"telemetry_updated_at","ALTER TABLE nodes ADD COLUMN telemetry_updated_at TEXT;");const n=e.prepare(`UPDATE nodes
434
+ `)}E(lt,"addNodeOutcomeAndDeadline");function ut(e){const t=O(e);c(e,t,"telemetry_tokens_in","ALTER TABLE nodes ADD COLUMN telemetry_tokens_in INTEGER;"),c(e,t,"telemetry_context_tokens","ALTER TABLE nodes ADD COLUMN telemetry_context_tokens INTEGER;"),c(e,t,"telemetry_last_activity","ALTER TABLE nodes ADD COLUMN telemetry_last_activity TEXT;"),c(e,t,"telemetry_updated_at","ALTER TABLE nodes ADD COLUMN telemetry_updated_at TEXT;");const n=e.prepare(`UPDATE nodes
435
435
  SET telemetry_tokens_in = ?, telemetry_context_tokens = ?,
436
436
  telemetry_last_activity = ?, telemetry_updated_at = ?
437
- WHERE node_id = ?`);for(const{node_id:o}of e.prepare("SELECT node_id FROM nodes").all()){const T=j(h(),o,"job","telemetry.json");if(U(T))try{const i=JSON.parse(M(T,"utf8")),a=typeof i.tokens_in=="number"&&Number.isFinite(i.tokens_in)?i.tokens_in:null,N=typeof i.context_tokens=="number"&&Number.isFinite(i.context_tokens)?i.context_tokens:null,L=typeof i.last_activity=="string"?i.last_activity:null,l=ue(T).mtime.toISOString();n.run(a,N,L,l,o)}catch{}}}E(lt,"addNodeTelemetryColumns");function ut(e){e.exec(`
437
+ WHERE node_id = ?`);for(const{node_id:o}of e.prepare("SELECT node_id FROM nodes").all()){const T=j(h(),o,"job","telemetry.json");if(U(T))try{const i=JSON.parse(M(T,"utf8")),a=typeof i.tokens_in=="number"&&Number.isFinite(i.tokens_in)?i.tokens_in:null,N=typeof i.context_tokens=="number"&&Number.isFinite(i.context_tokens)?i.context_tokens:null,L=typeof i.last_activity=="string"?i.last_activity:null,l=pe(T).mtime.toISOString();n.run(a,N,L,l,o)}catch{}}}E(ut,"addNodeTelemetryColumns");function pt(e){e.exec(`
438
438
  CREATE INDEX IF NOT EXISTS deliveries_external_due_order
439
439
  ON deliveries(state, next_attempt_at, created_at, delivery_id)
440
440
  WHERE destination_kind = 'external_action' AND canceled_at IS NULL;
441
441
  DROP INDEX IF EXISTS deliveries_external_due;
442
442
  CREATE INDEX IF NOT EXISTS idx_nodes_parent_created ON nodes(parent, created);
443
443
  CREATE INDEX IF NOT EXISTS idx_edges_type_created ON edges(type, created);
444
- `)}E(ut,"addRecurringLaneIndexes");function pt(e){_e(e)}E(pt,"projectLiveNodeState");function Rt(e){c(e,O(e),"scopes_json","ALTER TABLE nodes ADD COLUMN scopes_json TEXT;")}E(Rt,"addNodeScopes");function At(e){const t=O(e);c(e,t,"grantee","ALTER TABLE nodes ADD COLUMN grantee TEXT NOT NULL DEFAULT 'user:local';"),c(e,t,"sub","ALTER TABLE nodes ADD COLUMN sub TEXT;"),c(e,t,"grant_id","ALTER TABLE nodes ADD COLUMN grant_id TEXT;"),c(e,t,"client_id","ALTER TABLE nodes ADD COLUMN client_id TEXT;"),c(e,t,"metadata_json","ALTER TABLE nodes ADD COLUMN metadata_json TEXT;"),c(e,t,"run_id","ALTER TABLE nodes ADD COLUMN run_id TEXT;"),c(e,t,"event_cursor","ALTER TABLE nodes ADD COLUMN event_cursor INTEGER;"),c(e,t,"usage_json","ALTER TABLE nodes ADD COLUMN usage_json TEXT;"),c(e,t,"deleting_at","ALTER TABLE nodes ADD COLUMN deleting_at TEXT;"),e.exec(`
444
+ `)}E(pt,"addRecurringLaneIndexes");function Rt(e){_e(e)}E(Rt,"projectLiveNodeState");function At(e){c(e,O(e),"scopes_json","ALTER TABLE nodes ADD COLUMN scopes_json TEXT;")}E(At,"addNodeScopes");function Ot(e){const t=O(e);c(e,t,"grantee","ALTER TABLE nodes ADD COLUMN grantee TEXT NOT NULL DEFAULT 'user:local';"),c(e,t,"sub","ALTER TABLE nodes ADD COLUMN sub TEXT;"),c(e,t,"grant_id","ALTER TABLE nodes ADD COLUMN grant_id TEXT;"),c(e,t,"client_id","ALTER TABLE nodes ADD COLUMN client_id TEXT;"),c(e,t,"metadata_json","ALTER TABLE nodes ADD COLUMN metadata_json TEXT;"),c(e,t,"run_id","ALTER TABLE nodes ADD COLUMN run_id TEXT;"),c(e,t,"event_cursor","ALTER TABLE nodes ADD COLUMN event_cursor INTEGER;"),c(e,t,"usage_json","ALTER TABLE nodes ADD COLUMN usage_json TEXT;"),c(e,t,"deleting_at","ALTER TABLE nodes ADD COLUMN deleting_at TEXT;"),e.exec(`
445
445
  ALTER TABLE sessions ADD COLUMN event_offset INTEGER;
446
446
  CREATE INDEX idx_nodes_run_id ON nodes(run_id);
447
447
  -- Child nodes may be pruned while their root run and event history remain.
@@ -466,10 +466,10 @@ CREATE INDEX IF NOT EXISTS idx_edges_type_created ON edges(type, created);
466
466
  PRIMARY KEY (grantee, key)
467
467
  );
468
468
  CREATE INDEX idx_idempotency_keys_created_at ON idempotency_keys(created_at);
469
- `)}E(At,"addRunFoundation");function Ot(e){e.exec("ALTER TABLE nodes ADD COLUMN last_activity_at TEXT;"),e.exec(`UPDATE nodes SET last_activity_at = (
469
+ `)}E(Ot,"addRunFoundation");function It(e){e.exec("ALTER TABLE nodes ADD COLUMN last_activity_at TEXT;"),e.exec(`UPDATE nodes SET last_activity_at = (
470
470
  SELECT e.ts FROM run_events e WHERE e.run_id = nodes.node_id
471
471
  ORDER BY e.sequence_number DESC LIMIT 1
472
- ) WHERE run_id = node_id`)}E(Ot,"addRunLastActivity");function It(e){e.exec(`
472
+ ) WHERE run_id = node_id`)}E(It,"addRunLastActivity");function mt(e){e.exec(`
473
473
  CREATE TABLE structured_requests (
474
474
  request_id TEXT PRIMARY KEY,
475
475
  node_id TEXT REFERENCES nodes(node_id) ON DELETE CASCADE,
@@ -494,7 +494,7 @@ CREATE TABLE structured_requests (
494
494
  CREATE UNIQUE INDEX idx_structured_requests_one_pending_node ON structured_requests(node_id) WHERE state = 'pending';
495
495
  CREATE INDEX idx_structured_requests_expiry ON structured_requests(state, deadline_at);
496
496
  CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done_at) WHERE effects_done_at IS NULL;
497
- `)}E(It,"addStructuredRequests");function mt(e){e.exec(`
497
+ `)}E(mt,"addStructuredRequests");function ft(e){e.exec(`
498
498
  CREATE TABLE grants (
499
499
  id TEXT PRIMARY KEY, runtime TEXT NOT NULL, sub TEXT NOT NULL, grantee TEXT NOT NULL,
500
500
  rev INTEGER NOT NULL, scopes_json TEXT NOT NULL, resolved_scopes_json TEXT NOT NULL,
@@ -503,13 +503,13 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
503
503
  );
504
504
  CREATE UNIQUE INDEX idx_grants_grantee_sub ON grants(grantee, sub);
505
505
  CREATE TABLE runtime_state (key TEXT PRIMARY KEY, value TEXT NOT NULL);
506
- `)}E(mt,"addGrantMirror");function ft(e){e.exec("UPDATE nodes SET grantee = 'app:terminal' WHERE grantee = 'user:local';")}E(ft,"migrateTerminalGrantees");function Xt(e){const t={llm:"crtr:llm",act:"crtr:act",schedule:"crtr:schedule","memory:read":"crtr:memory:read:user","memory:write":"crtr:memory:rw:user"},n=e.prepare("SELECT node_id, scopes_json FROM nodes WHERE scopes_json IS NOT NULL").all(),o=e.prepare("UPDATE nodes SET scopes_json = ? WHERE node_id = ?");for(const T of n){const i=JSON.parse(T.scopes_json);if(!Array.isArray(i))throw new Error(`invalid launched scopes for node ${T.node_id}`);const a=[];for(const N of i){if(typeof N!="string")continue;const L=t[N]??N;try{ae(L),a.push(L)}catch(l){if(!(l instanceof TypeError))throw l}}o.run(JSON.stringify([...new Set(a)]),T.node_id)}}E(Xt,"migrateLaunchedScopes");function Ut(e){e.exec(`CREATE TABLE node_tokens (
506
+ `)}E(ft,"addGrantMirror");function Xt(e){e.exec("UPDATE nodes SET grantee = 'app:terminal' WHERE grantee = 'user:local';")}E(Xt,"migrateTerminalGrantees");function Ut(e){const t={llm:"crtr:llm",act:"crtr:act",schedule:"crtr:schedule","memory:read":"crtr:memory:read:user","memory:write":"crtr:memory:rw:user"},n=e.prepare("SELECT node_id, scopes_json FROM nodes WHERE scopes_json IS NOT NULL").all(),o=e.prepare("UPDATE nodes SET scopes_json = ? WHERE node_id = ?");for(const T of n){const i=JSON.parse(T.scopes_json);if(!Array.isArray(i))throw new Error(`invalid launched scopes for node ${T.node_id}`);const a=[];for(const N of i){if(typeof N!="string")continue;const L=t[N]??N;try{ae(L),a.push(L)}catch(l){if(!(l instanceof TypeError))throw l}}o.run(JSON.stringify([...new Set(a)]),T.node_id)}}E(Ut,"migrateLaunchedScopes");function Ct(e){e.exec(`CREATE TABLE node_tokens (
507
507
  broker_process_id TEXT PRIMARY KEY REFERENCES executions(execution_id) ON DELETE CASCADE,
508
508
  node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
509
509
  token_hash TEXT NOT NULL UNIQUE, grantee TEXT NOT NULL, uid INTEGER NOT NULL,
510
510
  sub TEXT NOT NULL, grant TEXT, client_id TEXT, scopes_json TEXT,
511
511
  issued_at TEXT NOT NULL, revoked_at TEXT
512
- );`)}E(Ut,"addNodeTokens");function C(e,t){return e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(t)!==void 0}E(C,"hasTable");function S(e,t,n){return e.prepare(`PRAGMA table_info(${t})`).all().some(o=>o.name===n)}E(S,"hasColumn");function ee(e){C(e,"memory_reads")||e.exec(`CREATE TABLE memory_reads (
512
+ );`)}E(Ct,"addNodeTokens");function C(e,t){return e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(t)!==void 0}E(C,"hasTable");function S(e,t,n){return e.prepare(`PRAGMA table_info(${t})`).all().some(o=>o.name===n)}E(S,"hasColumn");function ee(e){C(e,"memory_reads")||e.exec(`CREATE TABLE memory_reads (
513
513
  node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
514
514
  name TEXT NOT NULL,
515
515
  scope TEXT NOT NULL,
@@ -523,7 +523,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
523
523
  created TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ('active', 'retired'))
524
524
  );`)}E(ne,"addAppUsers");function Ee(e){S(e,"crons","grantee")||(e.exec("ALTER TABLE crons ADD COLUMN grantee TEXT NOT NULL DEFAULT 'app:terminal'"),e.exec(`UPDATE crons SET grantee = COALESCE(
525
525
  (SELECT COALESCE(nodes.grantee, 'app:terminal') FROM nodes WHERE nodes.node_id = crons.anchor_node),
526
- 'app:terminal') WHERE anchor_node IS NOT NULL`))}E(Ee,"addCronGrantee");function Ct(e){ee(e),te(e),ne(e),Ee(e)}E(Ct,"convergeSharedVersions");function St(e){(e.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'app_users'").get()?.sql??"").includes("'removed'")||e.exec(`CREATE TABLE app_users_new (
526
+ 'app:terminal') WHERE anchor_node IS NOT NULL`))}E(Ee,"addCronGrantee");function St(e){ee(e),te(e),ne(e),Ee(e)}E(St,"convergeSharedVersions");function Dt(e){(e.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'app_users'").get()?.sql??"").includes("'removed'")||e.exec(`CREATE TABLE app_users_new (
527
527
  uid INTEGER PRIMARY KEY, app TEXT NOT NULL,
528
528
  created TEXT NOT NULL, status TEXT NOT NULL CHECK (status IN ('active', 'removed')),
529
529
  removed_at TEXT
@@ -533,7 +533,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
533
533
  CASE status WHEN 'active' THEN NULL ELSE created END FROM app_users;
534
534
  DROP TABLE app_users;
535
535
  ALTER TABLE app_users_new RENAME TO app_users;
536
- CREATE UNIQUE INDEX idx_app_users_active_app ON app_users(app) WHERE status = 'active';`)}E(St,"appUsersRemoved");function oe(e){C(e,"objects")||(e.exec(`
536
+ CREATE UNIQUE INDEX idx_app_users_active_app ON app_users(app) WHERE status = 'active';`)}E(Dt,"appUsersRemoved");function oe(e){C(e,"objects")||(e.exec(`
537
537
  CREATE TABLE objects (
538
538
  rowid INTEGER PRIMARY KEY,
539
539
  id TEXT NOT NULL UNIQUE,
@@ -659,7 +659,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
659
659
  WHERE NOT EXISTS (SELECT 1 FROM identities i WHERE i.external_id = n.grantee AND i.scheme IN ('app', 'local-user'))`).all();for(const{grantee:i}of T){let a;if(i==="user:local")a={type:"person",scheme:"local-user",handle:"user"};else if(/^app:[a-z0-9][a-z0-9._-]*$/.test(i))a={type:"app",scheme:"app",handle:i.slice(4)};else throw new Error(`canvas objects migration: node grantee ${JSON.stringify(i)} is neither app:<name> nor user:local`);const{rowid:N}=n.get(`${Date.now().toString(36)}-${P(4).toString("hex")}`,a.type,a.handle,t);o.run(N,a.scheme,i)}e.exec(`INSERT INTO objects (id, type, kind, owner, privacy, name, preview, created_at)
660
660
  SELECT n.node_id, 'node', n.kind, i.object, 'public', n.name, '', n.created
661
661
  FROM nodes n JOIN identities i ON i.external_id = n.grantee AND i.scheme IN ('app', 'local-user')
662
- WHERE NOT EXISTS (SELECT 1 FROM objects o WHERE o.id = n.node_id)`)}E(ie,"copyNodesIntoObjects");function Dt(e){if(oe(e),!S(e,"nodes","name"))return;ie(e);const t=e.prepare("SELECT COUNT(*) AS n FROM nodes WHERE node_id NOT IN (SELECT id FROM objects)").get();if(t.n>0)throw new Error(`canvasObjectsCut: ${t.n} node(s) have no objects row`);e.exec(`
662
+ WHERE NOT EXISTS (SELECT 1 FROM objects o WHERE o.id = n.node_id)`)}E(ie,"copyNodesIntoObjects");function gt(e){if(oe(e),!S(e,"nodes","name"))return;ie(e);const t=e.prepare("SELECT COUNT(*) AS n FROM nodes WHERE node_id NOT IN (SELECT id FROM objects)").get();if(t.n>0)throw new Error(`canvasObjectsCut: ${t.n} node(s) have no objects row`);e.exec(`
663
663
  ALTER TABLE edges RENAME TO legacy_edges;
664
664
  CREATE TABLE edges (
665
665
  type TEXT NOT NULL CHECK (type IN ('acted-on','links-to')),
@@ -707,7 +707,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
707
707
  LEFT JOIN sessions s ON s.node_id = n.node_id AND s.unbound_at IS NULL
708
708
  LEFT JOIN node_faults f ON f.node_id = n.node_id AND f.active = 1;
709
709
  ANALYZE;
710
- `)}E(Dt,"canvasObjectsCut");function gt(e){e.exec(`CREATE TABLE IF NOT EXISTS uploads (
710
+ `)}E(gt,"canvasObjectsCut");function wt(e){e.exec(`CREATE TABLE IF NOT EXISTS uploads (
711
711
  upload_id TEXT PRIMARY KEY, grantee TEXT NOT NULL, name TEXT NOT NULL, media_type TEXT NOT NULL,
712
712
  size INTEGER NOT NULL, created_at TEXT NOT NULL, delete_pending_since TEXT
713
713
  );
@@ -723,7 +723,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
723
723
  url TEXT NOT NULL, created_by TEXT NOT NULL, created_at TEXT NOT NULL, expires_at TEXT,
724
724
  status TEXT NOT NULL CHECK (status IN ('on', 'off')), object_deleted_at TEXT
725
725
  );
726
- CREATE INDEX IF NOT EXISTS idx_shares_created_by ON shares(created_by);`)}E(gt,"addFileTransfer");function wt(e){e.exec(`CREATE TABLE IF NOT EXISTS daemon_actions (
726
+ CREATE INDEX IF NOT EXISTS idx_shares_created_by ON shares(created_by);`)}E(wt,"addFileTransfer");function yt(e){e.exec(`CREATE TABLE IF NOT EXISTS daemon_actions (
727
727
  action_id TEXT PRIMARY KEY,
728
728
  adapter_json TEXT NOT NULL,
729
729
  body_json TEXT,
@@ -762,7 +762,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
762
762
  DELETE FROM messages
763
763
  WHERE message_id IN (SELECT message_id FROM moved_actions WHERE message_id IS NOT NULL)
764
764
  AND NOT EXISTS (SELECT 1 FROM deliveries d WHERE d.message_id = messages.message_id);
765
- DROP TABLE moved_actions;`)}E(wt,"moveDaemonActions");function yt(e){B(e,61,()=>{if(!C(e,"objects"))return;const t=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n,n=e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%objects%'").all();for(const i of n)e.exec(`DROP VIEW "${i.name}"`);e.exec(`
765
+ DROP TABLE moved_actions;`)}E(yt,"moveDaemonActions");function vt(e){B(e,61,()=>{if(!C(e,"objects"))return;const t=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n,n=e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%objects%'").all();for(const i of n)e.exec(`DROP VIEW "${i.name}"`);e.exec(`
766
766
  CREATE TABLE objects_new (
767
767
  rowid INTEGER PRIMARY KEY,
768
768
  id TEXT NOT NULL UNIQUE,
@@ -783,10 +783,10 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
783
783
  CREATE UNIQUE INDEX objects_handle ON objects(type, name) WHERE type IN ('person','app','repo','profile');
784
784
  CREATE INDEX objects_owner_type ON objects(owner, type, kind);
785
785
  CREATE INDEX objects_type_kind ON objects(type, kind);
786
- `);for(const i of n)e.exec(i.sql);const o=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n;if(o!==t)throw new Error(`objects rebuild lost rows: expected ${t}, got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`objects rebuild left ${T.length} foreign-key violation(s)`)})}E(yt,"objectsWithoutTypeCheck");function vt(e){C(e,"deliveries")&&e.exec(`
786
+ `);for(const i of n)e.exec(i.sql);const o=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n;if(o!==t)throw new Error(`objects rebuild lost rows: expected ${t}, got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`objects rebuild left ${T.length} foreign-key violation(s)`)})}E(vt,"objectsWithoutTypeCheck");function ht(e){C(e,"deliveries")&&e.exec(`
787
787
  CREATE INDEX IF NOT EXISTS deliveries_destination ON deliveries(destination_id, wake, state, created_at);
788
788
  DROP INDEX IF EXISTS deliveries_node_inbox;
789
- `)}E(vt,"addDeliveriesDestinationIndex");function ht(e){e.exec(`
789
+ `)}E(ht,"addDeliveriesDestinationIndex");function xt(e){e.exec(`
790
790
  CREATE TABLE object_kinds (
791
791
  name TEXT PRIMARY KEY, owner INTEGER NOT NULL REFERENCES objects(rowid),
792
792
  description TEXT NOT NULL DEFAULT '', events_json TEXT NOT NULL,
@@ -809,14 +809,14 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
809
809
  DROP INDEX objects_doc_name;
810
810
  CREATE UNIQUE INDEX objects_named ON objects(owner, name)
811
811
  WHERE deleted_at IS NULL AND (type = 'document' OR instr(type, '.') > 0);
812
- `)}E(ht,"customObjectKinds");function xt(e){e.exec("CREATE INDEX IF NOT EXISTS revision_parents_parent ON revision_parents(parent);")}E(xt,"addRevisionParentsParentIndex");function Ft(e){C(e,"run_events")&&e.exec(`
812
+ `)}E(xt,"customObjectKinds");function Ft(e){e.exec("CREATE INDEX IF NOT EXISTS revision_parents_parent ON revision_parents(parent);")}E(Ft,"addRevisionParentsParentIndex");function Mt(e){C(e,"run_events")&&e.exec(`
813
813
  DELETE FROM run_events
814
814
  WHERE type IN ('node.thinking.delta', 'node.output_text.delta')
815
815
  AND EXISTS (SELECT 1 FROM run_events done
816
816
  WHERE done.run_id = run_events.run_id AND done.node_id = run_events.node_id
817
817
  AND done.type IN ('node.thinking.done', 'node.output_text.done', 'usage')
818
818
  AND done.sequence_number > run_events.sequence_number);
819
- `)}E(Ft,"dropSpentRunEventDeltas");function Mt(e){e.exec("CREATE INDEX IF NOT EXISTS idx_run_events_node_type ON run_events(run_id, node_id, type);")}E(Mt,"addRunEventsNodeTypeIndex");function kt(e){B(e,63,()=>{if(!C(e,"objects")||!C(e,"deliveries"))return;if(S(e,"objects","reception")||e.exec("ALTER TABLE objects ADD COLUMN reception INTEGER NOT NULL DEFAULT 0"),S(e,"objects","listen_json")||e.exec("ALTER TABLE objects ADD COLUMN listen_json TEXT"),e.exec(`UPDATE objects SET reception = CASE WHEN n.status IN ('active','idle') THEN 2 ELSE 1 END
819
+ `)}E(Mt,"dropSpentRunEventDeltas");function kt(e){e.exec("CREATE INDEX IF NOT EXISTS idx_run_events_node_type ON run_events(run_id, node_id, type);")}E(kt,"addRunEventsNodeTypeIndex");function jt(e){B(e,63,()=>{if(!C(e,"objects")||!C(e,"deliveries"))return;if(S(e,"objects","reception")||e.exec("ALTER TABLE objects ADD COLUMN reception INTEGER NOT NULL DEFAULT 0"),S(e,"objects","listen_json")||e.exec("ALTER TABLE objects ADD COLUMN listen_json TEXT"),e.exec(`UPDATE objects SET reception = CASE WHEN n.status IN ('active','idle') THEN 2 ELSE 1 END
820
820
  FROM nodes n WHERE n.node_id = objects.id`),S(e,"nodes","listen_default_json")){e.exec(`UPDATE objects SET listen_json = n.listen_default_json FROM nodes n
821
821
  WHERE n.node_id = objects.id AND n.listen_default_json IS NOT NULL`);const n=e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%nodes%'").all();for(const o of n)e.exec(`DROP VIEW "${o.name}"`);e.exec("ALTER TABLE nodes DROP COLUMN listen_default_json");for(const o of n)e.exec(o.sql)}if(e.exec(`
822
822
  DROP TRIGGER IF EXISTS nodes_reception_insert;
@@ -862,7 +862,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
862
862
  CREATE INDEX deliveries_handed_off ON deliveries(claim_owner) WHERE state = 'handed_off';
863
863
  CREATE INDEX deliveries_message ON deliveries(message_id);
864
864
  CREATE UNIQUE INDEX deliveries_idempotency ON deliveries(idempotency_key) WHERE idempotency_key IS NOT NULL;
865
- `);const o=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n;if(o!==n)throw new Error(`deliveries rebuild lost rows: expected ${n}, got ${o}`)}const t=e.prepare("PRAGMA foreign_key_check").all();if(t.length>0)throw new Error(`v64 left ${t.length} foreign-key violation(s)`)})}E(kt,"nodesOnObjectInterface");function jt(e){B(e,66,()=>{if(e.exec(`CREATE TABLE IF NOT EXISTS custom_objects (
865
+ `);const o=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n;if(o!==n)throw new Error(`deliveries rebuild lost rows: expected ${n}, got ${o}`)}const t=e.prepare("PRAGMA foreign_key_check").all();if(t.length>0)throw new Error(`v64 left ${t.length} foreign-key violation(s)`)})}E(jt,"nodesOnObjectInterface");function Ht(e){B(e,66,()=>{if(e.exec(`CREATE TABLE IF NOT EXISTS custom_objects (
866
866
  object INTEGER PRIMARY KEY REFERENCES objects(rowid) ON DELETE CASCADE,
867
867
  receiver_json TEXT,
868
868
  payload_json TEXT
@@ -916,7 +916,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
916
916
  CREATE INDEX deliveries_handed_off ON deliveries(claim_owner) WHERE state = 'handed_off';
917
917
  CREATE INDEX deliveries_message ON deliveries(message_id);
918
918
  CREATE UNIQUE INDEX deliveries_idempotency ON deliveries(idempotency_key) WHERE idempotency_key IS NOT NULL;
919
- `);for(const s of I)e.exec(s.sql);const R=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n;if(R!==p)throw new Error(`v67 deliveries rebuild lost rows: expected ${p}, got ${R}`)}const t=e.prepare("PRAGMA foreign_key_check").all();if(t.length)throw new Error(`v67 left ${t.length} foreign-key violation(s)`)})}E(jt,"outcomeActionsOnObjects");function Ht(e){e.exec(`
919
+ `);for(const s of I)e.exec(s.sql);const R=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n;if(R!==p)throw new Error(`v67 deliveries rebuild lost rows: expected ${p}, got ${R}`)}const t=e.prepare("PRAGMA foreign_key_check").all();if(t.length)throw new Error(`v67 left ${t.length} foreign-key violation(s)`)})}E(Ht,"outcomeActionsOnObjects");function Gt(e){e.exec(`
920
920
  CREATE TABLE IF NOT EXISTS create_requests (
921
921
  request_key TEXT PRIMARY KEY,
922
922
  node_id TEXT,
@@ -924,7 +924,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
924
924
  state TEXT NOT NULL DEFAULT 'reserved' CHECK (state IN ('reserved', 'warm_claimed', 'complete'))
925
925
  );
926
926
  CREATE INDEX IF NOT EXISTS idx_create_requests_expires ON create_requests(expires_at);
927
- `)}E(Ht,"addCreateRequests");function Gt(e){for(const[r,_]of[["sub","TEXT"],["grant_id","TEXT"],["scopes_json","TEXT"],["origin_run_id","TEXT"],["run_execution_id","TEXT"]])S(e,"crons",r)||e.exec(`ALTER TABLE crons ADD COLUMN ${r} ${_}`);const t=[],n=E(r=>e.prepare("SELECT id, sub, resolved_scopes_json FROM grants WHERE grantee = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r),"grantRow"),o=E(r=>e.prepare("SELECT grantee, sub, resolved_scopes_json FROM grants WHERE id = ?").get(r),"grantById"),T=E(r=>{try{const _=JSON.parse(r);return Array.isArray(_)?_.flatMap(d=>d&&d.mode==="always"&&typeof d.scope=="string"?[d.scope]:[]):[]}catch{return[]}},"snapshot"),i=E((r,_)=>{if(_===null)return null;const d=e.prepare("SELECT grantee, sub, grant_id, scopes_json, run_id FROM node_rows WHERE node_id = ?").get(_);if(d===void 0||d.grantee!==r)return null;const u=r==="app:terminal";let p=null;if(d.scopes_json!==null){let A;try{A=JSON.parse(d.scopes_json)}catch{return{pause:"bad_scopes"}}if(!Array.isArray(A)||!A.every(m=>typeof m=="string"))return{pause:"bad_scopes"};p=A}const I=u?n(r):void 0;let R=d.grant_id??I?.id??null;R===null&&!u&&d.sub!==null&&(R=e.prepare("SELECT id FROM grants WHERE grantee = ? AND sub = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r,d.sub)?.id??null);const s=R===null?void 0:o(R);return R!==null&&(s===void 0||s.grantee!==r||d.sub!==null&&s.sub!==d.sub)?{pause:"no_grant"}:R===null&&!u?{pause:"no_grant"}:(p===null&&!u&&(p=T(s.resolved_scopes_json)),{principal:{sub:d.sub??s?.sub??I?.sub??"user:local",grant_id:R,scopes:p,origin_run_id:d.run_id}})},"fromCreator"),a=E(r=>{const _=n(r);return r==="app:terminal"?{sub:_?.sub??"user:local",grant_id:_?.id??null,scopes:null,origin_run_id:null}:_===void 0?null:{sub:_.sub,grant_id:_.id,scopes:T(_.resolved_scopes_json),origin_run_id:null}},"fromGrantee"),N=e.prepare("SELECT cron_id, grantee, created_by, isolated, cwd FROM crons WHERE sub IS NULL").all(),L=e.prepare("UPDATE crons SET sub = ?, grant_id = ?, scopes_json = ?, origin_run_id = ? WHERE cron_id = ?"),l=new Map;for(const r of N){const _=i(r.grantee,r.created_by),d=_===null?a(r.grantee):"principal"in _?_.principal:null;if(d===null){const u=_!==null&&"pause"in _?_.pause:"no_grant";L.run("user:local",null,null,null,r.cron_id),e.prepare("UPDATE crons SET state = 'paused' WHERE cron_id = ?").run(r.cron_id),t.push({event:`cron.migrated.${u}`,fields:{cron_id:r.cron_id,grantee:r.grantee}})}else l.set(r.cron_id,d),L.run(d.sub,d.grant_id,d.scopes===null?null:JSON.stringify(d.scopes),d.origin_run_id,r.cron_id);if(r.isolated!==0){const u=j(Re(r.grantee).root,"crons",r.cron_id);e.prepare("UPDATE crons SET cwd = ? WHERE cron_id = ?").run(u,r.cron_id),t.push({event:"cron.migrated.isolated_cwd",fields:{cron_id:r.cron_id,old_cwd:r.cwd,cwd:u}})}}if(C(e,"daemon_actions")){const r=e.prepare("SELECT action_id, adapter_json FROM daemon_actions WHERE state IN ('pending', 'handed_off') AND json_extract(adapter_json, '$.adapter') = 'cron_spawn' AND json_extract(adapter_json, '$.principal') IS NULL").all();for(const _ of r){const d=JSON.parse(_.adapter_json),u=typeof d.cronId=="string"?d.cronId:null,p=u===null?void 0:e.prepare("SELECT grantee, sub, grant_id, scopes_json, origin_run_id, isolated, created_by FROM crons WHERE cron_id = ?").get(u);let I=null;if(p!==void 0&&!(p.grant_id===null&&p.grantee!=="app:terminal"))I={cron_id:u,grantee:p.grantee,sub:p.sub,grant_id:p.grant_id,scopes:p.scopes_json===null?null:JSON.parse(p.scopes_json),origin_run_id:p.origin_run_id,isolated:p.isolated!==0,creator:p.created_by};else if(p===void 0){const R=typeof d.parent=="string"?d.parent:null,s=R===null?void 0:e.prepare("SELECT grantee FROM node_rows WHERE node_id = ?").get(R),A=s===void 0?null:i(s.grantee,R),m=A===null||!("principal"in A)?null:A.principal;s!==void 0&&m!==null&&(I={cron_id:u,grantee:s.grantee,sub:m.sub,grant_id:m.grant_id,scopes:m.scopes,origin_run_id:m.origin_run_id,isolated:d.isolated===!0,creator:R})}if(I!==null)e.prepare("UPDATE daemon_actions SET adapter_json = ? WHERE action_id = ?").run(JSON.stringify({...d,principal:I}),_.action_id);else{const R=Date.now();e.prepare("UPDATE daemon_actions SET state = 'permanent_failed', failed_at = ?, updated_at = ?, claimed_at = NULL, claim_owner = NULL, next_attempt_at = NULL, last_failure_json = ? WHERE action_id = ?").run(R,R,JSON.stringify({kind:"grant_refused",message:"the cron has no derivable principal to authorize this birth"}),_.action_id),t.push({event:"cron.birth.refused",fields:{cron_id:u,action_id:_.action_id,reason:"grant_missing"}})}}}for(const{event:r,fields:_}of t)Ae({level:"warn",event:r,fields:_})}E(Gt,"addCronPrincipal");const F=[Ue,Ce,Se,De,ge,we,ye,he,ve,xe,Fe,Me,ke,J,je,J,He,Ge,be,Be,We,Qe,Ve,Ze,et,tt,nt,Et,ot,it,st,rt,Tt,at,Nt,dt,_t,ct,Lt,e=>{de(e),Ne(e),ce(e),Le(e)},ut,pt,lt,Rt,At,Ot,mt,Ut,ft,Xt,ee,te,ne,Ee,Ct,St,oe,Dt,Ie,gt,wt,yt,vt,kt,Mt,Ft,jt,xt,e=>e.exec(`
927
+ `)}E(Gt,"addCreateRequests");function bt(e){for(const[r,_]of[["sub","TEXT"],["grant_id","TEXT"],["scopes_json","TEXT"],["origin_run_id","TEXT"],["run_execution_id","TEXT"]])S(e,"crons",r)||e.exec(`ALTER TABLE crons ADD COLUMN ${r} ${_}`);const t=[],n=E(r=>e.prepare("SELECT id, sub, resolved_scopes_json FROM grants WHERE grantee = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r),"grantRow"),o=E(r=>e.prepare("SELECT grantee, sub, resolved_scopes_json FROM grants WHERE id = ?").get(r),"grantById"),T=E(r=>{try{const _=JSON.parse(r);return Array.isArray(_)?_.flatMap(d=>d&&d.mode==="always"&&typeof d.scope=="string"?[d.scope]:[]):[]}catch{return[]}},"snapshot"),i=E((r,_)=>{if(_===null)return null;const d=e.prepare("SELECT grantee, sub, grant_id, scopes_json, run_id FROM node_rows WHERE node_id = ?").get(_);if(d===void 0||d.grantee!==r)return null;const u=r==="app:terminal";let p=null;if(d.scopes_json!==null){let A;try{A=JSON.parse(d.scopes_json)}catch{return{pause:"bad_scopes"}}if(!Array.isArray(A)||!A.every(m=>typeof m=="string"))return{pause:"bad_scopes"};p=A}const I=u?n(r):void 0;let R=d.grant_id??I?.id??null;R===null&&!u&&d.sub!==null&&(R=e.prepare("SELECT id FROM grants WHERE grantee = ? AND sub = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r,d.sub)?.id??null);const s=R===null?void 0:o(R);return R!==null&&(s===void 0||s.grantee!==r||d.sub!==null&&s.sub!==d.sub)?{pause:"no_grant"}:R===null&&!u?{pause:"no_grant"}:(p===null&&!u&&(p=T(s.resolved_scopes_json)),{principal:{sub:d.sub??s?.sub??I?.sub??"user:local",grant_id:R,scopes:p,origin_run_id:d.run_id}})},"fromCreator"),a=E(r=>{const _=n(r);return r==="app:terminal"?{sub:_?.sub??"user:local",grant_id:_?.id??null,scopes:null,origin_run_id:null}:_===void 0?null:{sub:_.sub,grant_id:_.id,scopes:T(_.resolved_scopes_json),origin_run_id:null}},"fromGrantee"),N=e.prepare("SELECT cron_id, grantee, created_by, isolated, cwd FROM crons WHERE sub IS NULL").all(),L=e.prepare("UPDATE crons SET sub = ?, grant_id = ?, scopes_json = ?, origin_run_id = ? WHERE cron_id = ?"),l=new Map;for(const r of N){const _=i(r.grantee,r.created_by),d=_===null?a(r.grantee):"principal"in _?_.principal:null;if(d===null){const u=_!==null&&"pause"in _?_.pause:"no_grant";L.run("user:local",null,null,null,r.cron_id),e.prepare("UPDATE crons SET state = 'paused' WHERE cron_id = ?").run(r.cron_id),t.push({event:`cron.migrated.${u}`,fields:{cron_id:r.cron_id,grantee:r.grantee}})}else l.set(r.cron_id,d),L.run(d.sub,d.grant_id,d.scopes===null?null:JSON.stringify(d.scopes),d.origin_run_id,r.cron_id);if(r.isolated!==0){const u=j(Ae(r.grantee).root,"crons",r.cron_id);e.prepare("UPDATE crons SET cwd = ? WHERE cron_id = ?").run(u,r.cron_id),t.push({event:"cron.migrated.isolated_cwd",fields:{cron_id:r.cron_id,old_cwd:r.cwd,cwd:u}})}}if(C(e,"daemon_actions")){const r=e.prepare("SELECT action_id, adapter_json FROM daemon_actions WHERE state IN ('pending', 'handed_off') AND json_extract(adapter_json, '$.adapter') = 'cron_spawn' AND json_extract(adapter_json, '$.principal') IS NULL").all();for(const _ of r){const d=JSON.parse(_.adapter_json),u=typeof d.cronId=="string"?d.cronId:null,p=u===null?void 0:e.prepare("SELECT grantee, sub, grant_id, scopes_json, origin_run_id, isolated, created_by FROM crons WHERE cron_id = ?").get(u);let I=null;if(p!==void 0&&!(p.grant_id===null&&p.grantee!=="app:terminal"))I={cron_id:u,grantee:p.grantee,sub:p.sub,grant_id:p.grant_id,scopes:p.scopes_json===null?null:JSON.parse(p.scopes_json),origin_run_id:p.origin_run_id,isolated:p.isolated!==0,creator:p.created_by};else if(p===void 0){const R=typeof d.parent=="string"?d.parent:null,s=R===null?void 0:e.prepare("SELECT grantee FROM node_rows WHERE node_id = ?").get(R),A=s===void 0?null:i(s.grantee,R),m=A===null||!("principal"in A)?null:A.principal;s!==void 0&&m!==null&&(I={cron_id:u,grantee:s.grantee,sub:m.sub,grant_id:m.grant_id,scopes:m.scopes,origin_run_id:m.origin_run_id,isolated:d.isolated===!0,creator:R})}if(I!==null)e.prepare("UPDATE daemon_actions SET adapter_json = ? WHERE action_id = ?").run(JSON.stringify({...d,principal:I}),_.action_id);else{const R=Date.now();e.prepare("UPDATE daemon_actions SET state = 'permanent_failed', failed_at = ?, updated_at = ?, claimed_at = NULL, claim_owner = NULL, next_attempt_at = NULL, last_failure_json = ? WHERE action_id = ?").run(R,R,JSON.stringify({kind:"grant_refused",message:"the cron has no derivable principal to authorize this birth"}),_.action_id),t.push({event:"cron.birth.refused",fields:{cron_id:u,action_id:_.action_id,reason:"grant_missing"}})}}}for(const{event:r,fields:_}of t)Oe({level:"warn",event:r,fields:_})}E(bt,"addCronPrincipal");const F=[Ce,Se,De,ge,we,ye,ve,xe,he,Fe,Me,ke,je,J,He,J,Ge,be,Be,We,Pe,ze,Ze,et,tt,nt,Et,ot,it,st,rt,Tt,at,dt,ct,_t,Nt,Lt,lt,e=>{de(e),ce(e),Le(e),le(e)},pt,Rt,ut,At,Ot,It,ft,Ct,Xt,Ut,ee,te,ne,Ee,St,Dt,oe,gt,me,wt,yt,vt,ht,jt,kt,Mt,Ht,Ft,e=>e.exec(`
928
928
  CREATE TABLE audit_rows (
929
929
  id INTEGER PRIMARY KEY, request_id TEXT NOT NULL, time TEXT NOT NULL, grantee TEXT, sub TEXT,
930
930
  client_id TEXT, class TEXT, operation TEXT NOT NULL, scope_checked TEXT,
@@ -955,7 +955,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
955
955
  ALTER TABLE audit_rows ADD COLUMN question_id TEXT;
956
956
  ALTER TABLE provider_approvals ADD COLUMN call_shape TEXT;
957
957
  ALTER TABLE provider_approvals ADD COLUMN prepared_files TEXT;
958
- `),ht,e=>e.exec(`
958
+ `),xt,e=>e.exec(`
959
959
  CREATE INDEX idx_human_requests_page_source ON human_requests(
960
960
  CASE WHEN json_valid(specification_json) THEN json_extract(specification_json, '$.source.nodeId') END
961
961
  ) WHERE kind = 'page';
@@ -986,14 +986,14 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
986
986
  -- that registered a custom object fixes the run that object reads from.
987
987
  CREATE TABLE deleted_isolated_nodes (node_id TEXT PRIMARY KEY, run_id TEXT NOT NULL);
988
988
  ALTER TABLE custom_objects ADD COLUMN registered_by TEXT;
989
- `),It,Ht,e=>e.exec("ALTER TABLE grants ADD COLUMN dependencies_json TEXT NOT NULL DEFAULT '{}'"),e=>e.exec("ALTER TABLE grants ADD COLUMN run_notice_url TEXT"),e=>e.exec(`
989
+ `),mt,Gt,e=>e.exec("ALTER TABLE grants ADD COLUMN dependencies_json TEXT NOT NULL DEFAULT '{}'"),e=>e.exec("ALTER TABLE grants ADD COLUMN run_notice_url TEXT"),e=>e.exec(`
990
990
  CREATE TABLE usage (
991
991
  grantee TEXT NOT NULL, month TEXT NOT NULL, payer TEXT NOT NULL, source TEXT NOT NULL, served_model TEXT NOT NULL,
992
992
  input_tokens INTEGER NOT NULL DEFAULT 0, output_tokens INTEGER NOT NULL DEFAULT 0, cached_tokens INTEGER NOT NULL DEFAULT 0,
993
993
  usd_equivalent REAL,
994
994
  PRIMARY KEY (grantee, month, payer, source, served_model)
995
995
  );
996
- `),Gt,e=>e.exec("ALTER TABLE audit_rows ADD COLUMN via TEXT"),e=>e.exec(`
996
+ `),bt,e=>e.exec("ALTER TABLE audit_rows ADD COLUMN via TEXT"),e=>e.exec(`
997
997
  ALTER TABLE objects ADD COLUMN home_machine TEXT;
998
998
  CREATE TABLE peer_stubs (
999
999
  object INTEGER PRIMARY KEY REFERENCES objects(rowid) ON DELETE CASCADE,
@@ -1046,13 +1046,13 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
1046
1046
  CREATE UNIQUE INDEX objects_named ON objects(owner, name)
1047
1047
  WHERE deleted_at IS NULL AND home_machine IS NULL AND (type = 'document' OR instr(type, '.') > 0);
1048
1048
  CREATE UNIQUE INDEX objects_handle ON objects(type, name) WHERE home_machine IS NULL AND type IN ('person','app','repo','profile');
1049
- `),e=>e.exec("ALTER TABLE grants ADD COLUMN inference_endpoint_json TEXT"),e=>e.exec("ALTER TABLE nodes ADD COLUMN reply_at TEXT; ALTER TABLE nodes ADD COLUMN read_at TEXT;"),Bt,bt,e=>e.exec(`
1049
+ `),e=>e.exec("ALTER TABLE grants ADD COLUMN inference_endpoint_json TEXT"),e=>e.exec("ALTER TABLE nodes ADD COLUMN reply_at TEXT; ALTER TABLE nodes ADD COLUMN read_at TEXT;"),Wt,Bt,e=>e.exec(`
1050
1050
  CREATE TABLE IF NOT EXISTS unresolved_links (
1051
1051
  src INTEGER NOT NULL REFERENCES objects(rowid) ON DELETE CASCADE,
1052
1052
  name TEXT NOT NULL,
1053
1053
  PRIMARY KEY (src, name)
1054
1054
  ) WITHOUT ROWID;
1055
- `)];function bt(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'waits'").get()===void 0&&e.exec("CREATE TABLE waits (wait_id TEXT PRIMARY KEY, node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE, kind TEXT, target_id TEXT, generation INTEGER, created_at INTEGER, satisfied_at INTEGER)");const t=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;e.exec(`
1055
+ `),Ne];function Bt(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'waits'").get()===void 0&&e.exec("CREATE TABLE waits (wait_id TEXT PRIMARY KEY, node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE, kind TEXT, target_id TEXT, generation INTEGER, created_at INTEGER, satisfied_at INTEGER)");const t=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;e.exec(`
1056
1056
  CREATE TABLE waits_new (
1057
1057
  wait_id TEXT PRIMARY KEY,
1058
1058
  node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
@@ -1070,4 +1070,4 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
1070
1070
  CREATE UNIQUE INDEX waits_live_object ON waits(node_id, target_id) WHERE satisfied_at IS NULL AND kind = 'object';
1071
1071
  CREATE INDEX waits_target ON waits(target_id) WHERE satisfied_at IS NULL;
1072
1072
  CREATE INDEX waits_node ON waits(node_id);
1073
- `);const n=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;if(n!==t)throw new Error(`v96 waits rebuild lost rows: expected ${t}, got ${n}`)}E(bt,"addObjectWaits");function Bt(e){const t=O(e);for(const n of["waiting_for","waiting_for_generation"])t.has(n)&&e.exec(`ALTER TABLE nodes DROP COLUMN ${n}`)}E(Bt,"dropNodeWaitColumns");function B(e,t,n){const o=e.prepare("PRAGMA foreign_keys").get().foreign_keys;e.exec("PRAGMA foreign_keys = OFF;");try{e.exec("BEGIN IMMEDIATE");try{W(e)===t&&(n(),e.exec(`PRAGMA user_version = ${t+1}`)),e.exec("COMMIT")}catch(T){try{e.exec("ROLLBACK")}catch{}throw T}}finally{e.exec(`PRAGMA foreign_keys = ${o};`)}}E(B,"selfTransactionalMigration");const Wt=new Set([3,61,63,66]);function W(e){return e.prepare("PRAGMA user_version").get().user_version}E(W,"currentUserVersion");function se(e,t){F[t](e),e.exec(`PRAGMA user_version = ${t+1}`)}E(se,"applyMigration");function rn(e){const t=W(e);if(t>F.length)throw new Error(`unsupported canvas schema version ${t} (latest supported ${F.length})`);if(t===F.length)return;const n=e.prepare("PRAGMA busy_timeout").get().timeout;e.exec("PRAGMA busy_timeout = 60000;");try{Pt(e)}finally{e.exec(`PRAGMA busy_timeout = ${n};`)}}E(rn,"migrate");function Pt(e){for(;;){const t=W(e);if(t>=F.length)return;if(Wt.has(t)){if(e.isTransaction)throw new Error(`canvas migration v${t+1} requires autocommit`);F[t](e);continue}if(e.isTransaction){se(e,t);continue}e.exec("BEGIN IMMEDIATE");try{W(e)===t&&se(e,t),e.exec("COMMIT")}catch(n){try{e.exec("ROLLBACK")}catch{}throw n}}}E(Pt,"runPendingMigrations");export{F as MIGRATIONS,rn as migrate};
1073
+ `);const n=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;if(n!==t)throw new Error(`v96 waits rebuild lost rows: expected ${t}, got ${n}`)}E(Bt,"addObjectWaits");function Wt(e){const t=O(e);for(const n of["waiting_for","waiting_for_generation"])t.has(n)&&e.exec(`ALTER TABLE nodes DROP COLUMN ${n}`)}E(Wt,"dropNodeWaitColumns");function B(e,t,n){const o=e.prepare("PRAGMA foreign_keys").get().foreign_keys;e.exec("PRAGMA foreign_keys = OFF;");try{e.exec("BEGIN IMMEDIATE");try{W(e)===t&&(n(),e.exec(`PRAGMA user_version = ${t+1}`)),e.exec("COMMIT")}catch(T){try{e.exec("ROLLBACK")}catch{}throw T}}finally{e.exec(`PRAGMA foreign_keys = ${o};`)}}E(B,"selfTransactionalMigration");const Pt=new Set([3,61,63,66]);function W(e){return e.prepare("PRAGMA user_version").get().user_version}E(W,"currentUserVersion");function se(e,t){F[t](e),e.exec(`PRAGMA user_version = ${t+1}`)}E(se,"applyMigration");function Tn(e){const t=W(e);if(t>F.length)throw new Error(`unsupported canvas schema version ${t} (latest supported ${F.length})`);if(t===F.length)return;const n=e.prepare("PRAGMA busy_timeout").get().timeout;e.exec("PRAGMA busy_timeout = 60000;");try{Yt(e)}finally{e.exec(`PRAGMA busy_timeout = ${n};`)}}E(Tn,"migrate");function Yt(e){for(;;){const t=W(e);if(t>=F.length)return;if(Pt.has(t)){if(e.isTransaction)throw new Error(`canvas migration v${t+1} requires autocommit`);F[t](e);continue}if(e.isTransaction){se(e,t);continue}e.exec("BEGIN IMMEDIATE");try{W(e)===t&&se(e,t),e.exec("COMMIT")}catch(n){try{e.exec("ROLLBACK")}catch{}throw n}}}E(Yt,"runPendingMigrations");export{F as MIGRATIONS,Tn as migrate};
@@ -1 +1 @@
1
- var R=Object.defineProperty;var o=(t,e)=>R(t,"name",{value:e,configurable:!0});import{getNode as $,subscribersOf as y,subscriptionsOf as I}from"./index.js";import{faultSummary as C}from"./status-glyph.js";import{statusRank as S}from"./node-order.js";import{nodeGlyph as _,navLabel as G,shortId as O,tokensCell as T,activityCell as D,cycleBadge as W,askBadge as L,liveBelowBadge as M,truncate as N,fillBar as w,fillWidth as k,isAttached as H,BOLD as K,DIM as g,RESET as m,REVERSE as P,BG_ATTACHED as V}from"./nav-render.js";import{PI_MAX_WIDGET_LINES as dt,VIEWPORT_FALLBACK_ROWS as ft,ESC as ht,RESET as pt,BOLD as $t,DIM as mt,REVERSE as vt,BG_ATTACHED as Et,GREEN as xt,RED as gt,YELLOW as Bt,CYAN as bt,GRAY as St,nodeGlyph as wt,visibleWidth as kt,truncate as At,fillWidth as Rt,fillBar as yt,fmtTokens as It,tokensCell as Ct,activityCell as _t,cycleBadge as Gt,navLabel as Ot,shortId as Tt,askBadge as Dt,liveBelowBadge as Wt,isAttached as Lt,hasBrokerViewers as Mt,fetchAsksMap as Nt,graphWidgetBudget as Ht,GRAPH_HINT as Kt}from"./nav-render.js";function Y(t){try{return I(t)}catch{return[]}}o(Y,"subsOf");function F(t){try{return y(t)}catch{return[]}}o(F,"mgrsOf");function q(t){return F(t)[0]?.node_id}o(q,"managerOf");function X(t){return $(t)?.kind==="human"}o(X,"isHumanAsk");function v(t){return Y(t).map(e=>e.node_id).filter(e=>!X(e))}o(v,"convoChildIds");function rt(t){return v(t).filter(e=>{const s=$(e)?.status;return s==="active"||s==="idle"})}o(rt,"liveReports");function j(t){return v(t).length}o(j,"childCount");function z(t){let e=t;const s=new Set([e]);for(;;){const c=q(e);if(c===void 0||s.has(c))break;s.add(c),e=c}return e}o(z,"climbRoot");function ct(t){const e=[],s=new Set([t]),c=v(t);for(;c.length>0;){const l=c.shift();if(!s.has(l)){s.add(l),e.push(l);for(const u of v(l))s.has(u)||c.push(u)}}return e}o(ct,"subtreeIds");function J(t){if(t===null)return"";const e=j(t.node_id);return e>0?` ${g}\u2933${e}${m}`:""}o(J,"childBadge");function Q(t){return v(t).sort((e,s)=>S($(e)?.status)-S($(s)?.status))}o(Q,"sortedChildIds");function U(t,e){const s=new Set,c=new Map,l=new Set,u=o(n=>{const i=$(n)?.status==="active";if(l.has(n))return{active:i?1:0,reveal:i||n===e};l.add(n);let d=0,r=!1;for(const h of v(n)){const f=u(h);d+=f.active,f.reveal&&(r=!0)}return c.set(n,d),r&&s.add(n),{active:d+(i?1:0),reveal:r||i||n===e}},"visit");return u(t),{expand:s,activeBelow:c}}o(U,"computeSubtreeActivity");function Z(t,e){return U(t,e).expand}o(Z,"computeDefaultExpanded");function at(t,e,s){const c=z(t),l=s??Z(c,t),u=o(r=>e.userExpanded.has(r)?!1:e.userCollapsed.has(r)?!0:!l.has(r),"isFolded"),n=[],i=new Set,d=o((r,h,f,E)=>{if(i.has(r)){const a=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";n.push({id:r,hasKids:!1,isSelf:r===t,branch:h+a,cycle:!0,collapsed:!1});return}i.add(r);const p=Q(r),x=u(r),B=f?"":E?"\u2514\u2500 ":"\u251C\u2500 ";if(n.push({id:r,hasKids:p.length>0,isSelf:r===t,branch:h+B,cycle:!1,collapsed:x}),x)return;const b=f?"":h+(E?" ":"\u2502 ");for(let a=0;a<p.length;a++)d(p[a],b,!1,a===p.length-1)},"walk");return d(c,"",!0,!0),n}o(at,"buildGraphModel");function lt(t,e,s,c,l){const u=o((a,A)=>e?w(a,k(),P):A?w(a,k(),V):N(a),"wrap");if(t.cycle){const a=`${t.branch} ${g}\u21BA ${O(t.id)}${m}`;return u(a,!1)}const n=$(t.id),i=_(n),d=G(n,t.id),r=t.isSelf?`${K}${d}${m}`:d,h=`${g}${n?.kind??""}${m}`,f=`${g}${T(n)}${m}`,E=t.hasKids&&t.collapsed,p=!e&&E?`${g}\u25B8${m} `:" ",x=n?.fault??null,B=x!==null?` \xB7 ${C(x)}`:"",b=`${t.branch}${p}${i} ${r} ${h} ${f}${W(n)}${J(n)}${M(n,c)}${L(t.id,l)}${D(n)}${B}`;return u(b,H(t.id,n,s))}o(lt,"renderGraphRow");export{Et as BG_ATTACHED,$t as BOLD,bt as CYAN,mt as DIM,ht as ESC,Kt as GRAPH_HINT,St as GRAY,xt as GREEN,dt as PI_MAX_WIDGET_LINES,gt as RED,pt as RESET,vt as REVERSE,ft as VIEWPORT_FALLBACK_ROWS,Bt as YELLOW,_t as activityCell,Dt as askBadge,at as buildGraphModel,J as childBadge,j as childCount,z as climbRoot,Z as computeDefaultExpanded,U as computeSubtreeActivity,v as convoChildIds,Gt as cycleBadge,Nt as fetchAsksMap,yt as fillBar,Rt as fillWidth,It as fmtTokens,Ht as graphWidgetBudget,Mt as hasBrokerViewers,Lt as isAttached,X as isHumanAsk,Wt as liveBelowBadge,rt as liveReports,q as managerOf,Ot as navLabel,wt as nodeGlyph,lt as renderGraphRow,Tt as shortId,Q as sortedChildIds,ct as subtreeIds,Ct as tokensCell,At as truncate,kt as visibleWidth};
1
+ var A=Object.defineProperty;var o=(t,e)=>A(t,"name",{value:e,configurable:!0});import{getNode as x,subscribersOf as R,subscriptionsOf as y}from"./index.js";import{faultSummary as I}from"./status-glyph.js";import{statusRank as C}from"./node-order.js";import{nodeGlyph as _,navLabel as G,shortId as O,tokensCell as T,activityCell as D,cycleBadge as W,askBadge as L,liveBelowBadge as M,truncate as N,fillBar as b,fillWidth as S,isAttached as H,BOLD as K,DIM as g,RESET as $,REVERSE as P,BG_ATTACHED as V}from"./nav-render.js";import{PI_MAX_WIDGET_LINES as dt,VIEWPORT_FALLBACK_ROWS as ft,ESC as ht,RESET as pt,BOLD as $t,DIM as mt,REVERSE as vt,BG_ATTACHED as Et,GREEN as xt,RED as gt,YELLOW as kt,CYAN as Bt,GRAY as bt,nodeGlyph as St,visibleWidth as wt,truncate as At,fillWidth as Rt,fillBar as yt,fmtTokens as It,tokensCell as Ct,activityCell as _t,cycleBadge as Gt,navLabel as Ot,shortId as Tt,askBadge as Dt,liveBelowBadge as Wt,isAttached as Lt,hasBrokerViewers as Mt,fetchAsksMap as Nt,graphWidgetBudget as Ht,GRAPH_HINT as Kt}from"./nav-render.js";function Y(t){try{return y(t)}catch{return[]}}o(Y,"subsOf");function F(t){try{return R(t)}catch{return[]}}o(F,"mgrsOf");function q(t){return F(t)[0]?.node_id}o(q,"managerOf");function X(t){return x(t)?.kind==="human"}o(X,"isHumanAsk");function m(t){return Y(t).map(e=>e.node_id).filter(e=>!X(e))}o(m,"convoChildIds");function st(t){return m(t).filter(e=>{const r=x(e)?.status;return r==="active"||r==="idle"})}o(st,"liveReports");function j(t){return m(t).length}o(j,"childCount");function z(t){let e=t;const r=new Set([e]);for(;;){const c=q(e);if(c===void 0||r.has(c))break;r.add(c),e=c}return e}o(z,"climbRoot");function ct(t){const e=[],r=new Set([t]),c=m(t);for(;c.length>0;){const l=c.shift();if(!r.has(l)){r.add(l),e.push(l);for(const u of m(l))r.has(u)||c.push(u)}}return e}o(ct,"subtreeIds");function J(t){if(t===null)return"";const e=j(t.node_id);return e>0?` ${g}\u2933${e}${$}`:""}o(J,"childBadge");function Q(t){return m(t).map(e=>({cid:e,rank:C(x(e)?.status)})).sort((e,r)=>e.rank-r.rank).map(({cid:e})=>e)}o(Q,"sortedChildIds");function U(t,e){const r=new Set,c=new Map,l=new Set,u=o(n=>{const i=x(n)?.status==="active";if(l.has(n))return{active:i?1:0,reveal:i||n===e};l.add(n);let d=0,s=!1;for(const h of m(n)){const f=u(h);d+=f.active,f.reveal&&(s=!0)}return c.set(n,d),s&&r.add(n),{active:d+(i?1:0),reveal:s||i||n===e}},"visit");return u(t),{expand:r,activeBelow:c}}o(U,"computeSubtreeActivity");function Z(t,e){return U(t,e).expand}o(Z,"computeDefaultExpanded");function at(t,e,r){const c=z(t),l=r??Z(c,t),u=o(s=>e.userExpanded.has(s)?!1:e.userCollapsed.has(s)?!0:!l.has(s),"isFolded"),n=[],i=new Set,d=o((s,h,f,v)=>{if(i.has(s)){const a=f?"":v?"\u2514\u2500 ":"\u251C\u2500 ";n.push({id:s,hasKids:!1,isSelf:s===t,branch:h+a,cycle:!0,collapsed:!1});return}i.add(s);const p=Q(s),E=u(s),k=f?"":v?"\u2514\u2500 ":"\u251C\u2500 ";if(n.push({id:s,hasKids:p.length>0,isSelf:s===t,branch:h+k,cycle:!1,collapsed:E}),E)return;const B=f?"":h+(v?" ":"\u2502 ");for(let a=0;a<p.length;a++)d(p[a],B,!1,a===p.length-1)},"walk");return d(c,"",!0,!0),n}o(at,"buildGraphModel");function lt(t,e,r,c,l){const u=o((a,w)=>e?b(a,S(),P):w?b(a,S(),V):N(a),"wrap");if(t.cycle){const a=`${t.branch} ${g}\u21BA ${O(t.id)}${$}`;return u(a,!1)}const n=x(t.id),i=_(n),d=G(n,t.id),s=t.isSelf?`${K}${d}${$}`:d,h=`${g}${n?.kind??""}${$}`,f=`${g}${T(n)}${$}`,v=t.hasKids&&t.collapsed,p=!e&&v?`${g}\u25B8${$} `:" ",E=n?.fault??null,k=E!==null?` \xB7 ${I(E)}`:"",B=`${t.branch}${p}${i} ${s} ${h} ${f}${W(n)}${J(n)}${M(n,c)}${L(t.id,l)}${D(n)}${k}`;return u(B,H(t.id,n,r))}o(lt,"renderGraphRow");export{Et as BG_ATTACHED,$t as BOLD,Bt as CYAN,mt as DIM,ht as ESC,Kt as GRAPH_HINT,bt as GRAY,xt as GREEN,dt as PI_MAX_WIDGET_LINES,gt as RED,pt as RESET,vt as REVERSE,ft as VIEWPORT_FALLBACK_ROWS,kt as YELLOW,_t as activityCell,Dt as askBadge,at as buildGraphModel,J as childBadge,j as childCount,z as climbRoot,Z as computeDefaultExpanded,U as computeSubtreeActivity,m as convoChildIds,Gt as cycleBadge,Nt as fetchAsksMap,yt as fillBar,Rt as fillWidth,It as fmtTokens,Ht as graphWidgetBudget,Mt as hasBrokerViewers,Lt as isAttached,X as isHumanAsk,Wt as liveBelowBadge,st as liveReports,q as managerOf,Ot as navLabel,St as nodeGlyph,lt as renderGraphRow,Tt as shortId,Q as sortedChildIds,ct as subtreeIds,Ct as tokensCell,At as truncate,wt as visibleWidth};
@@ -15,6 +15,8 @@ export interface FaultRecordInput {
15
15
  }
16
16
  export interface StoredFault extends Fault {
17
17
  faultId: string;
18
+ /** The episode start (`since`) a fatal-fault notice was last published for; unset until one is sent. */
19
+ notifiedSince?: string;
18
20
  }
19
21
  export interface ProviderRetryEpisode {
20
22
  state: 'pending' | 'admitted' | 'invalidated';
@@ -58,6 +60,12 @@ export declare function readInterruptedTurn(nodeId: string): {
58
60
  * exists before the kickoff is admitted. */
59
61
  export declare function hasAdmittedTurn(nodeId: string): boolean;
60
62
  export declare function recordFault(nodeId: string, input: FaultRecordInput): StoredFault | null;
63
+ /** Record that the fatal-fault notice for this fault row's current episode has been published. Callers run it in the write that publishes. */
64
+ export declare function markFaultNotified(faultId: string): boolean;
65
+ /** Nodes whose active fatal provider fault has not been announced yet, read from the fault table so a node with no live broker is still found. */
66
+ export declare function listUnnotifiedFatalFaultNodes(): string[];
67
+ /** The daemon registers the one function that publishes a fatal provider fault's notice. Every clear of an unannounced fatal fault runs it first, so no clear can drop a notice. */
68
+ export declare function setFatalFaultAnnouncer(announce: ((nodeId: string) => void) | null): void;
61
69
  export declare function clearFault(nodeId: string, opts?: {
62
70
  link?: FaultLink;
63
71
  preserveEpisode?: boolean;
@@ -97,4 +105,9 @@ export interface PendingProviderRetry {
97
105
  export declare function listPendingProviderRetries(): PendingProviderRetry[];
98
106
  export declare function beginBootFaultAttempt(nodeId: string): BootFaultAttempt;
99
107
  /** Import legacy witness and recovery files inside the parent's one shared consolidation transaction. */
108
+ /** v98 — `notified_since` on a fault row: the episode start its fatal notice was published for.
109
+ * No backfill: a fatal fault already active at upgrade reads as unannounced and is announced once more,
110
+ * because the old in-memory record cannot be rebuilt and a backfill could silence a fault never announced.
111
+ * Guarded like v95: a fixture that starts past v39 never created the table. */
112
+ export declare function addFaultNotifiedSince(db: DatabaseSync): void;
100
113
  export declare function migrateRecoveryWitnesses(db: DatabaseSync): void;