@north-light/cli 0.3.535 → 0.3.536

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 (43) hide show
  1. package/dist/api/client.d.ts +3 -0
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/recovery.d.ts +2 -1
  6. package/dist/clients/attach/viewer.js +406 -406
  7. package/dist/commands/api-client.js +3 -3
  8. package/dist/core/canvas/canvas.d.ts +10 -0
  9. package/dist/core/canvas/canvas.js +20 -20
  10. package/dist/core/canvas/crons.d.ts +4 -2
  11. package/dist/core/canvas/crons.js +1 -1
  12. package/dist/core/canvas/paths.d.ts +5 -0
  13. package/dist/core/canvas/paths.js +1 -1
  14. package/dist/core/canvas/recovery.d.ts +7 -0
  15. package/dist/core/canvas/recovery.js +2 -2
  16. package/dist/core/feed/feed.js +3 -3
  17. package/dist/core/feed/messages.d.ts +6 -0
  18. package/dist/core/feed/messages.js +5 -5
  19. package/dist/core/graph/kinds/node.js +5 -5
  20. package/dist/core/providers/mint.d.ts +2 -0
  21. package/dist/core/providers/mint.js +1 -1
  22. package/dist/core/runtime/broker/cli-relay.js +1 -1
  23. package/dist/core/runtime/broker/fault-retry.d.ts +12 -0
  24. package/dist/core/runtime/broker/fault-retry.js +1 -1
  25. package/dist/core/runtime/broker/run-turn-end.d.ts +3 -2
  26. package/dist/core/runtime/broker/run-turn-end.js +1 -1
  27. package/dist/core/runtime/lifecycle.d.ts +4 -0
  28. package/dist/core/runtime/lifecycle.js +2 -2
  29. package/dist/core/runtime/nodes.js +1 -1
  30. package/dist/core/runtime/revive.d.ts +1 -1
  31. package/dist/core/runtime/revive.js +1 -1
  32. package/dist/core/worktree-mutation-async.d.ts +10 -0
  33. package/dist/core/worktree-mutation-async.js +5 -5
  34. package/dist/core/worktree-sweep.js +6 -6
  35. package/dist/core/worktree.d.ts +1 -0
  36. package/dist/core/worktree.js +1 -1
  37. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  38. package/dist/daemon/api/handlers/messages.js +2 -2
  39. package/dist/daemon/messaging/node-message.js +1 -1
  40. package/dist/daemon/peer/forward.js +1 -1
  41. package/package.json +2 -2
  42. package/packages/crouter-identity/package.json +1 -1
  43. package/runtime.lock.json +12 -12
@@ -1,4 +1,4 @@
1
- var b=Object.defineProperty;var a=(r,t)=>b(r,"name",{value:t,configurable:!0});import{closeSync as _,fstatSync as S,openSync as g,readSync as v}from"node:fs";import{join as y}from"node:path";import{gunzipSync as C}from"node:zlib";import{ApiError as l}from"../api/index.js";import{localClient as d}from"../api/node-transport.js";import{apiErrorToCliError as N}from"../core/io.js";import{autostartDisabled as h,daemonAutostartStartupFailure as M,ensureDaemon as T}from"../daemon/manage.js";import{DAEMON_STARTUP_WINDOW_MS as p}from"../daemon/startup-policy.js";import{readState as A}from"../core/config.js";import{resolveRemoteCanvasTarget as O}from"../core/remote-canvas-target.js";import{RemoteCanvasSource as R}from"../core/canvas/remote-canvas-source.js";import{crtrHome as I}from"../core/canvas/paths.js";import{envTestNodeSocketWindowMs as x,isSandboxedNode as D}from"../shared/env.js";import{ownerOnly as F}from"../core/errors.js";function u(r){return{...r,fault:r.fault??null}}a(u,"withRowFault");function E(r,t){throw r instanceof l?N(r,t):r}a(E,"rethrowAsCliError");async function tt(r){try{return await m().getNode(r)}catch(t){if(t instanceof l&&t.status===404)return null;E(t)}}a(tt,"getNodeOrNull");const L=4096,k=20;function W(){let r;try{r=g(y(I(),"crtrd.log"),"r");const{size:t}=S(r),s=Math.max(0,t-L),n=t-s;if(n<=0)return;const e=Buffer.alloc(n);v(r,e,0,n,s);const o=e.toString("utf8").split(`
2
- `).filter(c=>c.trim()!=="").slice(-k).join(`
1
+ var y=Object.defineProperty;var a=(r,t)=>y(r,"name",{value:t,configurable:!0});import{closeSync as g,existsSync as v,fstatSync as C,openSync as N,readFileSync as m,readSync as R}from"node:fs";import{dirname as T,join as l}from"node:path";import{gunzipSync as E}from"node:zlib";import{ApiError as u}from"../api/index.js";import{localClient as f}from"../api/node-transport.js";import{apiErrorToCliError as p}from"../core/io.js";import{autostartDisabled as w,daemonAutostartStartupFailure as A,ensureDaemon as M}from"../daemon/manage.js";import{DAEMON_STARTUP_WINDOW_MS as b}from"../daemon/startup-policy.js";import{readState as O}from"../core/config.js";import{resolveRemoteCanvasTarget as I}from"../core/remote-canvas-target.js";import{RemoteCanvasSource as x}from"../core/canvas/remote-canvas-source.js";import{BROKER_RELEASED_MARKER as D,BROKER_RELAY_GENERATION as F,crtrHome as k}from"../core/canvas/paths.js";import{envTestNodeSocketWindowMs as L,isSandboxedNode as B}from"../shared/env.js";import{ownerOnly as W}from"../core/errors.js";function d(r){return{...r,fault:r.fault??null}}a(d,"withRowFault");function K(r,t){throw r instanceof u?p(r,t):r}a(K,"rethrowAsCliError");async function it(r){try{return await _().getNode(r)}catch(t){if(t instanceof u&&t.status===404)return null;K(t)}}a(it,"getNodeOrNull");const P=4096,j=20;function G(){let r;try{r=N(l(k(),"crtrd.log"),"r");const{size:t}=C(r),s=Math.max(0,t-P),n=t-s;if(n<=0)return;const e=Buffer.alloc(n);R(r,e,0,n,s);const o=e.toString("utf8").split(`
2
+ `).filter(c=>c.trim()!=="").slice(-j).join(`
3
3
  `).trim();return o===""?void 0:`crtrd.log (tail):
4
- ${o}`}catch{return}finally{if(r!==void 0)try{_(r)}catch{}}}a(W,"readColdStartDiagnostic");function m(r){return process.env.CRTR_API_SOCKET?d({autostart:!1,coldStartPollWindowMs:(h()?x():void 0)??p,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):h()?d({autostart:!1,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):d({...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{},onColdSocket:a(async()=>{T()},"onColdSocket"),coldStartDiagnostic:W,coldStartFailure:M,coldStartPollWindowMs:p})}a(m,"cliClient");const P=2e3;class w{static{a(this,"ApiCanvasSource")}client;rosterCache=null;rosterInFlight=null;constructor(t=m()){this.client=t}async roster(){const t=Date.now();return this.rosterCache!==null&&t-this.rosterCache.at<P?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(s=>{const n={snapshot:s,subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i={node_id:e.to_id,active:e.active,created:e.created},o={node_id:e.from_id,active:e.active,created:e.created},c=n.subscriptions.get(e.from_id);c===void 0?n.subscriptions.set(e.from_id,[i]):c.push(i);const f=n.subscribers.get(e.to_id);f===void 0?n.subscribers.set(e.to_id,[o]):f.push(o)}return this.rosterCache={at:Date.now(),index:n},n}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(t){try{return await t()}catch(s){if(s instanceof l&&s.status===404)return null;throw s}}async getNode(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async getRow(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:u(s)}async listNodes(t){const s=t?.status,n=t?.under===void 0?{}:{under:t.under,under_inclusive:!0};let e;if(Array.isArray(s)){const i=new Set(s);e=(await this.client.listNodes(n)).filter(c=>i.has(c.status))}else e=await this.client.listNodes({...s!==void 0?{status:s}:{},...n});return e.map(i=>u(i))}async browseSnapshot(){const t=await this.client.canvasBrowseCompressed(),s=JSON.parse(C(t).toString("utf8")),n={subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i=n.subscriptions.get(e.from_id)??[];i.push({node_id:e.to_id,active:e.active,created:e.created}),n.subscriptions.set(e.from_id,i);const o=n.subscribers.get(e.to_id)??[];o.push({node_id:e.from_id,active:e.active,created:e.created}),n.subscribers.set(e.to_id,o)}return this.rosterCache={at:Date.now(),index:n},s.nodes.map(e=>u(e))}async panelRoster(){const t=await this.roster();return t.snapshot!==void 0?t.snapshot:(this.rosterCache=null,(await this.roster()).snapshot)}async subscriptionsOf(t){return this.roster().then(s=>s.subscriptions.get(t)??[])}async subscribersOf(t){return this.roster().then(s=>s.subscribers.get(t)??[])}async view(t){const s=new Set([t]),n=[],e=(await this.subscriptionsOf(t)).map(i=>i.node_id);for(;e.length>0;){const i=e.shift();if(!s.has(i)){s.add(i),n.push(i);for(const o of await this.subscriptionsOf(i))s.has(o.node_id)||e.push(o.node_id)}}return n}async ticketCountsForNodes(t){return(await this.client.attentionCounts([...t])).counts}async ticketCountsForView(t){return this.ticketCountsForNodes([t,...await this.view(t)])}async newestReport(t){return(await this.client.getReports(t,{limit:1}))[0]??null}async hasActiveLiveSubscription(t){const s=(await this.subscriptionsOf(t)).filter(n=>n.active);for(const n of s){const e=await this.getRow(n.node_id);if(e&&(e.status==="active"||e.status==="idle"))return!0}return!1}}function et(r,t=D()){const s=r?.scope??"user";if(t){if(r?.canvasName!==void 0)throw F("--canvas selects the person's remote canvas targets, which an app's node cannot reach","Omit --canvas; this node reads its own runtime's canvas.");return new w}const n=r?.canvasName??A(s).activeCanvas??null;if(!n)return new w;const{previewEndpoint:e,relayToken:i}=O(n,s);return new R(e,i)}a(et,"cliCanvasSource");export{w as ApiCanvasSource,L as COLD_START_DIAGNOSTIC_TAIL_BYTES,et as cliCanvasSource,m as cliClient,tt as getNodeOrNull,W as readColdStartDiagnostic,E as rethrowAsCliError};
4
+ ${o}`}catch{return}finally{if(r!==void 0)try{g(r)}catch{}}}a(G,"readColdStartDiagnostic");function _(r){const t=process.env.CRTR_API_SOCKET;if(t){const s=a(()=>{if(!v(t))try{const e=T(t),i=m(l(e,D),"utf8"),o=m(l(e,F),"utf8");if(i===o&&i!=="")return new u(503,"broker_released","This node's broker has been released, so crtr commands from its background jobs are not available.")}catch(e){if(e.code!=="ENOENT")throw e}},"availabilityFailure"),n=s();if(n!==void 0)throw p(n,"Run the command from the node's own turn instead.");return f({autostart:!1,availabilityFailure:s,coldStartPollWindowMs:(w()?L():void 0)??b,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}})}return w()?f({autostart:!1,...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{}}):f({...r?.timeoutMs!==void 0?{timeoutMs:r.timeoutMs}:{},onColdSocket:a(async()=>{M()},"onColdSocket"),coldStartDiagnostic:G,coldStartFailure:A,coldStartPollWindowMs:b})}a(_,"cliClient");const z=2e3;class S{static{a(this,"ApiCanvasSource")}client;rosterCache=null;rosterInFlight=null;constructor(t=_()){this.client=t}async roster(){const t=Date.now();return this.rosterCache!==null&&t-this.rosterCache.at<z?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(s=>{const n={snapshot:s,subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i={node_id:e.to_id,active:e.active,created:e.created},o={node_id:e.from_id,active:e.active,created:e.created},c=n.subscriptions.get(e.from_id);c===void 0?n.subscriptions.set(e.from_id,[i]):c.push(i);const h=n.subscribers.get(e.to_id);h===void 0?n.subscribers.set(e.to_id,[o]):h.push(o)}return this.rosterCache={at:Date.now(),index:n},n}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(t){try{return await t()}catch(s){if(s instanceof u&&s.status===404)return null;throw s}}async getNode(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:d(s)}async getRow(t){const s=await this.orNull(()=>this.client.getNode(t));return s===null?null:d(s)}async listNodes(t){const s=t?.status,n=t?.under===void 0?{}:{under:t.under,under_inclusive:!0};let e;if(Array.isArray(s)){const i=new Set(s);e=(await this.client.listNodes(n)).filter(c=>i.has(c.status))}else e=await this.client.listNodes({...s!==void 0?{status:s}:{},...n});return e.map(i=>d(i))}async browseSnapshot(){const t=await this.client.canvasBrowseCompressed(),s=JSON.parse(E(t).toString("utf8")),n={subscriptions:new Map,subscribers:new Map};for(const e of s.edges){const i=n.subscriptions.get(e.from_id)??[];i.push({node_id:e.to_id,active:e.active,created:e.created}),n.subscriptions.set(e.from_id,i);const o=n.subscribers.get(e.to_id)??[];o.push({node_id:e.from_id,active:e.active,created:e.created}),n.subscribers.set(e.to_id,o)}return this.rosterCache={at:Date.now(),index:n},s.nodes.map(e=>d(e))}async panelRoster(){const t=await this.roster();return t.snapshot!==void 0?t.snapshot:(this.rosterCache=null,(await this.roster()).snapshot)}async subscriptionsOf(t){return this.roster().then(s=>s.subscriptions.get(t)??[])}async subscribersOf(t){return this.roster().then(s=>s.subscribers.get(t)??[])}async view(t){const s=new Set([t]),n=[],e=(await this.subscriptionsOf(t)).map(i=>i.node_id);for(;e.length>0;){const i=e.shift();if(!s.has(i)){s.add(i),n.push(i);for(const o of await this.subscriptionsOf(i))s.has(o.node_id)||e.push(o.node_id)}}return n}async ticketCountsForNodes(t){return(await this.client.attentionCounts([...t])).counts}async ticketCountsForView(t){return this.ticketCountsForNodes([t,...await this.view(t)])}async newestReport(t){return(await this.client.getReports(t,{limit:1}))[0]??null}async hasActiveLiveSubscription(t){const s=(await this.subscriptionsOf(t)).filter(n=>n.active);for(const n of s){const e=await this.getRow(n.node_id);if(e&&(e.status==="active"||e.status==="idle"))return!0}return!1}}function ot(r,t=B()){const s=r?.scope??"user";if(t){if(r?.canvasName!==void 0)throw W("--canvas selects the person's remote canvas targets, which an app's node cannot reach","Omit --canvas; this node reads its own runtime's canvas.");return new S}const n=r?.canvasName??O(s).activeCanvas??null;if(!n)return new S;const{previewEndpoint:e,relayToken:i}=I(n,s);return new x(e,i)}a(ot,"cliCanvasSource");export{S as ApiCanvasSource,P as COLD_START_DIAGNOSTIC_TAIL_BYTES,ot as cliCanvasSource,_ as cliClient,it as getNodeOrNull,G as readColdStartDiagnostic,K as rethrowAsCliError};
@@ -183,6 +183,16 @@ export declare function listNodesForSupervision(): Promise<NodeRow[]>;
183
183
  * canceled, dead, terminal-lifecycle and deleting nodes are never reopened by mail.
184
184
  * The SQL form of `isParkedResident` (runtime/lifecycle.ts), which must change with it; `n` is a `nodes` row. */
185
185
  export declare const PARKED_RESIDENT_SQL: (n: string) => string;
186
+ /** A node the runtime can still bring back to life, so its cwd must keep existing: a live row
187
+ * (`active`/`idle`), a parked resident the lifecycle tick reopens when wake mail arrives
188
+ * (`PARKED_RESIDENT_SQL`), or a terminal row with no final latch that still carries a frozen
189
+ * mark, which the tick thaws (`node-lifecycle/tick.ts` `classifyRow`). `n` is a `nodes` row. */
190
+ export declare const RESUMABLE_NODE_SQL: (n: string) => string;
191
+ /** Every resumable node (`RESUMABLE_NODE_SQL`) other than `ownerId`, with the cwd it will run in. */
192
+ export declare function resumableNodeCwds(ownerId: string): Promise<Array<{
193
+ node_id: string;
194
+ cwd: string;
195
+ }>>;
186
196
  /** Parked residents with unseen wake mail (`UNSEEN_WAKE_MAIL_SQL`), which nothing else
187
197
  * launches: the lifecycle tick reopens them. Each parked resident seeks its own mail
188
198
  * through `deliveries_destination`. */
@@ -1,13 +1,13 @@
1
- var Z=Object.defineProperty;var i=(e,n)=>Z(e,"name",{value:n,configurable:!0});import{envNodeId as U}from"../../shared/env.js";import{rmdirSync as ee,rmSync as ne,statSync as te}from"node:fs";import{dirname as ae,join as I,resolve as ie}from"node:path";import{removeTreeBeneath as j}from"../spaces/open-beneath.js";import{emitEvent as oe}from"../events/emit.js";import{withCanvasWrite as p,openDb as s}from"./db.js";import{conversationStore as re,ConversationNotFoundError as se}from"../conversation-store/index.js";import{hasUnseenWakeMail as de,UNSEEN_WAKE_MAIL_SQL as ue}from"./deliveries.js";import{isAppRun as W}from"./app-run.js";import{registerOutcomeAction as b}from"./outcome-actions.js";import{publish as le}from"../graph/events.js";import{nodeObject as ce}from"../graph/objects.js";import{findNodeBySessionFileSql as _e}from"./sessions.js";import{hydrateFault as pe}from"./recovery.js";import{hasUnreconciledWorktree as fe,openWorktree as Ee,readWorktree as we,worktreeFromRow as ye}from"./worktrees.js";import{isPidAlive as me,isPidPresent as F,recordedPidLiveness as Ne}from"./pid.js";import{ensureHome as Re,jobDir as Se,nodeDir as he,nodeRunDir as H}from"./paths.js";import{appForNode as Oe,ensureNodeDirs as Te,nodeAgentDir as Le}from"./node-agent-paths.js";import{appSpace as C}from"../layout.js";import{createObject as De,getById as M,ownerForGrantee as h,setObjectKind as ge,setObjectName as Ae}from"../graph/objects.js";import{deleteNodeWithOwned as ve}from"../graph/deletion.js";import{SUBTREE_ALL_IDS_SQL as ke,SUBTREE_IDS_SQL as xe}from"./tree.js";import{filterAsync as y,mapAsync as O}from"../async-array.js";function E(e,n){if(e==null)return null;const t=JSON.stringify(e);if(t===void 0)throw new TypeError(`${n} must be JSON-serializable`);return t}i(E,"jsonValue");async function ln(e,n){if((await e.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(n))?.deleting_at)throw new Error("run is deleting")}i(ln,"assertRunNotDeleting");async function Ue(e,n){const t=await h(n,e.grantee??"app:terminal");await De(n,{id:e.node_id,type:"node",kind:e.kind,owner:t.id,privacy:"public",name:e.name,preview:""}),await n.prepare(`INSERT INTO nodes (node_id, description, title, icon, cycles, mode, lifecycle, cwd, host_kind, profile_id, parent, spawned_by, creator, fork_from, fork_source_file, created, passive_default, cycle_pending, model_override, persona_ack_json, review_binding_json, launch_config_json, scopes_json, isolated, status, intent, final_report, finalized_at, deadline_at, "window", tmux_session, pane, sub, grant_id, client_id, metadata_json, run_id, event_cursor, usage_json, deleting_at) VALUES (${Array(40).fill("?").join(", ")})`).run(e.node_id,e.description??null,e.title??null,e.icon??null,e.cycles??null,e.mode,e.lifecycle,e.cwd,e.host_kind??null,e.profile_id??null,e.parent??null,e.spawned_by??null,e.creator??null,e.fork_from??null,e.fork_source_file??null,e.created,e.passive_default===!0?1:0,e.cycle_pending===!0?1:0,e.model_override??null,E(e.persona_ack,"persona_ack"),E(e.review_binding,"review_binding"),E(e.launch,"launch"),E(e.scopes,"scopes"),e.isolated===!0?1:0,e.status??"active",e.intent??null,e.final_report??null,e.finalized_at??null,e.deadline_at??null,e.window??null,e.tmux_session??null,e.pane??null,e.sub??null,e.grant_id??null,e.client_id??null,e.metadata_json??null,e.run_id??null,e.event_cursor??null,e.usage_json??null,e.deleting_at??null)}i(Ue,"seedRow");function P(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,a])=>[t==="fault_id"?t:t.slice(6),a]);return pe(Object.fromEntries(n))}i(P,"faultFrom");function f(e){const n={node_id:e.node_id,name:e.name,description:e.description??void 0,cycles:e.cycles??void 0,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),isolated:e.isolated===1,grantee:e.grantee,sub:e.sub??null,grant_id:e.grant_id??null,client_id:e.client_id??null,metadata_json:e.metadata_json??null,run_id:e.run_id??null,event_cursor:e.event_cursor??null,last_activity_at:e.last_activity_at??null,usage_json:e.usage_json??null,last_turn_error_json:e.last_turn_error_json??null,deleting_at:e.deleting_at??null,parent:e.parent??null,created:e.created,intent:e.intent??null,frozen_at:e.frozen_at??null,respawn_failures:e.respawn_failures??0,respawn_not_before:e.respawn_not_before??null,launched_at:e.launched_at??null,last_settled_at:e.last_settled_at??null,terminal_reason:e.terminal_reason??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,outcome_kind:e.outcome_kind??null,outcome_reason:e.outcome_reason??null,outcome_at:e.outcome_at??null,outcome_revision:e.outcome_revision??0,outcome_detail_json:e.outcome_detail_json??null,deadline_at:e.deadline_at??null,telemetry_tokens_in:e.telemetry_tokens_in??null,telemetry_context_tokens:e.telemetry_context_tokens??null,telemetry_last_activity:e.telemetry_last_activity??null,telemetry_updated_at:e.telemetry_updated_at??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,fault:null,streaming:!1},t=F(n.pi_pid),a=P(e);return n.fault=a?.link==="pi\u2192provider"&&a.retry.by==="daemon"&&a.retry.disposition==="auto"&&!t?null:a,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}i(f,"rowFrom");async function $(e,n){return n??=await we(e.node_id),{...f(e),title:e.title??void 0,icon:e.icon??void 0,spawned_by:e.spawned_by??null,creator:e.creator??null,fork_from:e.fork_from??null,fork_source_file:e.fork_source_file??null,passive_default:e.passive_default===1,cycle_pending:e.cycle_pending===1,model_override:e.model_override??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),persona_ack:e.persona_ack_json==null?void 0:JSON.parse(e.persona_ack_json),review_binding:e.review_binding_json==null?void 0:JSON.parse(e.review_binding_json),launch:e.launch_config_json==null?void 0:JSON.parse(e.launch_config_json),pi_session_id:e.pi_session_id??null,pi_session_file:e.pi_session_file??null,...n===null?{}:{managed_worktree:n}}}i($,"metaFrom");async function cn(e,n={}){return Re(),await p(async t=>{await Ue(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&await Ee(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&await b(t,e.node_id,n.outcomeDelivery),await n.withinCreate?.(t,e)}),await Te(e.node_id),await N(e.node_id)}i(cn,"createNode");async function N(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:await $(n)}i(N,"getNode");const Ie=1440*60*1e3;function q(e){return{requestKey:e.request_key,nodeId:e.node_id,state:e.state}}i(q,"createRequestRecord");async function _n(e){const n=await(await s()).prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return n===void 0?null:q(n)}i(_n,"findCreateRequest");async function pn(e){return await p(async n=>{const t=Date.now();await n.prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(t);const a=await n.prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return a!==void 0?q(a):(await n.prepareUncached("INSERT INTO create_requests (request_key, node_id, expires_at, state) VALUES (?, NULL, ?, 'reserved')").run(e,t+Ie),{requestKey:e,nodeId:null,state:"reserved"})})}i(pn,"reserveCreateRequest");async function fn(e=Date.now()){return Number((await(await s()).prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(e)).changes)}i(fn,"pruneExpiredCreateRequests");async function En(e,n){await(await s()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'complete' WHERE request_key = ?").run(n,e)}i(En,"recordCreateRequestNode");async function wn(e,n){await(await s()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'reserved' WHERE request_key = ?").run(n,e)}i(wn,"reserveCreateRequestNode");async function yn(e,n){await(await s()).prepareUncached("UPDATE create_requests SET state = 'complete' WHERE request_key = ? AND node_id = ?").run(e,n)}i(yn,"completeCreateRequest");async function mn(e,n){await p(async t=>{if(n===null){await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id IS NULL").run(e);return}await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id = ?").run(e,n)})}i(mn,"abandonCreateRequest");function Nn(e){return ie(e)}i(Nn,"canonicalSessionFile");async function Rn(e){const n=await _e(e);return n===null?null:await N(n)}i(Rn,"findNodeBySessionFile");async function Sn(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?f(n):null}i(Sn,"getRow");async function hn(e){const n=await(await s()).prepare("SELECT * FROM node_rows WHERE pane = ?").get(e);return n?f(n):null}i(hn,"getRowByPane");async function On(e){return(await(await s()).prepare(`SELECT * FROM node_rows
1
+ var ee=Object.defineProperty;var i=(e,n)=>ee(e,"name",{value:n,configurable:!0});import{envNodeId as x}from"../../shared/env.js";import{rmdirSync as ne,rmSync as te,statSync as ae}from"node:fs";import{dirname as ie,join as I,resolve as oe}from"node:path";import{removeTreeBeneath as j}from"../spaces/open-beneath.js";import{emitEvent as re}from"../events/emit.js";import{withCanvasWrite as p,openDb as r}from"./db.js";import{conversationStore as se,ConversationNotFoundError as de}from"../conversation-store/index.js";import{hasUnseenWakeMail as ue,UNSEEN_WAKE_MAIL_SQL as le}from"./deliveries.js";import{isAppRun as W}from"./app-run.js";import{registerOutcomeAction as b}from"./outcome-actions.js";import{publish as ce}from"../graph/events.js";import{nodeObject as _e}from"../graph/objects.js";import{findNodeBySessionFileSql as pe}from"./sessions.js";import{hydrateFault as fe}from"./recovery.js";import{hasUnreconciledWorktree as Ee,openWorktree as we,readWorktree as ye,worktreeFromRow as me}from"./worktrees.js";import{isPidAlive as Ne,isPidPresent as F,recordedPidLiveness as Re}from"./pid.js";import{ensureHome as Se,jobDir as he,nodeDir as Oe,nodeRunDir as C}from"./paths.js";import{appForNode as Te,ensureNodeDirs as Le,nodeAgentDir as De}from"./node-agent-paths.js";import{appSpace as H}from"../layout.js";import{createObject as ge,getById as M,ownerForGrantee as h,setObjectKind as Ae,setObjectName as ve}from"../graph/objects.js";import{deleteNodeWithOwned as ke}from"../graph/deletion.js";import{SUBTREE_ALL_IDS_SQL as Ue,SUBTREE_IDS_SQL as xe}from"./tree.js";import{filterAsync as y,mapAsync as O}from"../async-array.js";function E(e,n){if(e==null)return null;const t=JSON.stringify(e);if(t===void 0)throw new TypeError(`${n} must be JSON-serializable`);return t}i(E,"jsonValue");async function cn(e,n){if((await e.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(n))?.deleting_at)throw new Error("run is deleting")}i(cn,"assertRunNotDeleting");async function Ie(e,n){const t=await h(n,e.grantee??"app:terminal");await ge(n,{id:e.node_id,type:"node",kind:e.kind,owner:t.id,privacy:"public",name:e.name,preview:""}),await n.prepare(`INSERT INTO nodes (node_id, description, title, icon, cycles, mode, lifecycle, cwd, host_kind, profile_id, parent, spawned_by, creator, fork_from, fork_source_file, created, passive_default, cycle_pending, model_override, persona_ack_json, review_binding_json, launch_config_json, scopes_json, isolated, status, intent, final_report, finalized_at, deadline_at, "window", tmux_session, pane, sub, grant_id, client_id, metadata_json, run_id, event_cursor, usage_json, deleting_at) VALUES (${Array(40).fill("?").join(", ")})`).run(e.node_id,e.description??null,e.title??null,e.icon??null,e.cycles??null,e.mode,e.lifecycle,e.cwd,e.host_kind??null,e.profile_id??null,e.parent??null,e.spawned_by??null,e.creator??null,e.fork_from??null,e.fork_source_file??null,e.created,e.passive_default===!0?1:0,e.cycle_pending===!0?1:0,e.model_override??null,E(e.persona_ack,"persona_ack"),E(e.review_binding,"review_binding"),E(e.launch,"launch"),E(e.scopes,"scopes"),e.isolated===!0?1:0,e.status??"active",e.intent??null,e.final_report??null,e.finalized_at??null,e.deadline_at??null,e.window??null,e.tmux_session??null,e.pane??null,e.sub??null,e.grant_id??null,e.client_id??null,e.metadata_json??null,e.run_id??null,e.event_cursor??null,e.usage_json??null,e.deleting_at??null)}i(Ie,"seedRow");function P(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,a])=>[t==="fault_id"?t:t.slice(6),a]);return fe(Object.fromEntries(n))}i(P,"faultFrom");function f(e){const n={node_id:e.node_id,name:e.name,description:e.description??void 0,cycles:e.cycles??void 0,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),isolated:e.isolated===1,grantee:e.grantee,sub:e.sub??null,grant_id:e.grant_id??null,client_id:e.client_id??null,metadata_json:e.metadata_json??null,run_id:e.run_id??null,event_cursor:e.event_cursor??null,last_activity_at:e.last_activity_at??null,usage_json:e.usage_json??null,last_turn_error_json:e.last_turn_error_json??null,deleting_at:e.deleting_at??null,parent:e.parent??null,created:e.created,intent:e.intent??null,frozen_at:e.frozen_at??null,respawn_failures:e.respawn_failures??0,respawn_not_before:e.respawn_not_before??null,launched_at:e.launched_at??null,last_settled_at:e.last_settled_at??null,terminal_reason:e.terminal_reason??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,outcome_kind:e.outcome_kind??null,outcome_reason:e.outcome_reason??null,outcome_at:e.outcome_at??null,outcome_revision:e.outcome_revision??0,outcome_detail_json:e.outcome_detail_json??null,deadline_at:e.deadline_at??null,telemetry_tokens_in:e.telemetry_tokens_in??null,telemetry_context_tokens:e.telemetry_context_tokens??null,telemetry_last_activity:e.telemetry_last_activity??null,telemetry_updated_at:e.telemetry_updated_at??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,fault:null,streaming:!1},t=F(n.pi_pid),a=P(e);return n.fault=a?.link==="pi\u2192provider"&&a.retry.by==="daemon"&&a.retry.disposition==="auto"&&!t?null:a,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}i(f,"rowFrom");async function $(e,n){return n??=await ye(e.node_id),{...f(e),title:e.title??void 0,icon:e.icon??void 0,spawned_by:e.spawned_by??null,creator:e.creator??null,fork_from:e.fork_from??null,fork_source_file:e.fork_source_file??null,passive_default:e.passive_default===1,cycle_pending:e.cycle_pending===1,model_override:e.model_override??null,scopes:e.scopes_json==null?null:JSON.parse(e.scopes_json),persona_ack:e.persona_ack_json==null?void 0:JSON.parse(e.persona_ack_json),review_binding:e.review_binding_json==null?void 0:JSON.parse(e.review_binding_json),launch:e.launch_config_json==null?void 0:JSON.parse(e.launch_config_json),pi_session_id:e.pi_session_id??null,pi_session_file:e.pi_session_file??null,...n===null?{}:{managed_worktree:n}}}i($,"metaFrom");async function _n(e,n={}){return Se(),await p(async t=>{await Ie(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&await we(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&await b(t,e.node_id,n.outcomeDelivery),await n.withinCreate?.(t,e)}),await Le(e.node_id),await N(e.node_id)}i(_n,"createNode");async function N(e){const n=await(await r()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:await $(n)}i(N,"getNode");const je=1440*60*1e3;function q(e){return{requestKey:e.request_key,nodeId:e.node_id,state:e.state}}i(q,"createRequestRecord");async function pn(e){const n=await(await r()).prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return n===void 0?null:q(n)}i(pn,"findCreateRequest");async function fn(e){return await p(async n=>{const t=Date.now();await n.prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(t);const a=await n.prepareUncached("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return a!==void 0?q(a):(await n.prepareUncached("INSERT INTO create_requests (request_key, node_id, expires_at, state) VALUES (?, NULL, ?, 'reserved')").run(e,t+je),{requestKey:e,nodeId:null,state:"reserved"})})}i(fn,"reserveCreateRequest");async function En(e=Date.now()){return Number((await(await r()).prepareUncached("DELETE FROM create_requests WHERE expires_at <= ?").run(e)).changes)}i(En,"pruneExpiredCreateRequests");async function wn(e,n){await(await r()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'complete' WHERE request_key = ?").run(n,e)}i(wn,"recordCreateRequestNode");async function yn(e,n){await(await r()).prepareUncached("UPDATE create_requests SET node_id = ?, state = 'reserved' WHERE request_key = ?").run(n,e)}i(yn,"reserveCreateRequestNode");async function mn(e,n){await(await r()).prepareUncached("UPDATE create_requests SET state = 'complete' WHERE request_key = ? AND node_id = ?").run(e,n)}i(mn,"completeCreateRequest");async function Nn(e,n){await p(async t=>{if(n===null){await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id IS NULL").run(e);return}await t.prepareUncached("DELETE FROM create_requests WHERE request_key = ? AND node_id = ?").run(e,n)})}i(Nn,"abandonCreateRequest");function Rn(e){return oe(e)}i(Rn,"canonicalSessionFile");async function Sn(e){const n=await pe(e);return n===null?null:await N(n)}i(Sn,"findNodeBySessionFile");async function hn(e){const n=await(await r()).prepare("SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?f(n):null}i(hn,"getRow");async function On(e){const n=await(await r()).prepare("SELECT * FROM node_rows WHERE pane = ?").get(e);return n?f(n):null}i(On,"getRowByPane");async function Tn(e){return(await(await r()).prepare(`SELECT * FROM node_rows
2
2
  WHERE deadline_at IS NOT NULL AND outcome_at IS NULL
3
3
  AND deadline_at <= ? AND status IN ('active','idle') AND kind != 'human'
4
- ORDER BY deadline_at, created, node_id`).all(e)).map(f)}i(On,"dueNodeDeadlines");async function Tn(e,n){return Number((await(await s()).prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e)).changes)===1}i(Tn,"setNodeDeadline");async function Ln(e,n){return!Number.isFinite(n)||n<=0?0:await p(async t=>{const a=await t.prepare(`SELECT node_id, deadline_at FROM nodes
5
- WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),o=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let r=0;for(const d of a){const l=Date.parse(d.deadline_at);Number.isNaN(l)||(r+=Number((await o.run(new Date(l+n).toISOString(),d.node_id,d.deadline_at)).changes))}return r})}i(Ln,"shiftProfileNodeDeadlines");async function Dn(e,n,t){const a=`SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner JOIN nodes n ON n.node_id = o.id
6
- WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = 'user:local'`,r=await e.prepareUncached(`${a} LIMIT 1`).get()!==void 0?Number((await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${a})`).run((await h(e,"app:terminal")).id)).changes):0,d=`SELECT o.id FROM objects o JOIN peer_stubs s ON s.object = o.id JOIN identities i ON i.object = o.owner
4
+ ORDER BY deadline_at, created, node_id`).all(e)).map(f)}i(Tn,"dueNodeDeadlines");async function Ln(e,n){return Number((await(await r()).prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e)).changes)===1}i(Ln,"setNodeDeadline");async function Dn(e,n){return!Number.isFinite(n)||n<=0?0:await p(async t=>{const a=await t.prepare(`SELECT node_id, deadline_at FROM nodes
5
+ WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),o=t.prepare("UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let s=0;for(const d of a){const l=Date.parse(d.deadline_at);Number.isNaN(l)||(s+=Number((await o.run(new Date(l+n).toISOString(),d.node_id,d.deadline_at)).changes))}return s})}i(Dn,"shiftProfileNodeDeadlines");async function gn(e,n,t){const a=`SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner JOIN nodes n ON n.node_id = o.id
6
+ WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = 'user:local'`,s=await e.prepareUncached(`${a} LIMIT 1`).get()!==void 0?Number((await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${a})`).run((await h(e,"app:terminal")).id)).changes):0,d=`SELECT o.id FROM objects o JOIN peer_stubs s ON s.object = o.id JOIN identities i ON i.object = o.owner
7
7
  WHERE o.type = 'node' AND o.reception = 2 AND s.envelope_json ->> 'app' IS NULL
8
- AND i.scheme = 'app' AND i.external_id = 'app:terminal'`,l=await e.prepareUncached(`${d} LIMIT 1`).get()!==void 0?Number((await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${d})`).run((await h(e,"user:local")).id)).changes):0;return Number((await e.prepare("UPDATE nodes SET sub = ? WHERE sub = 'user:local'").run(n)).changes)+r+l+Number((await e.prepare(`UPDATE nodes SET sub = ? WHERE sub IS NULL AND node_id IN (
8
+ AND i.scheme = 'app' AND i.external_id = 'app:terminal'`,l=await e.prepareUncached(`${d} LIMIT 1`).get()!==void 0?Number((await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${d})`).run((await h(e,"user:local")).id)).changes):0;return Number((await e.prepare("UPDATE nodes SET sub = ? WHERE sub = 'user:local'").run(n)).changes)+s+l+Number((await e.prepare(`UPDATE nodes SET sub = ? WHERE sub IS NULL AND node_id IN (
9
9
  SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner
10
- WHERE o.type = 'node' AND i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(n)).changes)+Number((await e.prepare("UPDATE nodes SET grant_id = NULL WHERE grant_id = ?").run(t)).changes)}i(Dn,"rewriteLocalNodeIdentity");function T(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}i(T,"sqlInput");async function gn(e,n){const t=[],a=i((r,d=r)=>{Object.prototype.hasOwnProperty.call(n,r)&&t.push([d,T(n[r],r)])},"add");if(a("description"),a("title"),a("icon"),a("cycles"),a("mode"),a("lifecycle"),a("cwd"),a("host_kind"),a("profile_id"),a("parent"),a("spawned_by"),a("creator"),a("fork_from"),a("fork_source_file"),a("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",E(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",E(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"isolated"))throw new TypeError("isolated cannot change after node creation");Object.prototype.hasOwnProperty.call(n,"scopes")&&t.push(["scopes_json",E(n.scopes,"scopes")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",E(n.launch,"launch")]);const o=i(r=>Object.prototype.hasOwnProperty.call(n,r),"has");return await p(async r=>{const d=await M(r,e);if(d===null||d.type!=="node")throw new Error(`unknown node: ${e}`);if(o("name")&&await Ae(r,d,T(n.name,"name")),o("kind")&&await ge(r,d,T(n.kind,"kind")),t.length===0)return;if((await r.prepareUncached(`UPDATE nodes SET ${t.map(([u])=>`${u} = ?`).join(", ")} WHERE node_id = ?`).run(...t.map(([,u])=>u),e)).changes!==1)throw new Error(`unknown node: ${e}`)}),await N(e)}i(gn,"updateNode");async function An(e,n){await(await s()).prepare("UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}i(An,"setStatus");async function vn(e,n){await(await s()).prepare("UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}i(vn,"setIntent");async function kn(e,n,t={}){if(t.outcome===void 0){const o=[],r=[];Object.prototype.hasOwnProperty.call(n,"status")&&(o.push("status = ?"),r.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(o.push("intent = ?"),r.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(o.push("terminal_reason = ?"),r.push(n.terminal_reason??null));const d=["node_id = ?"];r.push(e),t.fromStatuses!==void 0&&(d.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),r.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&d.push("final_report IS NULL");const l=await(await s()).prepareUncached(`UPDATE nodes SET ${o.join(", ")} WHERE ${d.join(" AND ")}`).run(...r);return Number(l.changes)}const a=t.outcome;return await p(async o=>{const r=[],d=[];Object.prototype.hasOwnProperty.call(n,"status")&&(r.push("status = ?"),d.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(r.push("intent = ?"),d.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(r.push("terminal_reason = ?"),d.push(n.terminal_reason??null));const l=i((m,c)=>a.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${c} END`,"outcomeValue");r.push(`outcome_kind = ${l(a.kind,"outcome_kind")}`,`outcome_reason = ${l(a.reason,"outcome_reason")}`,`outcome_detail_json = ${l(a.detailJson,"outcome_detail_json")}`,`outcome_revision = ${a.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${l(a.at,"outcome_at")}`),d.push(a.kind,a.reason,a.detailJson,a.at);const u=["node_id = ?"];d.push(e),t.fromStatuses!==void 0&&(u.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),d.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&u.push("final_report IS NULL");const _=await o.prepareUncached(`UPDATE nodes SET ${r.join(", ")} WHERE ${u.join(" AND ")}`).run(...d);if(Number(_.changes)===0)return 0;const S=await o.prepare("SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(a.supersede===!0||S.outcome_at===a.at)&&a.documentJson!==null&&a.documentJson!==void 0&&await le(o,{event:"outcome",object:await ce(o,e),actor:null,attrs:{revision:Number((await o.prepare("SELECT outcome_revision FROM nodes WHERE node_id = ?").get(e)).outcome_revision)},messageBody:JSON.parse(a.documentJson)}),Number(_.changes)})}i(kn,"transitionStatusIntent");async function xn(e){return(await(await s()).prepare("SELECT final_report FROM nodes WHERE node_id = ?").get(e))?.final_report??null}i(xn,"getFinalReport");async function Un(e,n){return(await(await s()).prepare("UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n)).changes>0}i(Un,"clearFinalReportIfMatches");async function In(e,n){await(await s()).prepare('UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}i(In,"setPresence");async function jn(e,n){await(await s()).prepare("UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}i(jn,"recordLaunch");async function Wn(e,n){await(await s()).prepare("UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}i(Wn,"recordSettledTurn");async function bn(e,n){await(await s()).prepare("UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}i(bn,"setFrozen");async function Fn(e){await(await s()).prepare("UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}i(Fn,"clearFrozen");async function Hn(e,n){await(await s()).prepare("UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}i(Hn,"recordRespawnAttempt");const w="node_id NOT IN (SELECT node_id FROM warm_pool)",B=["state","cleanup_state","path","branch","repo_root","base_ref","base_sha","created_at","closed_at","next_attempt_at","attempts","quarantined","sweep_reason","sweep_detail","sweep_last_at","sweep_observed_json","abandoned_json","land_intent_json","disposal_json"];function je(e){return e.worktree_state===null?null:ye(Object.fromEntries(B.map(n=>[n,e[`worktree_${n}`]])))}i(je,"worktreeFromProjection");async function Cn(e){const n=B.map(a=>`w.${a} AS worktree_${a}`).join(", "),t=await(await s()).prepareUncached(`SELECT n.*, ${n} FROM node_rows n LEFT JOIN worktrees w ON w.node_id = n.node_id WHERE n.profile_id = ? ORDER BY n.created`).all(e);return await O(t,async a=>await $(a,je(a)))}i(Cn,"listNodesByProfile");async function Mn(){return(await(await s()).prepare(`SELECT
10
+ WHERE o.type = 'node' AND i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(n)).changes)+Number((await e.prepare("UPDATE nodes SET grant_id = NULL WHERE grant_id = ?").run(t)).changes)}i(gn,"rewriteLocalNodeIdentity");function T(e,n){if(e==null)return null;if(typeof e=="string"||typeof e=="number"||typeof e=="bigint"||e instanceof Uint8Array)return e;throw new TypeError(`${n} must be a SQLite scalar`)}i(T,"sqlInput");async function An(e,n){const t=[],a=i((s,d=s)=>{Object.prototype.hasOwnProperty.call(n,s)&&t.push([d,T(n[s],s)])},"add");if(a("description"),a("title"),a("icon"),a("cycles"),a("mode"),a("lifecycle"),a("cwd"),a("host_kind"),a("profile_id"),a("parent"),a("spawned_by"),a("creator"),a("fork_from"),a("fork_source_file"),a("model_override"),Object.prototype.hasOwnProperty.call(n,"passive_default")&&t.push(["passive_default",n.passive_default===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"cycle_pending")&&t.push(["cycle_pending",n.cycle_pending===!0?1:0]),Object.prototype.hasOwnProperty.call(n,"persona_ack")&&t.push(["persona_ack_json",E(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",E(n.review_binding,"review_binding")]),Object.prototype.hasOwnProperty.call(n,"isolated"))throw new TypeError("isolated cannot change after node creation");Object.prototype.hasOwnProperty.call(n,"scopes")&&t.push(["scopes_json",E(n.scopes,"scopes")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",E(n.launch,"launch")]);const o=i(s=>Object.prototype.hasOwnProperty.call(n,s),"has");return await p(async s=>{const d=await M(s,e);if(d===null||d.type!=="node")throw new Error(`unknown node: ${e}`);if(o("name")&&await ve(s,d,T(n.name,"name")),o("kind")&&await Ae(s,d,T(n.kind,"kind")),t.length===0)return;if((await s.prepareUncached(`UPDATE nodes SET ${t.map(([u])=>`${u} = ?`).join(", ")} WHERE node_id = ?`).run(...t.map(([,u])=>u),e)).changes!==1)throw new Error(`unknown node: ${e}`)}),await N(e)}i(An,"updateNode");async function vn(e,n){await(await r()).prepare("UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}i(vn,"setStatus");async function kn(e,n){await(await r()).prepare("UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}i(kn,"setIntent");async function Un(e,n,t={}){if(t.outcome===void 0){const o=[],s=[];Object.prototype.hasOwnProperty.call(n,"status")&&(o.push("status = ?"),s.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(o.push("intent = ?"),s.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(o.push("terminal_reason = ?"),s.push(n.terminal_reason??null));const d=["node_id = ?"];s.push(e),t.fromStatuses!==void 0&&(d.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),s.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&d.push("final_report IS NULL");const l=await(await r()).prepareUncached(`UPDATE nodes SET ${o.join(", ")} WHERE ${d.join(" AND ")}`).run(...s);return Number(l.changes)}const a=t.outcome;return await p(async o=>{const s=[],d=[];Object.prototype.hasOwnProperty.call(n,"status")&&(s.push("status = ?"),d.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(s.push("intent = ?"),d.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(s.push("terminal_reason = ?"),d.push(n.terminal_reason??null));const l=i((m,c)=>a.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${c} END`,"outcomeValue");s.push(`outcome_kind = ${l(a.kind,"outcome_kind")}`,`outcome_reason = ${l(a.reason,"outcome_reason")}`,`outcome_detail_json = ${l(a.detailJson,"outcome_detail_json")}`,`outcome_revision = ${a.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${l(a.at,"outcome_at")}`),d.push(a.kind,a.reason,a.detailJson,a.at);const u=["node_id = ?"];d.push(e),t.fromStatuses!==void 0&&(u.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),d.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&u.push("final_report IS NULL");const _=await o.prepareUncached(`UPDATE nodes SET ${s.join(", ")} WHERE ${u.join(" AND ")}`).run(...d);if(Number(_.changes)===0)return 0;const S=await o.prepare("SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(a.supersede===!0||S.outcome_at===a.at)&&a.documentJson!==null&&a.documentJson!==void 0&&await ce(o,{event:"outcome",object:await _e(o,e),actor:null,attrs:{revision:Number((await o.prepare("SELECT outcome_revision FROM nodes WHERE node_id = ?").get(e)).outcome_revision)},messageBody:JSON.parse(a.documentJson)}),Number(_.changes)})}i(Un,"transitionStatusIntent");async function xn(e){return(await(await r()).prepare("SELECT final_report FROM nodes WHERE node_id = ?").get(e))?.final_report??null}i(xn,"getFinalReport");async function In(e,n){return(await(await r()).prepare("UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n)).changes>0}i(In,"clearFinalReportIfMatches");async function jn(e,n){await(await r()).prepare('UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}i(jn,"setPresence");async function Wn(e,n){await(await r()).prepare("UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}i(Wn,"recordLaunch");async function bn(e,n){await(await r()).prepare("UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}i(bn,"recordSettledTurn");async function Fn(e,n){await(await r()).prepare("UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}i(Fn,"setFrozen");async function Cn(e){await(await r()).prepare("UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}i(Cn,"clearFrozen");async function Hn(e,n){await(await r()).prepare("UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}i(Hn,"recordRespawnAttempt");const w="node_id NOT IN (SELECT node_id FROM warm_pool)",B=["state","cleanup_state","path","branch","repo_root","base_ref","base_sha","created_at","closed_at","next_attempt_at","attempts","quarantined","sweep_reason","sweep_detail","sweep_last_at","sweep_observed_json","abandoned_json","land_intent_json","disposal_json"];function We(e){return e.worktree_state===null?null:me(Object.fromEntries(B.map(n=>[n,e[`worktree_${n}`]])))}i(We,"worktreeFromProjection");async function Mn(e){const n=B.map(a=>`w.${a} AS worktree_${a}`).join(", "),t=await(await r()).prepareUncached(`SELECT n.*, ${n} FROM node_rows n LEFT JOIN worktrees w ON w.node_id = n.node_id WHERE n.profile_id = ? ORDER BY n.created`).all(e);return await O(t,async a=>await $(a,We(a)))}i(Mn,"listNodesByProfile");async function Pn(){return(await(await r()).prepare(`SELECT
11
11
  node_id, name, description, kind, mode, lifecycle, status, cwd, profile_id,
12
12
  grantee, parent, created, frozen_at, terminal_reason, final_report,
13
13
  telemetry_tokens_in, telemetry_updated_at, pi_pid, turn_open_at, turn_closed_at,
@@ -15,13 +15,13 @@ var Z=Object.defineProperty;var i=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
15
15
  fault_operation_id, fault_anchor_entry_id, fault_retry_disposition,
16
16
  fault_retry_by, fault_retry_attempt, fault_retry_max, fault_retry_next_at,
17
17
  fault_provider_error_json
18
- FROM node_rows WHERE ${w} ORDER BY created`).all()).map(f)}i(Mn,"browseNodes");async function Pn(e,n){await(await s()).prepare(`UPDATE nodes
18
+ FROM node_rows WHERE ${w} ORDER BY created`).all()).map(f)}i(Pn,"browseNodes");async function $n(e,n){await(await r()).prepare(`UPDATE nodes
19
19
  SET telemetry_tokens_in = ?,
20
20
  telemetry_context_tokens = COALESCE(?, telemetry_context_tokens),
21
21
  telemetry_last_activity = COALESCE(?, telemetry_last_activity),
22
22
  telemetry_updated_at = ?
23
23
  WHERE node_id = ?
24
- AND (telemetry_updated_at IS NULL OR telemetry_updated_at < ?)`).run(n.tokensIn,n.contextTokens,n.lastActivity,n.updatedAt,e,n.updatedAt)}i(Pn,"updateNodeTelemetry");async function $n(){return(await(await s()).prepare(`SELECT
24
+ AND (telemetry_updated_at IS NULL OR telemetry_updated_at < ?)`).run(n.tokensIn,n.contextTokens,n.lastActivity,n.updatedAt,e,n.updatedAt)}i($n,"updateNodeTelemetry");async function qn(){return(await(await r()).prepare(`SELECT
25
25
  node_id, name, description, cycles, kind, status, frozen_at,
26
26
  telemetry_context_tokens, telemetry_last_activity,
27
27
  pi_pid, turn_open_at, turn_closed_at,
@@ -29,14 +29,14 @@ var Z=Object.defineProperty;var i=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
29
29
  fault_operation_id, fault_anchor_entry_id, fault_retry_disposition,
30
30
  fault_retry_by, fault_retry_attempt, fault_retry_max, fault_retry_next_at,
31
31
  fault_provider_error_json
32
- FROM node_rows WHERE ${w} ORDER BY created`).all()).map(n=>{const t=n.pi_pid??null,a=F(t),o=P(n);return{node_id:n.node_id,name:n.name,description:n.description??null,cycles:n.cycles??null,kind:n.kind,status:n.status,frozen_at:n.frozen_at??null,pi_pid:t,telemetry_context_tokens:n.telemetry_context_tokens??null,telemetry_last_activity:n.telemetry_last_activity??null,fault:o?.link==="pi\u2192provider"&&o.retry.by==="daemon"&&o.retry.disposition==="auto"&&!a?null:o,streaming:n.turn_open_at!==null&&n.turn_closed_at===null&&a}})}i($n,"graphNodes");async function We(e){const n=[w],t=[];if(e?.under!==void 0&&(e.underInclusive===!0?(n.push(`(node_id IN (${ke}) OR node_id = ?)`),t.push(e.under,e.under,e.under)):(n.push(`node_id IN (${xe})`),t.push(e.under,e.under))),e?.lifecycle!==void 0&&(n.push("lifecycle = ?"),t.push(e.lifecycle)),e?.kind!==void 0&&(n.push("kind = ?"),t.push(e.kind)),e?.mode!==void 0&&(n.push("mode = ?"),t.push(e.mode)),e?.profileId!==void 0&&(n.push("profile_id = ?"),t.push(e.profileId)),e?.profilePrefix!==void 0&&(n.push("profile_id LIKE ? ESCAPE '\\'"),t.push(`${e.profilePrefix.replace(/[\\%_]/g,o=>`\\${o}`)}%`)),e?.parent!==void 0&&(n.push("parent = ?"),t.push(e.parent)),e?.topLevel===!0&&n.push("parent IS NULL"),e?.hanging===!0&&n.push("parent IS NOT NULL AND parent NOT IN (SELECT node_id FROM node_rows)"),e?.status!==void 0){const o=Array.isArray(e.status)?e.status:[e.status];n.push(`status IN (${o.map(()=>"?").join(",")})`),t.push(...o)}return e?.withRecordedPid===!0&&n.push("pi_pid IS NOT NULL"),e?.withRecordedPidOrFrozen===!0&&n.push("(pi_pid IS NOT NULL OR frozen_at IS NOT NULL)"),(await(await s()).prepareUncached(`SELECT * FROM node_rows WHERE ${n.join(" AND ")} ORDER BY created`).all(...t)).map(f)}i(We,"listNodes");const be=`SELECT
32
+ FROM node_rows WHERE ${w} ORDER BY created`).all()).map(n=>{const t=n.pi_pid??null,a=F(t),o=P(n);return{node_id:n.node_id,name:n.name,description:n.description??null,cycles:n.cycles??null,kind:n.kind,status:n.status,frozen_at:n.frozen_at??null,pi_pid:t,telemetry_context_tokens:n.telemetry_context_tokens??null,telemetry_last_activity:n.telemetry_last_activity??null,fault:o?.link==="pi\u2192provider"&&o.retry.by==="daemon"&&o.retry.disposition==="auto"&&!a?null:o,streaming:n.turn_open_at!==null&&n.turn_closed_at===null&&a}})}i(qn,"graphNodes");async function be(e){const n=[w],t=[];if(e?.under!==void 0&&(e.underInclusive===!0?(n.push(`(node_id IN (${Ue}) OR node_id = ?)`),t.push(e.under,e.under,e.under)):(n.push(`node_id IN (${xe})`),t.push(e.under,e.under))),e?.lifecycle!==void 0&&(n.push("lifecycle = ?"),t.push(e.lifecycle)),e?.kind!==void 0&&(n.push("kind = ?"),t.push(e.kind)),e?.mode!==void 0&&(n.push("mode = ?"),t.push(e.mode)),e?.profileId!==void 0&&(n.push("profile_id = ?"),t.push(e.profileId)),e?.profilePrefix!==void 0&&(n.push("profile_id LIKE ? ESCAPE '\\'"),t.push(`${e.profilePrefix.replace(/[\\%_]/g,o=>`\\${o}`)}%`)),e?.parent!==void 0&&(n.push("parent = ?"),t.push(e.parent)),e?.topLevel===!0&&n.push("parent IS NULL"),e?.hanging===!0&&n.push("parent IS NOT NULL AND parent NOT IN (SELECT node_id FROM node_rows)"),e?.status!==void 0){const o=Array.isArray(e.status)?e.status:[e.status];n.push(`status IN (${o.map(()=>"?").join(",")})`),t.push(...o)}return e?.withRecordedPid===!0&&n.push("pi_pid IS NOT NULL"),e?.withRecordedPidOrFrozen===!0&&n.push("(pi_pid IS NOT NULL OR frozen_at IS NOT NULL)"),(await(await r()).prepareUncached(`SELECT * FROM node_rows WHERE ${n.join(" AND ")} ORDER BY created`).all(...t)).map(f)}i(be,"listNodes");const Fe=`SELECT
33
33
  node_id, created, launched_at, last_settled_at, finalized_at,
34
34
  outcome_at, last_activity_at, pane, "window", tmux_session
35
35
  FROM nodes
36
36
  WHERE ${w}
37
37
  AND status IN ('done', 'canceled', 'dead')
38
38
  AND (pane IS NOT NULL OR "window" IS NOT NULL OR tmux_session IS NOT NULL)
39
- ORDER BY created`;async function qn(){return await(await s()).prepare(be).all()}i(qn,"listTerminalPlacementResidue");const Fe=`WITH candidates AS MATERIALIZED (
39
+ ORDER BY created`;async function Bn(){return await(await r()).prepare(Fe).all()}i(Bn,"listTerminalPlacementResidue");const Ce=`WITH candidates AS MATERIALIZED (
40
40
  SELECT node_id FROM nodes WHERE status IN ('active', 'idle')
41
41
  UNION
42
42
  SELECT node_id FROM nodes
@@ -50,19 +50,19 @@ var Z=Object.defineProperty;var i=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
50
50
  AND v.node_id NOT IN (SELECT node_id FROM warm_pool)
51
51
  AND v.kind != 'human'
52
52
  AND (v.status IN ('active', 'idle') OR (v.status IN ('done', 'canceled', 'dead') AND (v.pi_pid IS NOT NULL OR v.frozen_at IS NOT NULL)))
53
- ORDER BY v.created`;async function Bn(){return(await(await s()).prepare(Fe).all()).map(f)}i(Bn,"listNodesForSupervision");const He=i(e=>`(${e}.status = 'done' AND ${e}.intent = 'parked' AND ${e}.lifecycle = 'resident' AND ${e}.final_report IS NULL AND ${e}.deleting_at IS NULL)`,"PARKED_RESIDENT_SQL");async function zn(){return(await(await s()).prepare(`SELECT v.* FROM node_rows v
54
- WHERE ${He("v")}
55
- AND EXISTS (SELECT 1 FROM deliveries d WHERE d.destination_id = v.node_id AND ${ue("d")}) AND v.kind != 'human' AND v.node_id NOT IN (SELECT node_id FROM warm_pool)
56
- ORDER BY v.created`).all()).map(f)}i(zn,"listParkedResidentsWithWakeMail");async function Jn(){return await(await s()).prepare(`SELECT node_id, name, created, grantee FROM node_rows WHERE ${w} ORDER BY created`).all()}i(Jn,"listNodeIdentities");async function Yn(e,n){await(await s()).prepare("INSERT INTO warm_pool (node_id, recipe_key, created) VALUES (?, ?, ?) ON CONFLICT (node_id) DO UPDATE SET recipe_key = excluded.recipe_key, created = excluded.created").run(e,n,new Date().toISOString())}i(Yn,"registerWarmSpare");async function Qn(e){return(await(await s()).prepare("DELETE FROM warm_pool WHERE node_id = ?").run(e)).changes>0}i(Qn,"unregisterWarmSpare");async function L(e,n){const t=`SELECT w.node_id AS node_id, w.recipe_key AS recipe_key, w.created AS created,
53
+ ORDER BY v.created`;async function zn(){return(await(await r()).prepare(Ce).all()).map(f)}i(zn,"listNodesForSupervision");const z=i(e=>`(${e}.status = 'done' AND ${e}.intent = 'parked' AND ${e}.lifecycle = 'resident' AND ${e}.final_report IS NULL AND ${e}.deleting_at IS NULL)`,"PARKED_RESIDENT_SQL"),He=i(e=>`(${e}.status IN ('active', 'idle') OR ${z(e)} OR (${e}.status IN ('done', 'canceled', 'dead') AND ${e}.frozen_at IS NOT NULL AND ${e}.final_report IS NULL))`,"RESUMABLE_NODE_SQL");async function Jn(e){return await(await r()).prepare(`SELECT node_id, cwd FROM nodes WHERE ${He("nodes")} AND node_id != ?`).all(e)}i(Jn,"resumableNodeCwds");async function Yn(){return(await(await r()).prepare(`SELECT v.* FROM node_rows v
54
+ WHERE ${z("v")}
55
+ AND EXISTS (SELECT 1 FROM deliveries d WHERE d.destination_id = v.node_id AND ${le("d")}) AND v.kind != 'human' AND v.node_id NOT IN (SELECT node_id FROM warm_pool)
56
+ ORDER BY v.created`).all()).map(f)}i(Yn,"listParkedResidentsWithWakeMail");async function Qn(){return await(await r()).prepare(`SELECT node_id, name, created, grantee FROM node_rows WHERE ${w} ORDER BY created`).all()}i(Qn,"listNodeIdentities");async function Vn(e,n){await(await r()).prepare("INSERT INTO warm_pool (node_id, recipe_key, created) VALUES (?, ?, ?) ON CONFLICT (node_id) DO UPDATE SET recipe_key = excluded.recipe_key, created = excluded.created").run(e,n,new Date().toISOString())}i(Vn,"registerWarmSpare");async function Kn(e){return(await(await r()).prepare("DELETE FROM warm_pool WHERE node_id = ?").run(e)).changes>0}i(Kn,"unregisterWarmSpare");async function L(e,n){const t=`SELECT w.node_id AS node_id, w.recipe_key AS recipe_key, w.created AS created,
57
57
  n.status AS status, n.pi_pid AS pi_pid, n.pi_pid_identity AS pi_pid_identity
58
- FROM warm_pool w JOIN node_rows n ON n.node_id = w.node_id`+(n===void 0?"":" WHERE w.recipe_key = ?")+" ORDER BY w.created";return(n===void 0?await e.prepareUncached(t).all():await e.prepareUncached(t).all(n)).map(o=>({node_id:o.node_id,recipe_key:o.recipe_key,created:o.created,status:o.status,pi_pid:o.pi_pid??null,pi_pid_identity:o.pi_pid_identity??null}))}i(L,"warmSpareRowsFor");async function Vn(){return await L(await s())}i(Vn,"listWarmSpares");async function Kn(e){return await(await s()).prepare("SELECT 1 FROM warm_pool WHERE node_id = ?").get(e)!==void 0}i(Kn,"isWarmSpare");function z(e){return e.status!=="active"&&e.status!=="idle"?!1:Ne(e.pi_pid,e.pi_pid_identity)==="alive"}i(z,"spareIsClaimable");async function Gn(e,n,t={}){return await p(async a=>{const o=(await L(a,e)).find(z);return o===void 0||t.requestKey!==void 0&&(await a.prepareUncached("UPDATE create_requests SET node_id = ?, state = 'warm_claimed' WHERE request_key = ? AND node_id IS NULL").run(o.node_id,t.requestKey)).changes===0||(await a.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(o.node_id)).changes===0?null:(await a.prepare("UPDATE nodes SET created = ?, deadline_at = ? WHERE node_id = ?").run(n,t.deadlineAt??null,o.node_id),t.outcomeDelivery!==void 0&&await b(a,o.node_id,t.outcomeDelivery),o.node_id)})}i(Gn,"claimWarmSpare");async function Xn(e){return(await L(await s(),e)).filter(z).length}i(Xn,"warmSpareCount");async function Zn(e){return(await(await s()).prepare("SELECT node_id FROM nodes WHERE parent = ? ORDER BY created").all(e)).map(n=>n.node_id)}i(Zn,"childrenOf");async function et(){return(await(await s()).prepareUncached(`SELECT node_id, name, kind, mode, lifecycle, status, cwd, host_kind, parent, created, description
59
- FROM node_rows WHERE ${w} ORDER BY created`).all()).map(e=>({node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,parent:e.parent??null,created:e.created,description:e.description??null}))}i(et,"rosterNodes");async function nt(e){return(await(await s()).prepareUncached(`SELECT * FROM node_rows
58
+ FROM warm_pool w JOIN node_rows n ON n.node_id = w.node_id`+(n===void 0?"":" WHERE w.recipe_key = ?")+" ORDER BY w.created";return(n===void 0?await e.prepareUncached(t).all():await e.prepareUncached(t).all(n)).map(o=>({node_id:o.node_id,recipe_key:o.recipe_key,created:o.created,status:o.status,pi_pid:o.pi_pid??null,pi_pid_identity:o.pi_pid_identity??null}))}i(L,"warmSpareRowsFor");async function Gn(){return await L(await r())}i(Gn,"listWarmSpares");async function Xn(e){return await(await r()).prepare("SELECT 1 FROM warm_pool WHERE node_id = ?").get(e)!==void 0}i(Xn,"isWarmSpare");function J(e){return e.status!=="active"&&e.status!=="idle"?!1:Re(e.pi_pid,e.pi_pid_identity)==="alive"}i(J,"spareIsClaimable");async function Zn(e,n,t={}){return await p(async a=>{const o=(await L(a,e)).find(J);return o===void 0||t.requestKey!==void 0&&(await a.prepareUncached("UPDATE create_requests SET node_id = ?, state = 'warm_claimed' WHERE request_key = ? AND node_id IS NULL").run(o.node_id,t.requestKey)).changes===0||(await a.prepare("DELETE FROM warm_pool WHERE node_id = ?").run(o.node_id)).changes===0?null:(await a.prepare("UPDATE nodes SET created = ?, deadline_at = ? WHERE node_id = ?").run(n,t.deadlineAt??null,o.node_id),t.outcomeDelivery!==void 0&&await b(a,o.node_id,t.outcomeDelivery),o.node_id)})}i(Zn,"claimWarmSpare");async function et(e){return(await L(await r(),e)).filter(J).length}i(et,"warmSpareCount");async function nt(e){return(await(await r()).prepare("SELECT node_id FROM nodes WHERE parent = ? ORDER BY created").all(e)).map(n=>n.node_id)}i(nt,"childrenOf");async function tt(){return(await(await r()).prepareUncached(`SELECT node_id, name, kind, mode, lifecycle, status, cwd, host_kind, parent, created, description
59
+ FROM node_rows WHERE ${w} ORDER BY created`).all()).map(e=>({node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,parent:e.parent??null,created:e.created,description:e.description??null}))}i(tt,"rosterNodes");async function at(e){return(await(await r()).prepareUncached(`SELECT * FROM node_rows
60
60
  WHERE parent IS NULL AND kind != 'human'
61
61
  AND status IN ('active','idle') AND cwd = ?
62
62
  AND ${w}
63
- ORDER BY created DESC`).all(e)).map(f)}i(nt,"listResumableRoots");export*from"./tree.js";async function tt(e,n,t){return await p(async a=>{const o=await a.prepare("SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return o===void 0?{kind:"missing"}:n(o)?{kind:"terminal",status:o.status,final_report:o.final_report}:{kind:"ran",result:await t()}})}i(tt,"withFreshTerminalGuard");async function R(e){return await fe(e)}i(R,"hasUnreconciledManagedWorktree");async function J(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||await R(e.node_id)||e.node_id===U()||W(e)?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}i(J,"isCollectible");async function D(e){if(e.length===0)return[];const n=e.map(()=>"?").join(",");return(await(await s()).prepareUncached(`SELECT DISTINCT session_id FROM sessions WHERE node_id IN (${n}) AND session_id IS NOT NULL`).all(...e)).map(({session_id:a})=>a)}i(D,"nodeConversationIds");async function g(e){const n=await s(),t=n.prepare("SELECT 1 FROM sessions WHERE session_id = ? LIMIT 1"),a=n.prepare(`SELECT 1 FROM nodes n WHERE n.fork_source_file LIKE '%\\_' || ? || '.jsonl' ESCAPE '\\'
64
- AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const o of e)if(!(await t.get(o)!==void 0||await a.get(o)!==void 0))try{await re().delete(o)}catch(r){if(!(r instanceof se))throw r}}i(g,"deleteNodeConversations");async function A(e,n){const t=await M(e,n);return t===null||t.deleted_at!==null?!1:(await ve(e,t),!0)}i(A,"deleteNodeObject");async function v(e){return{nodeId:e,app:await N(e)===null?null:await Oe(e)}}i(v,"nodeFiles");async function Y({nodeId:e,app:n}){n!==null&&j(C(n).nodes,await Le(e,n)),j(ae(H(e)),H(e))}i(Y,"removeNodeAppTrees");function Q({nodeId:e}){return[he(e)]}i(Q,"nodeOwnedDirs");function V({nodeId:e,app:n}){if(n!==null)try{ee(I(C(n).conversations,e))}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}i(V,"removeNodeConversationDir");async function k(e){await Y(e);for(const n of Q(e))ne(n,{recursive:!0,force:!0});V(e)}i(k,"removeNodeFiles");async function at(e){if(await R(e))return{deleted:!1};const n=await v(e),t=await D([e]),a=await p(async o=>(await A(o,e),{deleted:!0}));return await g(t),await k(n),a}i(at,"deleteNode");async function it(e){const n=[...new Set(e)];if(n.length===0)return[];const t=await y(n,R);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const a=await O(n,v),o=await D(n),r=n.map(()=>"?").join(","),d=(await(await s()).prepareUncached(`SELECT node_id FROM nodes WHERE node_id IN (${r}) ORDER BY created`).all(...n)).map(({node_id:u})=>u),l=await y(d,async u=>await p(async _=>await A(_,u)));await g(o);for(const u of l){const _=a[n.indexOf(u)];await x(_,async()=>await k(_))}return l}i(it,"deleteNodes");async function ot(e){const n=e.dryRun??!1,t=e.includeStale??!1,a=Date.now()-e.ttlDays*864e5,o=new Date(a).toISOString(),r=U()??"",d=await s(),l=i(c=>X(c)<a,"quiet"),u=i(c=>({node_id:c.node_id,status:c.status,created:c.created}),"toPruned"),_=(await y((await d.prepare(`SELECT * FROM node_rows
63
+ ORDER BY created DESC`).all(e)).map(f)}i(at,"listResumableRoots");export*from"./tree.js";async function it(e,n,t){return await p(async a=>{const o=await a.prepare("SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return o===void 0?{kind:"missing"}:n(o)?{kind:"terminal",status:o.status,final_report:o.final_report}:{kind:"ran",result:await t()}})}i(it,"withFreshTerminalGuard");async function R(e){return await Ee(e)}i(R,"hasUnreconciledManagedWorktree");async function Y(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||await R(e.node_id)||e.node_id===x()||W(e)?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}i(Y,"isCollectible");async function D(e){if(e.length===0)return[];const n=e.map(()=>"?").join(",");return(await(await r()).prepareUncached(`SELECT DISTINCT session_id FROM sessions WHERE node_id IN (${n}) AND session_id IS NOT NULL`).all(...e)).map(({session_id:a})=>a)}i(D,"nodeConversationIds");async function g(e){const n=await r(),t=n.prepare("SELECT 1 FROM sessions WHERE session_id = ? LIMIT 1"),a=n.prepare(`SELECT 1 FROM nodes n WHERE n.fork_source_file LIKE '%\\_' || ? || '.jsonl' ESCAPE '\\'
64
+ AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const o of e)if(!(await t.get(o)!==void 0||await a.get(o)!==void 0))try{await se().delete(o)}catch(s){if(!(s instanceof de))throw s}}i(g,"deleteNodeConversations");async function A(e,n){const t=await M(e,n);return t===null||t.deleted_at!==null?!1:(await ke(e,t),!0)}i(A,"deleteNodeObject");async function v(e){return{nodeId:e,app:await N(e)===null?null:await Te(e)}}i(v,"nodeFiles");async function Q({nodeId:e,app:n}){n!==null&&j(H(n).nodes,await De(e,n)),j(ie(C(e)),C(e))}i(Q,"removeNodeAppTrees");function V({nodeId:e}){return[Oe(e)]}i(V,"nodeOwnedDirs");function K({nodeId:e,app:n}){if(n!==null)try{ne(I(H(n).conversations,e))}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}i(K,"removeNodeConversationDir");async function k(e){await Q(e);for(const n of V(e))te(n,{recursive:!0,force:!0});K(e)}i(k,"removeNodeFiles");async function ot(e){if(await R(e))return{deleted:!1};const n=await v(e),t=await D([e]),a=await p(async o=>(await A(o,e),{deleted:!0}));return await g(t),await k(n),a}i(ot,"deleteNode");async function rt(e){const n=[...new Set(e)];if(n.length===0)return[];const t=await y(n,R);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const a=await O(n,v),o=await D(n),s=n.map(()=>"?").join(","),d=(await(await r()).prepareUncached(`SELECT node_id FROM nodes WHERE node_id IN (${s}) ORDER BY created`).all(...n)).map(({node_id:u})=>u),l=await y(d,async u=>await p(async _=>await A(_,u)));await g(o);for(const u of l){const _=a[n.indexOf(u)];await U(_,async()=>await k(_))}return l}i(rt,"deleteNodes");async function st(e){const n=e.dryRun??!1,t=e.includeStale??!1,a=Date.now()-e.ttlDays*864e5,o=new Date(a).toISOString(),s=x()??"",d=await r(),l=i(c=>Z(c)<a,"quiet"),u=i(c=>({node_id:c.node_id,status:c.status,created:c.created}),"toPruned"),_=(await y((await d.prepare(`SELECT * FROM node_rows
65
65
  WHERE status IN ('dead', 'done', 'canceled') AND created < ?
66
- ORDER BY created`).all(o)).map(f),async c=>await J(c,{pastTtl:!0})&&l(c)&&!await e.held(c.node_id))).map(u),S=t?(await y((await d.prepare(`SELECT * FROM node_rows
66
+ ORDER BY created`).all(o)).map(f),async c=>await Y(c,{pastTtl:!0})&&l(c)&&!await e.held(c.node_id))).map(u),S=t?(await y((await d.prepare(`SELECT * FROM node_rows
67
67
  WHERE status IN ('active', 'idle') AND created < ?
68
- ORDER BY created`).all(o)).map(f),async c=>c.node_id!==r&&!me(c.pi_pid??null)&&(c.frozen_at??null)===null&&(c.respawn_not_before??null)===null&&c.intent!=="idle-release"&&!W(c)&&!await de(c.node_id)&&!await R(c.node_id)&&l(c)&&!await e.held(c.node_id))).map(u):[],m=await K([..._,...S]);return n||m.length===0?{pruned:m,dryRun:n}:(await G(m,e.removeDirs),{pruned:m,dryRun:n})}i(ot,"pruneNodes");async function K(e){const t=(await s()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ?"),a=new Set(e.map(o=>o.node_id));return await y(e,async o=>(await t.all(o.node_id,o.node_id)).every(r=>a.has(r.node_id)))}i(K,"retainRunRootsWithMembers");async function G(e,n){if(e.length===0)return;const t=await O(e,async o=>await v(o.node_id)),a=await D(e.map(o=>o.node_id));for(const o of e)await p(async r=>await A(r,o.node_id));if(await g(a),n!==void 0){for(const o of t)await x(o,async()=>{await Y(o),V(o)});n(t.flatMap(Q));return}for(const o of t)await x(o,async()=>await k(o))}i(G,"deletePrunedNodes");async function x(e,n){try{n()}catch(t){oe({level:"error",event:"canvas.node_files.remove_failed",error:t,fields:{node_id:e.nodeId}})}}i(x,"eachNodeBestEffort");function X(e){let n=0;for(const t of[e.created,e.launched_at,e.last_settled_at,e.finalized_at,e.outcome_at,e.last_activity_at]){if(t==null)continue;const a=Date.parse(t);Number.isFinite(a)&&a>n&&(n=a)}try{const t=te(I(Se(e.node_id),"telemetry.json"),{throwIfNoEntry:!1});t!==void 0&&t.mtimeMs>n&&(n=t.mtimeMs)}catch{}return n}i(X,"lastActivityMs");async function rt(e){const n=e.dryRun??!1,t=await We(),a=await y(t,async u=>await J(u)&&!await e.held(u.node_id)),o=t.length-a.length,r=Math.max(0,e.maxNodes-o),d=a.map(u=>({row:u,recency:X(u)})).sort((u,_)=>_.recency-u.recency).slice(r).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created})),l=await K(d);return n||l.length===0?{pruned:l,dryRun:n}:(await G(l),{pruned:l,dryRun:n})}i(rt,"pruneToLimit");export{He as PARKED_RESIDENT_SQL,mn as abandonCreateRequest,ln as assertRunNotDeleting,Mn as browseNodes,Nn as canonicalSessionFile,Zn as childrenOf,Gn as claimWarmSpare,Un as clearFinalReportIfMatches,Fn as clearFrozen,yn as completeCreateRequest,cn as createNode,at as deleteNode,it as deleteNodes,On as dueNodeDeadlines,_n as findCreateRequest,Rn as findNodeBySessionFile,xn as getFinalReport,N as getNode,Sn as getRow,hn as getRowByPane,$n as graphNodes,J as isCollectible,Kn as isWarmSpare,X as lastActivityMs,Jn as listNodeIdentities,We as listNodes,Cn as listNodesByProfile,Bn as listNodesForSupervision,zn as listParkedResidentsWithWakeMail,nt as listResumableRoots,qn as listTerminalPlacementResidue,Vn as listWarmSpares,v as nodeFiles,Fe as nodesForSupervisionSql,fn as pruneExpiredCreateRequests,ot as pruneNodes,rt as pruneToLimit,En as recordCreateRequestNode,jn as recordLaunch,Hn as recordRespawnAttempt,Wn as recordSettledTurn,Yn as registerWarmSpare,k as removeNodeFiles,pn as reserveCreateRequest,wn as reserveCreateRequestNode,Dn as rewriteLocalNodeIdentity,et as rosterNodes,bn as setFrozen,vn as setIntent,Tn as setNodeDeadline,In as setPresence,An as setStatus,Ln as shiftProfileNodeDeadlines,be as terminalPlacementResidueSql,kn as transitionStatusIntent,Qn as unregisterWarmSpare,gn as updateNode,Pn as updateNodeTelemetry,Xn as warmSpareCount,tt as withFreshTerminalGuard};
68
+ ORDER BY created`).all(o)).map(f),async c=>c.node_id!==s&&!Ne(c.pi_pid??null)&&(c.frozen_at??null)===null&&(c.respawn_not_before??null)===null&&c.intent!=="idle-release"&&!W(c)&&!await ue(c.node_id)&&!await R(c.node_id)&&l(c)&&!await e.held(c.node_id))).map(u):[],m=await G([..._,...S]);return n||m.length===0?{pruned:m,dryRun:n}:(await X(m,e.removeDirs),{pruned:m,dryRun:n})}i(st,"pruneNodes");async function G(e){const t=(await r()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ?"),a=new Set(e.map(o=>o.node_id));return await y(e,async o=>(await t.all(o.node_id,o.node_id)).every(s=>a.has(s.node_id)))}i(G,"retainRunRootsWithMembers");async function X(e,n){if(e.length===0)return;const t=await O(e,async o=>await v(o.node_id)),a=await D(e.map(o=>o.node_id));for(const o of e)await p(async s=>await A(s,o.node_id));if(await g(a),n!==void 0){for(const o of t)await U(o,async()=>{await Q(o),K(o)});n(t.flatMap(V));return}for(const o of t)await U(o,async()=>await k(o))}i(X,"deletePrunedNodes");async function U(e,n){try{n()}catch(t){re({level:"error",event:"canvas.node_files.remove_failed",error:t,fields:{node_id:e.nodeId}})}}i(U,"eachNodeBestEffort");function Z(e){let n=0;for(const t of[e.created,e.launched_at,e.last_settled_at,e.finalized_at,e.outcome_at,e.last_activity_at]){if(t==null)continue;const a=Date.parse(t);Number.isFinite(a)&&a>n&&(n=a)}try{const t=ae(I(he(e.node_id),"telemetry.json"),{throwIfNoEntry:!1});t!==void 0&&t.mtimeMs>n&&(n=t.mtimeMs)}catch{}return n}i(Z,"lastActivityMs");async function dt(e){const n=e.dryRun??!1,t=await be(),a=await y(t,async u=>await Y(u)&&!await e.held(u.node_id)),o=t.length-a.length,s=Math.max(0,e.maxNodes-o),d=a.map(u=>({row:u,recency:Z(u)})).sort((u,_)=>_.recency-u.recency).slice(s).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created})),l=await G(d);return n||l.length===0?{pruned:l,dryRun:n}:(await X(l),{pruned:l,dryRun:n})}i(dt,"pruneToLimit");export{z as PARKED_RESIDENT_SQL,He as RESUMABLE_NODE_SQL,Nn as abandonCreateRequest,cn as assertRunNotDeleting,Pn as browseNodes,Rn as canonicalSessionFile,nt as childrenOf,Zn as claimWarmSpare,In as clearFinalReportIfMatches,Cn as clearFrozen,mn as completeCreateRequest,_n as createNode,ot as deleteNode,rt as deleteNodes,Tn as dueNodeDeadlines,pn as findCreateRequest,Sn as findNodeBySessionFile,xn as getFinalReport,N as getNode,hn as getRow,On as getRowByPane,qn as graphNodes,Y as isCollectible,Xn as isWarmSpare,Z as lastActivityMs,Qn as listNodeIdentities,be as listNodes,Mn as listNodesByProfile,zn as listNodesForSupervision,Yn as listParkedResidentsWithWakeMail,at as listResumableRoots,Bn as listTerminalPlacementResidue,Gn as listWarmSpares,v as nodeFiles,Ce as nodesForSupervisionSql,En as pruneExpiredCreateRequests,st as pruneNodes,dt as pruneToLimit,wn as recordCreateRequestNode,Wn as recordLaunch,Hn as recordRespawnAttempt,bn as recordSettledTurn,Vn as registerWarmSpare,k as removeNodeFiles,fn as reserveCreateRequest,yn as reserveCreateRequestNode,Jn as resumableNodeCwds,gn as rewriteLocalNodeIdentity,tt as rosterNodes,Fn as setFrozen,kn as setIntent,Ln as setNodeDeadline,jn as setPresence,vn as setStatus,Dn as shiftProfileNodeDeadlines,Fe as terminalPlacementResidueSql,Un as transitionStatusIntent,Kn as unregisterWarmSpare,An as updateNode,$n as updateNodeTelemetry,et as warmSpareCount,it as withFreshTerminalGuard};
@@ -214,8 +214,10 @@ export declare function hasPendingCronWake(nodeId: string): Promise<boolean>;
214
214
  * wakes and leave the deadline armed. Terminal
215
215
  * lifecycle transitions also clear the wait. Standing declarative crons are
216
216
  * untouched. Kills an in-flight run process group first (the cancelCron
217
- * discipline), under one canvas write boundary. Returns removed cron ids. */
218
- export declare function cancelCronsOnWake(anchor_node: string): Promise<string[]>;
217
+ * discipline), under one canvas write boundary. Returns the removed crons. A wake must
218
+ * go through `consumeDeadlineOnWake` (feed/messages.ts), which also tells the
219
+ * node; ending a node calls this directly because nobody is left to tell. */
220
+ export declare function cancelCronsOnWake(anchor_node: string): Promise<Cron[]>;
219
221
  /** UPDATE the next fire time — recurrence advancement. The daemon settles a
220
222
  * recurring row to its next slot BEFORE enacting the run (crash-safe). */
221
223
  export declare function advanceCron(cron_id: string, nextFireIso: string): Promise<void>;
@@ -11,7 +11,7 @@ var f=Object.defineProperty;var a=(n,r)=>f(n,"name",{value:r,configurable:!0});i
11
11
  run_state = 'running'
12
12
  OR (run_state = 'idle' AND state = 'active' AND (expires_at IS NULL OR expires_at > ?))
13
13
  )
14
- )`).all(n,new Date().toISOString());for(const e of r){if(e.anchor_node===n&&Number(e.cancel_on_wake)!==0)return!0;const t=p(e.sink);if(t?.kind==="node"&&t.node===n)return!0}return!1}a(j,"hasPendingCronWake");async function q(n){return await c(async r=>{const e=(await r.prepare("SELECT * FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1").all(n)).map(s);for(const t of e)t.run_state==="running"&&_(t),await r.prepare("DELETE FROM crons WHERE cron_id = ?").run(t.cron_id);return e.map(t=>t.cron_id)})}a(q,"cancelCronsOnWake");async function z(n,r){await(await i()).prepare("UPDATE crons SET fire_at = ?, updated = ? WHERE cron_id = ?").run(r,new Date().toISOString(),n)}a(z,"advanceCron");async function G(n){return(await(await i()).prepare(`SELECT * FROM crons
14
+ )`).all(n,new Date().toISOString());for(const e of r){if(e.anchor_node===n&&Number(e.cancel_on_wake)!==0)return!0;const t=p(e.sink);if(t?.kind==="node"&&t.node===n)return!0}return!1}a(j,"hasPendingCronWake");async function q(n){return await c(async r=>{const e=(await r.prepare("SELECT * FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1").all(n)).map(s);for(const t of e)t.run_state==="running"&&_(t),await r.prepare("DELETE FROM crons WHERE cron_id = ?").run(t.cron_id);return e})}a(q,"cancelCronsOnWake");async function z(n,r){await(await i()).prepare("UPDATE crons SET fire_at = ?, updated = ? WHERE cron_id = ?").run(r,new Date().toISOString(),n)}a(z,"advanceCron");async function G(n){return(await(await i()).prepare(`SELECT * FROM crons
15
15
  WHERE state = 'active' AND run_state = 'idle' AND fire_at <= ?
16
16
  ORDER BY fire_at, created, cron_id`).all(n)).map(s).filter(r=>!h(r.profile))}a(G,"dueClockCrons");async function J(n,r,e,t,o=null){const u=await(await i()).prepare(`UPDATE crons
17
17
  SET run_state = 'running', run_started_at = ?, run_pid = NULL, run_pid_identity = NULL,
@@ -39,6 +39,11 @@ export declare function isolatedNodeHome(nodeId: string, grantee: string): strin
39
39
  /** The HOME a node's processes get: its own home in an isolated run, else the app's. */
40
40
  export declare function nodeHome(nodeId: string, grantee: string, isolated: boolean): string;
41
41
  export declare function nodeRunDir(nodeId: string): string;
42
+ /** File the daemon leaves in a node's run folder when its broker was released on purpose (idle-release, park,
43
+ * finish, cancel) and removes when the broker is launched again. A background job's `crtr` call that finds its
44
+ * relay socket gone reads it, without asking the daemon, to tell a release from a restart. */
45
+ export declare const BROKER_RELEASED_MARKER = "broker-released";
46
+ export declare const BROKER_RELAY_GENERATION = "cli-relay-generation";
42
47
  /** The run's scope allow-list as a JSON array, beside `broker-launch.json`. */
43
48
  export declare function scopesFilePath(nodeId: string): string;
44
49
  export declare function contextDir(nodeId: string, grantee?: string): string;
@@ -1 +1 @@
1
- var P=Object.defineProperty;var e=(t,n)=>P(t,"name",{value:n,configurable:!0});import{join as r}from"node:path";import{mkdirSync as c}from"node:fs";import{appSpace as f,runtimeRoot as k,socketDir as m}from"../layout.js";import{envGrantee as R,envNodeId as j}from"../../shared/env.js";import{withDirBeneath as h}from"../spaces/open-beneath.js";function i(){return k()}e(i,"crtrHome");function H(){return r(i(),"canvas.db")}e(H,"canvasDbPath");function B(){return r(i(),"on-disk-migration.lock")}e(B,"onDiskMigrationLockPath");function L(){return r(i(),"on-disk-migrations.json")}e(L,"onDiskMigrationMarkerPath");function O(t){return r(s(t),"view.sock")}e(O,"viewSocketPath");function D(){return r(i(),"nodes")}e(D,"nodesRoot");function w(){return r(i(),"reviews")}e(w,"reviewsRoot");function l(t){return p(t),r(w(),t)}e(l,"reviewDir");function $(t){return r(l(t),"result.json")}e($,"reviewResultPath");function F(t){c(l(t),{recursive:!0,mode:448})}e(F,"ensureReviewDir");function X(){return r(m(),"api.sock")}e(X,"apiSocketPath");function G(){return r(i(),"session-list-cache.json")}e(G,"sessionListCachePath");const b=128;function g(t){return typeof t=="string"&&t!==""&&t!=="."&&t!==".."&&!/[\\/\0]/u.test(t)&&Buffer.byteLength(t,"utf8")<=b}e(g,"isSafeNodeId");function p(t){if(!g(t))throw new TypeError("node_id must be a non-empty path segment of at most 128 UTF-8 bytes")}e(p,"assertSafeNodeId");function a(t){return p(t),r(D(),t)}e(a,"nodeRecordDir");const u=a;function x(t,n){p(t);const o=n??(j()===t?R():void 0);if(!o)throw new Error(`node ${t} has no app assignment`);return r(f(o).nodes,t)}e(x,"nodeAgentDir");function N(t,n){return r(x(t,n),"home")}e(N,"isolatedNodeHome");function J(t,n,o){return o?N(t,n):f(n).home}e(J,"nodeHome");function s(t){return p(t),process.platform==="linux"?r(m(),"nodes",t):r(a(t),"run")}e(s,"nodeRunDir");function U(t){return r(s(t),"scopes.json")}e(U,"scopesFilePath");function _(t,n){return r(x(t,n),"context")}e(_,"contextDir");function Y(t,n,o){return t.replaceAll("$CRTR_CONTEXT_DIR",_(n,o)).replaceAll("$CRTR_NODE_ID",n)}e(Y,"interpolateNodePaths");function S(t){return r(a(t),"job")}e(S,"jobDir");function T(t){return r(s(t),"job")}e(T,"nodeRunJobDir");function q(t){return r(u(t),"messages")}e(q,"messagesDir");function z(t){return r(u(t),"meta.json")}e(z,"nodeMetaPath");function K(t){return r(u(t),"inbox.jsonl")}e(K,"inboxPath");function Q(t){return r(s(t),"situational-context.md")}e(Q,"situationalContextPath");function V(t){return r(u(t),"passive.jsonl")}e(V,"passivePath");function W(t){return r(u(t),"transcript.jsonl")}e(W,"transcriptPath");function Z(t){return r(u(t),"session.ptr")}e(Z,"sessionPtrPath");function I(t,n){const o=x(t,n);c(a(t),{recursive:!0}),c(S(t),{recursive:!0});for(const v of["context","reports","attachments","worktree"])h(f(n).nodes,r(o,v),()=>{},!0);h(s(t),T(t),()=>{},!0)}e(I,"ensureNodeDirs");function tt(){c(D(),{recursive:!0})}e(tt,"ensureHome");export{X as apiSocketPath,H as canvasDbPath,_ as contextDir,i as crtrHome,tt as ensureHome,I as ensureNodeDirs,F as ensureReviewDir,K as inboxPath,Y as interpolateNodePaths,g as isSafeNodeId,N as isolatedNodeHome,S as jobDir,q as messagesDir,x as nodeAgentDir,u as nodeDir,J as nodeHome,z as nodeMetaPath,a as nodeRecordDir,s as nodeRunDir,T as nodeRunJobDir,D as nodesRoot,B as onDiskMigrationLockPath,L as onDiskMigrationMarkerPath,V as passivePath,l as reviewDir,$ as reviewResultPath,w as reviewsRoot,U as scopesFilePath,G as sessionListCachePath,Z as sessionPtrPath,Q as situationalContextPath,W as transcriptPath,O as viewSocketPath};
1
+ var v=Object.defineProperty;var e=(t,n)=>v(t,"name",{value:n,configurable:!0});import{join as r}from"node:path";import{mkdirSync as c}from"node:fs";import{appSpace as f,runtimeRoot as P,socketDir as m}from"../layout.js";import{envGrantee as k,envNodeId as E}from"../../shared/env.js";import{withDirBeneath as h}from"../spaces/open-beneath.js";function i(){return P()}e(i,"crtrHome");function B(){return r(i(),"canvas.db")}e(B,"canvasDbPath");function C(){return r(i(),"on-disk-migration.lock")}e(C,"onDiskMigrationLockPath");function L(){return r(i(),"on-disk-migrations.json")}e(L,"onDiskMigrationMarkerPath");function H(t){return r(u(t),"view.sock")}e(H,"viewSocketPath");function l(){return r(i(),"nodes")}e(l,"nodesRoot");function b(){return r(i(),"reviews")}e(b,"reviewsRoot");function D(t){return p(t),r(b(),t)}e(D,"reviewDir");function K(t){return r(D(t),"result.json")}e(K,"reviewResultPath");function $(t){c(D(t),{recursive:!0,mode:448})}e($,"ensureReviewDir");function F(){return r(m(),"api.sock")}e(F,"apiSocketPath");function G(){return r(i(),"session-list-cache.json")}e(G,"sessionListCachePath");const j=128;function w(t){return typeof t=="string"&&t!==""&&t!=="."&&t!==".."&&!/[\\/\0]/u.test(t)&&Buffer.byteLength(t,"utf8")<=j}e(w,"isSafeNodeId");function p(t){if(!w(t))throw new TypeError("node_id must be a non-empty path segment of at most 128 UTF-8 bytes")}e(p,"assertSafeNodeId");function a(t){return p(t),r(l(),t)}e(a,"nodeRecordDir");const s=a;function x(t,n){p(t);const o=n??(E()===t?k():void 0);if(!o)throw new Error(`node ${t} has no app assignment`);return r(f(o).nodes,t)}e(x,"nodeAgentDir");function _(t,n){return r(x(t,n),"home")}e(_,"isolatedNodeHome");function X(t,n,o){return o?_(t,n):f(n).home}e(X,"nodeHome");function u(t){return p(t),process.platform==="linux"?r(m(),"nodes",t):r(a(t),"run")}e(u,"nodeRunDir");const Y="broker-released",J="cli-relay-generation";function U(t){return r(u(t),"scopes.json")}e(U,"scopesFilePath");function g(t,n){return r(x(t,n),"context")}e(g,"contextDir");function q(t,n,o){return t.replaceAll("$CRTR_CONTEXT_DIR",g(n,o)).replaceAll("$CRTR_NODE_ID",n)}e(q,"interpolateNodePaths");function N(t){return r(a(t),"job")}e(N,"jobDir");function A(t){return r(u(t),"job")}e(A,"nodeRunJobDir");function z(t){return r(s(t),"messages")}e(z,"messagesDir");function Q(t){return r(s(t),"meta.json")}e(Q,"nodeMetaPath");function V(t){return r(s(t),"inbox.jsonl")}e(V,"inboxPath");function W(t){return r(u(t),"situational-context.md")}e(W,"situationalContextPath");function Z(t){return r(s(t),"passive.jsonl")}e(Z,"passivePath");function I(t){return r(s(t),"transcript.jsonl")}e(I,"transcriptPath");function tt(t){return r(s(t),"session.ptr")}e(tt,"sessionPtrPath");function et(t,n){const o=x(t,n);c(a(t),{recursive:!0}),c(N(t),{recursive:!0});for(const R of["context","reports","attachments","worktree"])h(f(n).nodes,r(o,R),()=>{},!0);h(u(t),A(t),()=>{},!0)}e(et,"ensureNodeDirs");function rt(){c(l(),{recursive:!0})}e(rt,"ensureHome");export{J as BROKER_RELAY_GENERATION,Y as BROKER_RELEASED_MARKER,F as apiSocketPath,B as canvasDbPath,g as contextDir,i as crtrHome,rt as ensureHome,et as ensureNodeDirs,$ as ensureReviewDir,V as inboxPath,q as interpolateNodePaths,w as isSafeNodeId,_ as isolatedNodeHome,N as jobDir,z as messagesDir,x as nodeAgentDir,s as nodeDir,X as nodeHome,Q as nodeMetaPath,a as nodeRecordDir,u as nodeRunDir,A as nodeRunJobDir,l as nodesRoot,C as onDiskMigrationLockPath,L as onDiskMigrationMarkerPath,Z as passivePath,D as reviewDir,K as reviewResultPath,b as reviewsRoot,U as scopesFilePath,G as sessionListCachePath,tt as sessionPtrPath,W as situationalContextPath,I as transcriptPath,H as viewSocketPath};
@@ -80,6 +80,13 @@ export declare function admitEpisode(nodeId: string, input: {
80
80
  faultId: string;
81
81
  retry: FaultRetry;
82
82
  }): Promise<boolean>;
83
+ /** Atomically settle only the admitted attempt that rejected its recovery prompt. A newer turn or episode must never be overwritten by its late result. */
84
+ export declare function settleRejectedEpisode(nodeId: string, input: {
85
+ sessionId: string;
86
+ faultId: string;
87
+ fault: FaultRecordInput;
88
+ reopen: boolean;
89
+ }): Promise<boolean>;
83
90
  export declare function reopenEpisode(nodeId: string, input: {
84
91
  sessionId: string;
85
92
  }): Promise<boolean>;
@@ -1,4 +1,4 @@
1
- var se=Object.defineProperty;var o=(e,t)=>se(e,"name",{value:t,configurable:!0});import{prepared as _}from"../sqlite-statements.js";import{randomUUID as I}from"node:crypto";import{existsSync as f,readdirSync as ae,readFileSync as de,realpathSync as ue,statSync as ce}from"node:fs";import{join as N,resolve as _e}from"node:path";import{withCanvasWrite as l,openDb as p}from"./db.js";import{jobDir as pe,nodesRoot as F}from"./paths.js";import{errorClassFromFault as X}from"../fault-classifier.js";import{parseProviderRateLimit as le}from"../provider-failure.js";import{emitEvent as $}from"../events/emit.js";import{operationIdContext as j,validateOperationId as B}from"../events/operation-id.js";const Me=5*6e4,Ee=500,J=["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"],fe=[...J,"broker\u2194crtrd"],ye=["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"],Te=["auto","manual","fatal"],Ne=["sdk","daemon","client"],ge=["pending","admitted","invalidated"];function u(){return new Date().toISOString()}o(u,"now");function C(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(({name:n})=>n))}o(C,"tableColumns");function Le(e){const t=C(e,"executions"),n=[["turn_open_at","TEXT"],["turn_progress_at","TEXT"],["turn_closed_at","TEXT"],["turn_end_reason","TEXT CHECK (turn_end_reason IS NULL OR turn_end_reason IN ('settled', 'teardown-aborted'))"],["exit_diagnostic_json","TEXT"]];for(const[r,i]of n)t.has(r)||e.exec(`ALTER TABLE executions ADD COLUMN ${r} ${i}`)}o(Le,"addExecutionColumns");function me(e){e.exec(`
1
+ var ae=Object.defineProperty;var o=(e,t)=>ae(e,"name",{value:t,configurable:!0});import{prepared as _}from"../sqlite-statements.js";import{randomUUID as I}from"node:crypto";import{existsSync as f,readdirSync as se,readFileSync as de,realpathSync as ue,statSync as ce}from"node:fs";import{join as N,resolve as _e}from"node:path";import{withCanvasWrite as l,openDb as p}from"./db.js";import{jobDir as pe,nodesRoot as C}from"./paths.js";import{errorClassFromFault as B}from"../fault-classifier.js";import{parseProviderRateLimit as le}from"../provider-failure.js";import{emitEvent as J}from"../events/emit.js";import{operationIdContext as K,validateOperationId as Y}from"../events/operation-id.js";const Me=5*6e4,Ee=500,G=["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"],fe=[...G,"broker\u2194crtrd"],ye=["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"],Te=["auto","manual","fatal"],Ne=["sdk","daemon","client"],ge=["pending","admitted","invalidated"];function u(){return new Date().toISOString()}o(u,"now");function H(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(({name:n})=>n))}o(H,"tableColumns");function Le(e){const t=H(e,"executions"),n=[["turn_open_at","TEXT"],["turn_progress_at","TEXT"],["turn_closed_at","TEXT"],["turn_end_reason","TEXT CHECK (turn_end_reason IS NULL OR turn_end_reason IN ('settled', 'teardown-aborted'))"],["exit_diagnostic_json","TEXT"]];for(const[r,i]of n)t.has(r)||e.exec(`ALTER TABLE executions ADD COLUMN ${r} ${i}`)}o(Le,"addExecutionColumns");function me(e){e.exec(`
2
2
  CREATE TABLE IF NOT EXISTS node_faults (
3
3
  fault_id TEXT PRIMARY KEY,
4
4
  node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
@@ -23,4 +23,4 @@ CREATE TABLE IF NOT EXISTS node_faults (
23
23
  );
24
24
  CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_active ON node_faults(node_id) WHERE active = 1;
25
25
  CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_episode ON node_faults(node_id) WHERE episode_state IS NOT NULL;
26
- `)}o(me,"createFaultTable");function g(e,t){return typeof t=="string"&&e.includes(t)}o(g,"contains");function b(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(b,"isRecord");function K(e){if(!b(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const t=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,n=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,s=le(e.ratelimit),d=Array.isArray(e.causes)?e.causes.flatMap(a=>{if(!b(a))return[];const E={...typeof a.message=="string"?{message:a.message}:{},...typeof a.status=="number"&&Number.isFinite(a.status)?{status:a.status}:{},...typeof a.code=="string"||typeof a.code=="number"?{code:a.code}:{},...typeof a.errno=="string"?{errno:a.errno}:{},...typeof a.body=="string"?{body:a.body}:{}};return Object.keys(E).length===0?[]:[E]}):void 0;return{provider:e.provider,model:e.model,...t===void 0?{}:{status:t},...n===void 0?{}:{code:n},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...d===void 0||d.length===0?{}:{causes:d},...s===void 0?{}:{ratelimit:s}}}o(K,"parseProviderError");function Y(e){try{const t=JSON.parse(e);if(!g(fe,t.link)||typeof t.op!="string"||t.op===""||!g(ye,t.kind)||typeof t.message!="string"||typeof t.since!="string")return null;const n=B(t.operation_id);if(!b(t.retry)||!g(Te,t.retry.disposition)||t.retry.by!==void 0&&!g(Ne,t.retry.by)||t.retry.attempt!==void 0&&typeof t.retry.attempt!="number"||t.retry.max!==void 0&&typeof t.retry.max!="number"||t.retry.nextAt!==void 0&&typeof t.retry.nextAt!="string"||t.anchorEntryId!==void 0&&(typeof t.anchorEntryId!="string"||t.anchorEntryId===""))return null;const r=t.providerError===void 0?void 0:K(t.providerError);return t.providerError!==void 0&&r===void 0?null:{link:t.link,op:t.op,kind:t.kind,retry:{disposition:t.retry.disposition,...t.retry.by===void 0?{}:{by:t.retry.by},...t.retry.attempt===void 0?{}:{attempt:t.retry.attempt},...t.retry.max===void 0?{}:{max:t.retry.max},...t.retry.nextAt===void 0?{}:{nextAt:t.retry.nextAt}},message:t.message,since:t.since,operation_id:n,...t.anchorEntryId===void 0?{}:{anchorEntryId:t.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(Y,"parseLegacyFault");function Ae(e){const t=_e(e);try{return ue(t)}catch{return t}}o(Ae,"canonicalPath");function Se(e){try{const t=JSON.parse(e);if(!g(ge,t.state)||typeof t.sessionFile!="string"||t.sessionFile==="")return null;const n=JSON.stringify(t.fault),r=Y(n);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=t.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:t.state,sessionFile:Ae(t.sessionFile),fault:r}}catch{return null}}o(Se,"parseLegacyEpisode");function G(e){return e!==void 0?B(e):j.current()??j.fresh(n=>n)}o(G,"resolveOperationId");function xe(e){return e.slice(0,Ee)}o(xe,"clampMessage");function w(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(w,"faultPriority");function q(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(q,"encodeFault");function H(e){const t=e.provider_error_json,n=typeof t=="string"?K(JSON.parse(t)):void 0;if(typeof t=="string"&&n===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...n===void 0?{}:{providerError:n},...typeof e.notified_since=="string"?{notifiedSince:e.notified_since}:{}}}o(H,"hydrateFault");async function L(e,t){const n=await e.prepare("SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(t);return n===void 0?null:H(n)}o(L,"activeFault");function V(e){if(!g(J,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:xe(e.message),since:e.since??u(),operation_id:G(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(V,"storedFault");function Q(e,t){$({level:t.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:t.operation_id,node_id:e,error_class:X(t),fields:{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}})}o(Q,"emitRecordedFault");const z="INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";function Z(e,t,n,r,i){const s=q(n),d=u();return[e,t,s.link,s.op,s.kind,s.message,s.since,s.operationId,s.anchorEntryId,s.retryDisposition,s.retryBy,s.retryAttempt,s.retryMax,s.retryNextAt,s.providerError,r?1:0,i?.state??null,i?.bindingId??null,d,d]}o(Z,"faultInsertParams");async function ee(e,t,n,r,i){const s=I();return await e.prepare(z).run(...Z(s,t,n,r,i)),{...n,faultId:s}}o(ee,"insertFault");async function te(e,t,n,r){const i=q(n);return await e.prepare("UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,u(),t),{...n,faultId:t}}o(te,"updateFault");async function D(e,t){await e.prepare("DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(t)}o(D,"deleteIfUnretained");async function ne(e,t,n,r){const i=await L(e,t);if(i===null){const s=await e.prepare("SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(t);return s!==void 0&&s.link===n.link&&s.kind===n.kind&&s.since===n.since&&s.operation_id===n.operation_id?(await e.prepare("UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(u(),s.fault_id),await te(e,s.fault_id,n)):await ee(e,t,n,!0,r)}if(i.link===n.link&&i.kind===n.kind){const s=n.retry.disposition==="auto"?{...i.retry,...n.retry}:n.retry,d=i.retry.disposition===n.retry.disposition&&(n.retry.disposition!=="fatal"||i.message===n.message),a=d?i.since:n.since,E=await te(e,i.faultId,{...n,since:a,anchorEntryId:n.anchorEntryId??i.anchorEntryId,retry:s},r);return d||await e.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(i.faultId),E}return i.link!==n.link&&w(i)>w(n)?null:(await e.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await D(e,i.faultId),await ee(e,t,n,!0,r))}o(ne,"replaceActiveFault");async function m(e,t,n){return(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(t,n))?.binding_id??null}o(m,"liveBinding");async function Xe(e,t){return await l(async n=>{const r=u();return(await n.prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e)).changes>0?!0:(await n.prepare("UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e)).changes>0})}o(Xe,"openTurn");async function $e(e){return(await(await p()).prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(u(),e)).changes>0}o($e,"recordTurnProgress");async function je(e,t){return await l(async n=>{const r=u(),i=(await n.prepare("UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,t.endReason,e)).changes>0;if(i&&t.endReason==="settled"){const s="(SELECT node_id FROM executions WHERE execution_id = ?)";t.viewerPresent===!0?await n.prepare(`UPDATE nodes SET reply_at = ?, read_at = ? WHERE node_id = ${s}`).run(r,r,e):await n.prepare(`UPDATE nodes SET reply_at = ? WHERE node_id = ${s}`).run(r,e)}return i})}o(je,"closeTurn");async function Be(e){return(await(await p()).prepare("UPDATE nodes SET read_at = ? WHERE node_id = ?").run(u(),e)).changes>0}o(Be,"markNodeRead");async function Je(e,t){if(!Number.isInteger(t.consecutivePasses)||t.consecutivePasses<1||t.routes.length===0||!t.routes.every(n=>n!==""))throw new Error("invalid transport-poison verdict");return(await(await p()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:t.consecutivePasses,routes:t.routes}}),e)).changes>0}o(Je,"recordTransportPoisonVerdict");async function Ke(e){const t=await(await p()).prepare("SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);if(t===void 0||t.exit_diagnostic_json===null)return null;try{const n=JSON.parse(t.exit_diagnostic_json),r=n.transport_poison;return n.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(Ke,"readTransportPoisonVerdict");async function Ye(e){const t=await(await p()).prepare("SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return t===void 0?null:{busy:t.turn_open_at!==null&&t.turn_closed_at===null,progressAt:t.turn_progress_at}}o(Ye,"readLiveTurn");async function Ge(e){const t=await p(),n=await t.prepare("SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY seq DESC LIMIT 1").get(e);if(n===void 0)return null;const r=await t.prepare("SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);return{interrupted:n.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:n.turn_progress_at}}o(Ge,"readInterruptedTurn");async function qe(e){return await(await p()).prepare("SELECT 1 FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL LIMIT 1").get(e)!==void 0}o(qe,"hasAdmittedTurn");async function Ve(e,t){const n=V(t);return Q(e,n),await l(async r=>await ne(r,e,n))}o(Ve,"recordFault");async function Qe(e){return await l(async t=>(await t.prepare("UPDATE node_faults SET notified_since = since, updated_at = ? WHERE fault_id = ?").run(u(),e)).changes>0)}o(Qe,"markFaultNotified");function Re(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="fatal"&&e.notifiedSince!==e.since}o(Re,"isUnnotifiedFatalProviderFault");async function ze(){return(await(await p()).prepare("SELECT f.node_id FROM node_faults f JOIN nodes n ON n.node_id = f.node_id WHERE f.active = 1 AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'fatal' AND (f.notified_since IS NULL OR f.notified_since != f.since) AND n.status IN ('active', 'idle')").all()).map(e=>e.node_id)}o(ze,"listUnnotifiedFatalFaultNodes");let W=null;function Ze(e){W=e}o(Ze,"setFatalFaultAnnouncer");async function et(e,t){const n=await L(await p(),e);return n===null||t?.link!==void 0&&n.link!==t.link?!1:await l(async r=>{const i=await L(r,e);if(i===null||t?.link!==void 0&&i.link!==t.link)return!1;W!==null&&Re(i)&&await W(e);const s=await r.prepare("SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);await r.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),s.episode_state==="pending"&&t?.preserveEpisode!==!0&&await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await D(r,i.faultId);const d=G();return $({level:"info",event:"fault.cleared",operation_id:d,node_id:e,error_class:X(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(et,"clearFault");async function re(e){return await L(await p(),e)}o(re,"readFault");async function tt(e,t){const n=V(t.input);if(n.link!=="pi\u2192provider"||n.retry.disposition!=="auto"||n.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return Q(e,n),await l(async r=>{const i=await m(r,e,t.sessionId);if(i===null)return null;const s=await L(r,e);if(s!==null&&(s.link!==n.link||s.kind!==n.kind)&&w(s)>w(n))return null;const d=await r.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(u(),e);for(const E of d)await D(r,E.fault_id);const a=await ne(r,e,n,{state:"pending",bindingId:i});return a===null?null:(await r.prepare("UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,u(),a.faultId),a)})}o(tt,"recordPendingEpisode");async function nt(e,t){return await l(async n=>{if(await n.prepare("SELECT 1 FROM nodes WHERE node_id = ? AND intent = 'refresh'").get(e)!==void 0)return!1;const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(t.retry.disposition,t.retry.by??null,t.retry.attempt??null,t.retry.max??null,t.retry.nextAt??null,u(),e,t.faultId,r)).changes>0})}o(nt,"admitEpisode");async function rt(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(rt,"reopenEpisode");async function it(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(it,"invalidateEpisode");async function ot(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);if(r===null)return!1;const i=await n.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;await n.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(u(),e,r);for(const s of i)await D(n,s.fault_id);return!0})}o(ot,"clearEpisode");async function st(e){const t=await(await p()).prepare("SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return t===void 0?null:{state:t.episode_state,sessionId:t.session_id,fault:H(t)}}o(st,"readEpisode");async function at(){return(await(await p()).prepare("SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all()).map(t=>({nodeId:t.node_id,sessionId:t.bound_session_id,fault:H(t),updatedAt:t.updated_at}))}o(at,"listPendingProviderRetries");async function dt(e){const t=await re(e)===null;return{async explanation(){if(!t)return null;const n=await re(e);if(n===null||n.link!=="crtr\u2192pi"||n.retry.disposition!=="fatal")return null;const r=n.op.trim(),i=n.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(dt,"beginBootFaultAttempt");function ie(e,t){try{return ce(e).mtime.toISOString()}catch{return t}}o(ie,"markerMtime");function P(e,t){if(!f(e))return null;try{return de(e,"utf8")}catch(n){if(!t)return null;throw new Error(`cannot import recovery input ${e}: ${n.message}`)}}o(P,"legacyFile");function Ie(e,t){return _(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(t)??null}o(Ie,"latestExecution");function we(e,t){const r=C(e,"nodes").has("launched_at")?_(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(t):_(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(t);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${t}`);const i=I();return _(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,t,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(we,"syntheticExecution");function oe(e,t,n,r,i){const s=I();return _(e,z).run(...Z(s,t,n,r,i)),{...n,faultId:s}}o(oe,"insertMigratedFault");function De(e,t,n,r){const i=_(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(n);if(i!==void 0){if(i.node_id!==t)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const s=_(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(t,n);if(s!==void 0)return s.binding_id;const d=_(e,"SELECT created FROM nodes WHERE node_id = ?").get(t);if(d===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${t}`);const a=I();return _(e,"INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, NULL, ?, ?, NULL, NULL, ?, ?, ?)").run(a,t,n,d.created,d.created,u()),a}o(De,"migrationBinding");function ut(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'node_faults'").get()!==void 0&&(C(e,"node_faults").has("notified_since")||e.exec("ALTER TABLE node_faults ADD COLUMN notified_since TEXT"))}o(ut,"addFaultNotifiedSince");function ct(e){if(Le(e),me(e),!f(F()))return;const t=ae(F(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),n=_(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of t){const i=r.name,s=pe(i),d=N(s,"busy"),a=N(s,"clean-abort"),E=N(s,"transport-poison.json"),U=N(s,"fault"),A=N(s,"provider-retry"),O=f(d),h=f(a);if(!O&&!h&&!f(E)&&!f(U)&&!f(A)||!f(N(F(),i,"meta.json"))&&n.get(i)===void 0)continue;const k=P(E,!1),S=P(U,!0),x=P(A,!0);if(!O&&!h&&k===null&&S===null&&x===null)continue;let y=Ie(e,i);if(y===null&&(y=we(e,i)),O){const c=ie(d,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(c,c,y.execution_id)}else if(h){const c=ie(a,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(c,c,c,y.execution_id)}if(k!==null)try{const c=JSON.parse(k);Number.isInteger(c.consecutivePasses)&&c.consecutivePasses>=1&&Array.isArray(c.routes)&&c.routes.length>0&&c.routes.every(M=>typeof M=="string"&&M!=="")&&_(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:c.consecutivePasses,routes:c.routes}}),y.execution_id)}catch{}const R=S===null?null:Y(S);if(S!==null&&R===null)throw new Error(`cannot import recovery fault ${U}`);const T=x===null?null:Se(x);if(x!==null&&T===null)throw new Error(`cannot import provider retry ${A}`);let v=R===null||R.link==="broker\u2194crtrd"?null:oe(e,i,R,!0);if(T!==null){const c=De(e,i,T.sessionFile,A);v!==null&&v.since===T.fault.since?_(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(T.state,c,u(),v.faultId):oe(e,i,T.fault,!1,{state:T.state,bindingId:c})}}}o(ct,"migrateRecoveryWitnesses");export{Me as FAULT_QUIET_MS,ut as addFaultNotifiedSince,nt as admitEpisode,dt as beginBootFaultAttempt,ot as clearEpisode,et as clearFault,je as closeTurn,qe as hasAdmittedTurn,H as hydrateFault,it as invalidateEpisode,at as listPendingProviderRetries,ze as listUnnotifiedFatalFaultNodes,Qe as markFaultNotified,Be as markNodeRead,ct as migrateRecoveryWitnesses,Xe as openTurn,K as parseProviderError,st as readEpisode,re as readFault,Ge as readInterruptedTurn,Ye as readLiveTurn,Ke as readTransportPoisonVerdict,Ve as recordFault,tt as recordPendingEpisode,Je as recordTransportPoisonVerdict,$e as recordTurnProgress,rt as reopenEpisode,Ze as setFatalFaultAnnouncer};
26
+ `)}o(me,"createFaultTable");function g(e,t){return typeof t=="string"&&e.includes(t)}o(g,"contains");function W(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(W,"isRecord");function q(e){if(!W(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const t=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,n=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,a=le(e.ratelimit),d=Array.isArray(e.causes)?e.causes.flatMap(s=>{if(!W(s))return[];const E={...typeof s.message=="string"?{message:s.message}:{},...typeof s.status=="number"&&Number.isFinite(s.status)?{status:s.status}:{},...typeof s.code=="string"||typeof s.code=="number"?{code:s.code}:{},...typeof s.errno=="string"?{errno:s.errno}:{},...typeof s.body=="string"?{body:s.body}:{}};return Object.keys(E).length===0?[]:[E]}):void 0;return{provider:e.provider,model:e.model,...t===void 0?{}:{status:t},...n===void 0?{}:{code:n},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...d===void 0||d.length===0?{}:{causes:d},...a===void 0?{}:{ratelimit:a}}}o(q,"parseProviderError");function V(e){try{const t=JSON.parse(e);if(!g(fe,t.link)||typeof t.op!="string"||t.op===""||!g(ye,t.kind)||typeof t.message!="string"||typeof t.since!="string")return null;const n=Y(t.operation_id);if(!W(t.retry)||!g(Te,t.retry.disposition)||t.retry.by!==void 0&&!g(Ne,t.retry.by)||t.retry.attempt!==void 0&&typeof t.retry.attempt!="number"||t.retry.max!==void 0&&typeof t.retry.max!="number"||t.retry.nextAt!==void 0&&typeof t.retry.nextAt!="string"||t.anchorEntryId!==void 0&&(typeof t.anchorEntryId!="string"||t.anchorEntryId===""))return null;const r=t.providerError===void 0?void 0:q(t.providerError);return t.providerError!==void 0&&r===void 0?null:{link:t.link,op:t.op,kind:t.kind,retry:{disposition:t.retry.disposition,...t.retry.by===void 0?{}:{by:t.retry.by},...t.retry.attempt===void 0?{}:{attempt:t.retry.attempt},...t.retry.max===void 0?{}:{max:t.retry.max},...t.retry.nextAt===void 0?{}:{nextAt:t.retry.nextAt}},message:t.message,since:t.since,operation_id:n,...t.anchorEntryId===void 0?{}:{anchorEntryId:t.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(V,"parseLegacyFault");function Ae(e){const t=_e(e);try{return ue(t)}catch{return t}}o(Ae,"canonicalPath");function Se(e){try{const t=JSON.parse(e);if(!g(ge,t.state)||typeof t.sessionFile!="string"||t.sessionFile==="")return null;const n=JSON.stringify(t.fault),r=V(n);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=t.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:t.state,sessionFile:Ae(t.sessionFile),fault:r}}catch{return null}}o(Se,"parseLegacyEpisode");function Q(e){return e!==void 0?Y(e):K.current()??K.fresh(n=>n)}o(Q,"resolveOperationId");function xe(e){return e.slice(0,Ee)}o(xe,"clampMessage");function w(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(w,"faultPriority");function z(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(z,"encodeFault");function b(e){const t=e.provider_error_json,n=typeof t=="string"?q(JSON.parse(t)):void 0;if(typeof t=="string"&&n===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...n===void 0?{}:{providerError:n},...typeof e.notified_since=="string"?{notifiedSince:e.notified_since}:{}}}o(b,"hydrateFault");async function L(e,t){const n=await e.prepare("SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(t);return n===void 0?null:b(n)}o(L,"activeFault");function P(e){if(!g(G,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:xe(e.message),since:e.since??u(),operation_id:Q(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(P,"storedFault");function M(e,t){J({level:t.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:t.operation_id,node_id:e,error_class:B(t),fields:{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}})}o(M,"emitRecordedFault");const Z="INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";function ee(e,t,n,r,i){const a=z(n),d=u();return[e,t,a.link,a.op,a.kind,a.message,a.since,a.operationId,a.anchorEntryId,a.retryDisposition,a.retryBy,a.retryAttempt,a.retryMax,a.retryNextAt,a.providerError,r?1:0,i?.state??null,i?.bindingId??null,d,d]}o(ee,"faultInsertParams");async function te(e,t,n,r,i){const a=I();return await e.prepare(Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(te,"insertFault");async function D(e,t,n,r){const i=z(n);return await e.prepare("UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,u(),t),{...n,faultId:t}}o(D,"updateFault");async function U(e,t){await e.prepare("DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(t)}o(U,"deleteIfUnretained");async function ne(e,t,n,r){const i=await L(e,t);if(i===null){const a=await e.prepare("SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(t);return a!==void 0&&a.link===n.link&&a.kind===n.kind&&a.since===n.since&&a.operation_id===n.operation_id?(await e.prepare("UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(u(),a.fault_id),await D(e,a.fault_id,n)):await te(e,t,n,!0,r)}if(i.link===n.link&&i.kind===n.kind){const a=n.retry.disposition==="auto"?{...i.retry,...n.retry}:n.retry,d=i.retry.disposition===n.retry.disposition&&(n.retry.disposition!=="fatal"||i.message===n.message),s=d?i.since:n.since,E=await D(e,i.faultId,{...n,since:s,anchorEntryId:n.anchorEntryId??i.anchorEntryId,retry:a},r);return d||await e.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(i.faultId),E}return i.link!==n.link&&w(i)>w(n)?null:(await e.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(e,i.faultId),await te(e,t,n,!0,r))}o(ne,"replaceActiveFault");async function m(e,t,n){return(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(t,n))?.binding_id??null}o(m,"liveBinding");async function Xe(e,t){return await l(async n=>{const r=u();return(await n.prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e)).changes>0?!0:(await n.prepare("UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e)).changes>0})}o(Xe,"openTurn");async function $e(e){return(await(await p()).prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(u(),e)).changes>0}o($e,"recordTurnProgress");async function je(e,t){return await l(async n=>{const r=u(),i=(await n.prepare("UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,t.endReason,e)).changes>0;if(i&&t.endReason==="settled"){const a="(SELECT node_id FROM executions WHERE execution_id = ?)";t.viewerPresent===!0?await n.prepare(`UPDATE nodes SET reply_at = ?, read_at = ? WHERE node_id = ${a}`).run(r,r,e):await n.prepare(`UPDATE nodes SET reply_at = ? WHERE node_id = ${a}`).run(r,e)}return i})}o(je,"closeTurn");async function Be(e){return(await(await p()).prepare("UPDATE nodes SET read_at = ? WHERE node_id = ?").run(u(),e)).changes>0}o(Be,"markNodeRead");async function Je(e,t){if(!Number.isInteger(t.consecutivePasses)||t.consecutivePasses<1||t.routes.length===0||!t.routes.every(n=>n!==""))throw new Error("invalid transport-poison verdict");return(await(await p()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:t.consecutivePasses,routes:t.routes}}),e)).changes>0}o(Je,"recordTransportPoisonVerdict");async function Ke(e){const t=await(await p()).prepare("SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);if(t===void 0||t.exit_diagnostic_json===null)return null;try{const n=JSON.parse(t.exit_diagnostic_json),r=n.transport_poison;return n.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(Ke,"readTransportPoisonVerdict");async function Ye(e){const t=await(await p()).prepare("SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return t===void 0?null:{busy:t.turn_open_at!==null&&t.turn_closed_at===null,progressAt:t.turn_progress_at}}o(Ye,"readLiveTurn");async function Ge(e){const t=await p(),n=await t.prepare("SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY seq DESC LIMIT 1").get(e);if(n===void 0)return null;const r=await t.prepare("SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);return{interrupted:n.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:n.turn_progress_at}}o(Ge,"readInterruptedTurn");async function qe(e){return await(await p()).prepare("SELECT 1 FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL LIMIT 1").get(e)!==void 0}o(qe,"hasAdmittedTurn");async function Ve(e,t){const n=P(t);return M(e,n),await l(async r=>await ne(r,e,n))}o(Ve,"recordFault");async function Qe(e){return await l(async t=>(await t.prepare("UPDATE node_faults SET notified_since = since, updated_at = ? WHERE fault_id = ?").run(u(),e)).changes>0)}o(Qe,"markFaultNotified");function Re(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="fatal"&&e.notifiedSince!==e.since}o(Re,"isUnnotifiedFatalProviderFault");async function ze(){return(await(await p()).prepare("SELECT f.node_id FROM node_faults f JOIN nodes n ON n.node_id = f.node_id WHERE f.active = 1 AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'fatal' AND (f.notified_since IS NULL OR f.notified_since != f.since) AND n.status IN ('active', 'idle')").all()).map(e=>e.node_id)}o(ze,"listUnnotifiedFatalFaultNodes");let X=null;function Ze(e){X=e}o(Ze,"setFatalFaultAnnouncer");async function et(e,t){const n=await L(await p(),e);return n===null||t?.link!==void 0&&n.link!==t.link?!1:await l(async r=>{const i=await L(r,e);if(i===null||t?.link!==void 0&&i.link!==t.link)return!1;X!==null&&Re(i)&&await X(e);const a=await r.prepare("SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);await r.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),a.episode_state==="pending"&&t?.preserveEpisode!==!0&&await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(r,i.faultId);const d=Q();return J({level:"info",event:"fault.cleared",operation_id:d,node_id:e,error_class:B(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(et,"clearFault");async function re(e){return await L(await p(),e)}o(re,"readFault");async function tt(e,t){const n=P(t.input);if(n.link!=="pi\u2192provider"||n.retry.disposition!=="auto"||n.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return M(e,n),await l(async r=>{const i=await m(r,e,t.sessionId);if(i===null)return null;const a=await L(r,e);if(a!==null&&(a.link!==n.link||a.kind!==n.kind)&&w(a)>w(n))return null;const d=await r.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(u(),e);for(const E of d)await U(r,E.fault_id);const s=await ne(r,e,n,{state:"pending",bindingId:i});return s===null?null:(await r.prepare("UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,u(),s.faultId),s)})}o(tt,"recordPendingEpisode");async function nt(e,t){return await l(async n=>{if(await n.prepare("SELECT 1 FROM nodes WHERE node_id = ? AND intent = 'refresh'").get(e)!==void 0)return!1;const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(t.retry.disposition,t.retry.by??null,t.retry.attempt??null,t.retry.max??null,t.retry.nextAt??null,u(),e,t.faultId,r)).changes>0})}o(nt,"admitEpisode");async function rt(e,t){const n=P(t.fault);return await l(async r=>{const i=await m(r,e,t.sessionId);return i===null||(await L(r,e))?.faultId!==t.faultId||await r.prepare("SELECT 1 FROM node_faults WHERE node_id = ? AND fault_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").get(e,t.faultId,i)===void 0?!1:(M(e,n),t.reopen?await D(r,t.faultId,n,{state:"pending",bindingId:i}):(await D(r,t.faultId,n),await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),t.faultId),await r.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(t.faultId)),!0)})}o(rt,"settleRejectedEpisode");async function it(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(it,"reopenEpisode");async function ot(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(ot,"invalidateEpisode");async function at(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);if(r===null)return!1;const i=await n.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;await n.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(u(),e,r);for(const a of i)await U(n,a.fault_id);return!0})}o(at,"clearEpisode");async function st(e){const t=await(await p()).prepare("SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return t===void 0?null:{state:t.episode_state,sessionId:t.session_id,fault:b(t)}}o(st,"readEpisode");async function dt(){return(await(await p()).prepare("SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all()).map(t=>({nodeId:t.node_id,sessionId:t.bound_session_id,fault:b(t),updatedAt:t.updated_at}))}o(dt,"listPendingProviderRetries");async function ut(e){const t=await re(e)===null;return{async explanation(){if(!t)return null;const n=await re(e);if(n===null||n.link!=="crtr\u2192pi"||n.retry.disposition!=="fatal")return null;const r=n.op.trim(),i=n.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(ut,"beginBootFaultAttempt");function ie(e,t){try{return ce(e).mtime.toISOString()}catch{return t}}o(ie,"markerMtime");function $(e,t){if(!f(e))return null;try{return de(e,"utf8")}catch(n){if(!t)return null;throw new Error(`cannot import recovery input ${e}: ${n.message}`)}}o($,"legacyFile");function Ie(e,t){return _(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(t)??null}o(Ie,"latestExecution");function we(e,t){const r=H(e,"nodes").has("launched_at")?_(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(t):_(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(t);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${t}`);const i=I();return _(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,t,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(we,"syntheticExecution");function oe(e,t,n,r,i){const a=I();return _(e,Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(oe,"insertMigratedFault");function De(e,t,n,r){const i=_(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(n);if(i!==void 0){if(i.node_id!==t)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const a=_(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(t,n);if(a!==void 0)return a.binding_id;const d=_(e,"SELECT created FROM nodes WHERE node_id = ?").get(t);if(d===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${t}`);const s=I();return _(e,"INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, NULL, ?, ?, NULL, NULL, ?, ?, ?)").run(s,t,n,d.created,d.created,u()),s}o(De,"migrationBinding");function ct(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'node_faults'").get()!==void 0&&(H(e,"node_faults").has("notified_since")||e.exec("ALTER TABLE node_faults ADD COLUMN notified_since TEXT"))}o(ct,"addFaultNotifiedSince");function _t(e){if(Le(e),me(e),!f(C()))return;const t=se(C(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),n=_(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of t){const i=r.name,a=pe(i),d=N(a,"busy"),s=N(a,"clean-abort"),E=N(a,"transport-poison.json"),O=N(a,"fault"),A=N(a,"provider-retry"),h=f(d),k=f(s);if(!h&&!k&&!f(E)&&!f(O)&&!f(A)||!f(N(C(),i,"meta.json"))&&n.get(i)===void 0)continue;const v=$(E,!1),S=$(O,!0),x=$(A,!0);if(!h&&!k&&v===null&&S===null&&x===null)continue;let y=Ie(e,i);if(y===null&&(y=we(e,i)),h){const c=ie(d,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(c,c,y.execution_id)}else if(k){const c=ie(s,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(c,c,c,y.execution_id)}if(v!==null)try{const c=JSON.parse(v);Number.isInteger(c.consecutivePasses)&&c.consecutivePasses>=1&&Array.isArray(c.routes)&&c.routes.length>0&&c.routes.every(j=>typeof j=="string"&&j!=="")&&_(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:c.consecutivePasses,routes:c.routes}}),y.execution_id)}catch{}const R=S===null?null:V(S);if(S!==null&&R===null)throw new Error(`cannot import recovery fault ${O}`);const T=x===null?null:Se(x);if(x!==null&&T===null)throw new Error(`cannot import provider retry ${A}`);let F=R===null||R.link==="broker\u2194crtrd"?null:oe(e,i,R,!0);if(T!==null){const c=De(e,i,T.sessionFile,A);F!==null&&F.since===T.fault.since?_(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(T.state,c,u(),F.faultId):oe(e,i,T.fault,!1,{state:T.state,bindingId:c})}}}o(_t,"migrateRecoveryWitnesses");export{Me as FAULT_QUIET_MS,ct as addFaultNotifiedSince,nt as admitEpisode,ut as beginBootFaultAttempt,at as clearEpisode,et as clearFault,je as closeTurn,qe as hasAdmittedTurn,b as hydrateFault,ot as invalidateEpisode,dt as listPendingProviderRetries,ze as listUnnotifiedFatalFaultNodes,Qe as markFaultNotified,Be as markNodeRead,_t as migrateRecoveryWitnesses,Xe as openTurn,q as parseProviderError,st as readEpisode,re as readFault,Ge as readInterruptedTurn,Ye as readLiveTurn,Ke as readTransportPoisonVerdict,Ve as recordFault,tt as recordPendingEpisode,Je as recordTransportPoisonVerdict,$e as recordTurnProgress,it as reopenEpisode,Ze as setFatalFaultAnnouncer,rt as settleRejectedEpisode};
@@ -1,4 +1,4 @@
1
- var N=Object.defineProperty;var i=(e,t)=>N(e,"name",{value:t,configurable:!0});import{cancelCronsOnWake as O,getNode as E}from"../canvas/index.js";import{runStructuredRequestEffects as y,settleStructuredRequestIn as R}from"../canvas/structured-requests.js";import{openDb as q,withCanvasWrite as T}from"../canvas/db.js";import{randomUUID as x}from"node:crypto";import{composeNodeOutcomeDocument as F}from"../runtime/outcome-document.js";import{closeNode as M}from"../runtime/close.js";import{put as W}from"../graph/bodies.js";import{writeDocument as z}from"../graph/documents.js";import{asRuntimeWriter as A}from"../graph/spaces/own-memory.js";import{publish as k}from"../graph/events.js";import{nodeObject as v}from"../graph/objects.js";import{readerForNode as L}from"../graph/reader.js";import{endMessageSubscriptions as C}from"../graph/watches.js";import{operationIdContext as D}from"../events/operation-id.js";class H extends Error{static{i(this,"StructuredRequestFinalizationError")}state;constructor(t){super(t==="expired"?"structured_request_expired":"structured_request_settled"),this.state=t}}class h extends Error{static{i(this,"FinalizationError")}code;report;constructor(t,r){super(t),this.code=t,this.report=r}}function j(e){const t=i((r,n=2)=>String(r).padStart(n,"0"),"pad");return`${e.getUTCFullYear()}${t(e.getUTCMonth()+1)}${t(e.getUTCDate())}T${t(e.getUTCHours())}${t(e.getUTCMinutes())}${t(e.getUTCSeconds())}${t(e.getUTCMilliseconds(),3)}`}i(j,"compactTs");function S(e,t=80){const r=e.split(`
2
- `)[0]??"";return r.length>t?`${r.slice(0,t-1)}\u2026`:r}i(S,"firstLine");function B(e){return e.kind==="final"?{event:"report.final"}:e.result!==void 0?{event:"report.result"}:e.kind==="urgent"?{event:"report.update",level:7}:{event:"report.update",level:e.deliveryTier==="deferred"?3:e.deliveryTier==="urgent"?7:5}}i(B,"eventFor");async function U(e,t,r){const n=r.from??t,o=`reports/${j(new Date)}-${x().slice(-8)}-${r.kind}`,u=await v(e,t),c=await v(e,n),{object:d}=await z(e,A(await L(e,n,async()=>[])),{owner:u,kind:"report",name:o,preview:S(r.body)||r.kind,privacy:"public"},r.body),s=`${t}/${o}`,{event:p,level:m}=B(r);await k(e,{event:p,object:u,actor:c,...m===void 0?{}:{level:m},attrs:{},pointer:d.id,messageBody:{kind:r.kind,label:S(r.body),bodyRef:s,...r.disposition===void 0?{}:{disposition:r.disposition}}});const l=(await e.prepare(`SELECT d.destination_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id
1
+ var O=Object.defineProperty;var i=(e,t)=>O(e,"name",{value:t,configurable:!0});import{cancelCronsOnWake as q,getNode as E}from"../canvas/index.js";import{runStructuredRequestEffects as g,settleStructuredRequestIn as R}from"../canvas/structured-requests.js";import{afterCommit as x,openDb as F,withCanvasWrite as k}from"../canvas/db.js";import{brokerRelayGeneration as M,recordBrokerRelease as W}from"../runtime/lifecycle.js";import{randomUUID as z}from"node:crypto";import{composeNodeOutcomeDocument as A}from"../runtime/outcome-document.js";import{closeNode as L}from"../runtime/close.js";import{put as H}from"../graph/bodies.js";import{writeDocument as j}from"../graph/documents.js";import{asRuntimeWriter as B}from"../graph/spaces/own-memory.js";import{publish as T}from"../graph/events.js";import{nodeObject as v}from"../graph/objects.js";import{readerForNode as J}from"../graph/reader.js";import{endMessageSubscriptions as C}from"../graph/watches.js";import{operationIdContext as D}from"../events/operation-id.js";class b extends Error{static{i(this,"StructuredRequestFinalizationError")}state;constructor(t){super(t==="expired"?"structured_request_expired":"structured_request_settled"),this.state=t}}class h extends Error{static{i(this,"FinalizationError")}code;report;constructor(t,r){super(t),this.code=t,this.report=r}}function Y(e){const t=i((r,n=2)=>String(r).padStart(n,"0"),"pad");return`${e.getUTCFullYear()}${t(e.getUTCMonth()+1)}${t(e.getUTCDate())}T${t(e.getUTCHours())}${t(e.getUTCMinutes())}${t(e.getUTCSeconds())}${t(e.getUTCMilliseconds(),3)}`}i(Y,"compactTs");function S(e,t=80){const r=e.split(`
2
+ `)[0]??"";return r.length>t?`${r.slice(0,t-1)}\u2026`:r}i(S,"firstLine");function P(e){return e.kind==="final"?{event:"report.final"}:e.result!==void 0?{event:"report.result"}:e.kind==="urgent"?{event:"report.update",level:7}:{event:"report.update",level:e.deliveryTier==="deferred"?3:e.deliveryTier==="urgent"?7:5}}i(P,"eventFor");async function U(e,t,r){const n=r.from??t,o=`reports/${Y(new Date)}-${z().slice(-8)}-${r.kind}`,u=await v(e,t),c=await v(e,n),{object:d}=await j(e,B(await J(e,n,async()=>[])),{owner:u,kind:"report",name:o,preview:S(r.body)||r.kind,privacy:"public"},r.body),s=`${t}/${o}`,{event:p,level:m}=P(r);await T(e,{event:p,object:u,actor:c,...m===void 0?{}:{level:m},attrs:{},pointer:d.id,messageBody:{kind:r.kind,label:S(r.body),bodyRef:s,...r.disposition===void 0?{}:{disposition:r.disposition}}});const l=(await e.prepare(`SELECT d.destination_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id
3
3
  JOIN objects receiver ON receiver.id = d.destination_id
4
- WHERE m.body_ref = ? AND receiver.type = 'node' ORDER BY d.destination_id`).all(s)).map(w=>w.destination_id);return r.kind==="final"?await C(e,u,"final"):r.result?.requestMessageId&&await C(e,u,{result:r.result.requestMessageId}),{name:o,ref:s,doc:d,createdAt:d.created_at,deliveredTo:l}}i(U,"writeReport");async function J(e,t){return T(async r=>{const n=await r.prepare("SELECT status, final_report FROM nodes WHERE node_id = ?").get(e);if(n===void 0)throw new h("unknown_node");const o=t.outcome;let u;if(o?.structured!==void 0){const a=await R(r,o.structured.requestId,o.structured.declined===void 0?{intended:"completed",result:o.structured.value}:{intended:"declined",declined:o.structured.declined});if(!a.changed||a.row===null||a.row.state!=="completed"&&a.row.state!=="declined")return{written:void 0,...a.row===null?{}:{structured:a.row},structuredRefused:!0};u=a.row}else{const a=await r.prepareUncached("SELECT request_id FROM structured_requests WHERE node_id = ? AND state = 'pending'").get(e);if(a!==void 0){const f=await R(r,a.request_id,{intended:"failed",failureReason:"finalized"});if(!f.changed||f.row===null||f.row.state!=="failed")return{written:void 0,...f.row===null?{}:{structured:f.row},structuredRefused:!0};u=f.row}}if(n.final_report!==null)throw new h("already_finalized",`${e}/${n.final_report}`);if(n.status!=="active"&&n.status!=="idle"&&n.status!=="done")throw new h("finalization_forbidden");const c=await U(r,e,t),d=await E(e),s=d?.kind!=="human",p=(d?.outcome_revision??0)+1,m=t.outcome?.kind??"result",l=t.outcome?.reason??"finalized",w=t.outcome?.detailJson??null,_=c.createdAt;if(s){const a=d===null?null:await F({node:{...d,status:"done",intent:"done",terminal_reason:l},outcome:{kind:m,reason:l,at:_,revision:p,detailJson:w},finalReport:c.name,...u?.state==="completed"?{structuredResult:u.result}:{}});await r.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = ?, final_report = ?, finalized_at = ?, outcome_kind = ?, outcome_reason = ?, outcome_at = ?, outcome_revision = outcome_revision + 1, outcome_detail_json = ? WHERE node_id = ? AND final_report IS NULL").run(l,c.name,_,m,l,_,w,e),a!==null&&await k(r,{event:"outcome",object:await v(r,e),actor:null,attrs:{revision:p},messageBody:a})}else await r.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = 'finalized', final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL").run(c.name,_,e);return{written:c,...u===void 0?{}:{structured:u}}})}i(J,"commitCanonicalFinal");async function $(e,t){if(!e)throw new Error(`push: empty nodeId (kind=${t.kind}) \u2014 a report must belong to a node`);if(t.kind==="final"&&t.deliveryTier!==void 0)throw new Error("push final does not accept a delivery tier");if(t.kind!=="final"&&t.outcome!==void 0)throw new Error("push outcome is final-only");if(t.kind!=="update"&&t.result!==void 0)throw new Error("a one-off result is an update report");if(W(t.body),t.kind==="final"){const n=await J(e,t);if(n.structuredRefused===!0)throw n.structured!==void 0&&y(n.structured),new H(n.structured?.state??"failed");n.structured!==void 0&&t.outcome?.structured?.skipEffects!==!0&&y(n.structured);const{written:o}=n;if(await O(e),(await E(e))?.run_id===e){const c=await(await q()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(e,e);for(const d of c){const s=await E(d.node_id);s&&s.status!=="done"&&s.status!=="canceled"&&s.status!=="dead"&&await M(d.node_id,{preserveEmpty:!0})}}return{report:o.ref,reportId:o.doc.id,deliveredTo:o.deliveredTo}}const r=await T(async n=>await U(n,e,t));return{report:r.ref,reportId:r.doc.id,deliveredTo:r.deliveredTo}}i($,"pushWithContext");function g(e,t){return D.current()===void 0?D.fresh(()=>$(e,t)):$(e,t)}i(g,"push");async function oe(e,t,r){return g(e,{kind:"update",body:t,...r})}i(oe,"pushUpdate");async function ae(e,t,r){return g(e,{kind:"urgent",body:t,...r})}i(ae,"pushUrgent");async function ue(e,t,r){return g(e,{kind:"final",body:t,...r})}i(ue,"pushFinal");export{h as FinalizationError,H as StructuredRequestFinalizationError,g as push,ue as pushFinal,oe as pushUpdate,ae as pushUrgent};
4
+ WHERE m.body_ref = ? AND receiver.type = 'node' ORDER BY d.destination_id`).all(s)).map(w=>w.destination_id);return r.kind==="final"?await C(e,u,"final"):r.result?.requestMessageId&&await C(e,u,{result:r.result.requestMessageId}),{name:o,ref:s,doc:d,createdAt:d.created_at,deliveredTo:l}}i(U,"writeReport");async function G(e,t){return k(async r=>{const n=await r.prepare("SELECT status, final_report FROM nodes WHERE node_id = ?").get(e);if(n===void 0)throw new h("unknown_node");const o=t.outcome;let u;if(o?.structured!==void 0){const a=await R(r,o.structured.requestId,o.structured.declined===void 0?{intended:"completed",result:o.structured.value}:{intended:"declined",declined:o.structured.declined});if(!a.changed||a.row===null||a.row.state!=="completed"&&a.row.state!=="declined")return{written:void 0,...a.row===null?{}:{structured:a.row},structuredRefused:!0};u=a.row}else{const a=await r.prepareUncached("SELECT request_id FROM structured_requests WHERE node_id = ? AND state = 'pending'").get(e);if(a!==void 0){const f=await R(r,a.request_id,{intended:"failed",failureReason:"finalized"});if(!f.changed||f.row===null||f.row.state!=="failed")return{written:void 0,...f.row===null?{}:{structured:f.row},structuredRefused:!0};u=f.row}}if(n.final_report!==null)throw new h("already_finalized",`${e}/${n.final_report}`);if(n.status!=="active"&&n.status!=="idle"&&n.status!=="done")throw new h("finalization_forbidden");const c=await U(r,e,t),d=await E(e),s=d?.kind!=="human",p=(d?.outcome_revision??0)+1,m=t.outcome?.kind??"result",l=t.outcome?.reason??"finalized",w=t.outcome?.detailJson??null,_=c.createdAt;if(s){const a=d===null?null:await A({node:{...d,status:"done",intent:"done",terminal_reason:l},outcome:{kind:m,reason:l,at:_,revision:p,detailJson:w},finalReport:c.name,...u?.state==="completed"?{structuredResult:u.result}:{}});await r.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = ?, final_report = ?, finalized_at = ?, outcome_kind = ?, outcome_reason = ?, outcome_at = ?, outcome_revision = outcome_revision + 1, outcome_detail_json = ? WHERE node_id = ? AND final_report IS NULL").run(l,c.name,_,m,l,_,w,e),a!==null&&await T(r,{event:"outcome",object:await v(r,e),actor:null,attrs:{revision:p},messageBody:a})}else await r.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = 'finalized', final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL").run(c.name,_,e);const N=M(e);return x(()=>W(e,N)),{written:c,...u===void 0?{}:{structured:u}}})}i(G,"commitCanonicalFinal");async function $(e,t){if(!e)throw new Error(`push: empty nodeId (kind=${t.kind}) \u2014 a report must belong to a node`);if(t.kind==="final"&&t.deliveryTier!==void 0)throw new Error("push final does not accept a delivery tier");if(t.kind!=="final"&&t.outcome!==void 0)throw new Error("push outcome is final-only");if(t.kind!=="update"&&t.result!==void 0)throw new Error("a one-off result is an update report");if(H(t.body),t.kind==="final"){const n=await G(e,t);if(n.structuredRefused===!0)throw n.structured!==void 0&&g(n.structured),new b(n.structured?.state??"failed");n.structured!==void 0&&t.outcome?.structured?.skipEffects!==!0&&g(n.structured);const{written:o}=n;if(await q(e),(await E(e))?.run_id===e){const c=await(await F()).prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(e,e);for(const d of c){const s=await E(d.node_id);s&&s.status!=="done"&&s.status!=="canceled"&&s.status!=="dead"&&await L(d.node_id,{preserveEmpty:!0})}}return{report:o.ref,reportId:o.doc.id,deliveredTo:o.deliveredTo}}const r=await k(async n=>await U(n,e,t));return{report:r.ref,reportId:r.doc.id,deliveredTo:r.deliveredTo}}i($,"pushWithContext");function y(e,t){return D.current()===void 0?D.fresh(()=>$(e,t)):$(e,t)}i(y,"push");async function ce(e,t,r){return y(e,{kind:"update",body:t,...r})}i(ce,"pushUpdate");async function le(e,t,r){return y(e,{kind:"urgent",body:t,...r})}i(le,"pushUrgent");async function fe(e,t,r){return y(e,{kind:"final",body:t,...r})}i(fe,"pushFinal");export{h as FinalizationError,b as StructuredRequestFinalizationError,y as push,fe as pushFinal,ce as pushUpdate,le as pushUrgent};
@@ -65,6 +65,12 @@ export declare function listenDeliveryTier(delivery: ListenDelivery): {
65
65
  urgency: InboxTier;
66
66
  wake: 0 | 1;
67
67
  };
68
+ /** A wake reached `nodeId`: delete its cancel-on-wake deadline and, in the same write, queue a
69
+ * notice naming each deleted deadline so the node knows its timer is gone. The notice is inserted
70
+ * directly rather than through `queueNodeNotice`, so it cancels nothing and a deadline the node
71
+ * arms afterwards survives it. A deadline that fires on its own deletes its row first, so finds
72
+ * nothing here and no notice is queued. */
73
+ export declare function consumeDeadlineOnWake(nodeId: string): Promise<void>;
68
74
  /** Queue one runtime notice to a node's inbox inside the caller's write transaction (no sender). */
69
75
  export declare function queueNodeNotice(db: CanvasDb, nodeId: string, notice: {
70
76
  body: string;