@north-light/cli 0.3.511 → 0.3.513
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +3 -1
- package/dist/api/client.js +3 -3
- package/dist/api/command-manifest/object-kinds.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +12 -0
- package/dist/api/dto/custom-objects.d.ts +1 -0
- package/dist/api/dto/health.d.ts +8 -0
- package/dist/api/dto/objects.d.ts +1 -0
- package/dist/api/routes.d.ts +1 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +12 -0
- package/dist/builtin-memory/crouter-sdk/resources.md +1 -1
- package/dist/clients/attach/chrome/canvas-panels.d.ts +5 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/object-wait.d.ts +4 -0
- package/dist/clients/attach/chrome/object-wait.js +1 -0
- package/dist/clients/attach/chrome/roster.d.ts +3 -0
- package/dist/clients/attach/chrome/roster.js +4 -4
- package/dist/clients/attach/session/editor-inventory.js +2 -2
- package/dist/clients/attach/session/readonly-popup.d.ts +15 -0
- package/dist/clients/attach/session/readonly-popup.js +1 -0
- package/dist/clients/attach/viewer.js +604 -604
- package/dist/commands/custom-object/register.js +1 -1
- package/dist/core/canvas/canvas.d.ts +0 -13
- package/dist/core/canvas/canvas.js +16 -18
- package/dist/core/canvas/migrations.js +40 -22
- package/dist/core/canvas/remote-canvas-source.js +1 -1
- package/dist/core/canvas/render-source.d.ts +1 -1
- package/dist/core/canvas/types.d.ts +0 -4
- package/dist/core/canvas/waits.d.ts +23 -2
- package/dist/core/canvas/waits.js +9 -4
- package/dist/core/graph/custom.d.ts +1 -0
- package/dist/core/graph/custom.js +2 -2
- package/dist/core/graph/events.js +6 -6
- package/dist/core/graph/kinds/custom.d.ts +1 -0
- package/dist/core/graph/kinds/custom.js +1 -1
- package/dist/core/graph/kinds/kind.d.ts +3 -0
- package/dist/core/graph/object-waits.d.ts +11 -0
- package/dist/core/graph/object-waits.js +1 -0
- package/dist/core/human/page-schema.d.ts +1 -1
- package/dist/core/llm/run.js +2 -2
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/stop-guard.js +3 -3
- package/dist/daemon/api/app-listener.js +12 -12
- package/dist/daemon/api/handlers/canvas.js +5 -5
- package/dist/daemon/api/handlers/health.js +3 -3
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/readiness.d.ts +10 -0
- package/dist/daemon/readiness.js +1 -0
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/types.d.ts +1 -0
- package/docs/sdk/release-notes.md +12 -0
- package/docs/sdk/resources.md +1 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var v=Object.defineProperty;var c=(e,r)=>v(e,"name",{value:r,configurable:!0});import{defineLeaf as m}from"../../core/command.js";import{usage as d}from"../../core/errors.js";import{routes as p}from"../../api/routes.js";import{cliClient as f,rethrowAsCliError as h}from"../api-client.js";import{jsonValue as u}from"./shared.js";const O=m({name:"register",description:"register or re-register a custom canvas object",whenToUse:"you have an external service, script or app whose declared events should be visible and watchable on the canvas; use this again to change its catalog or receiver, or rotate its token.",help:{name:"custom-object register",summary:"register or replace a named custom object\u2019s catalog and receiver",params:[{kind:"flag",name:"kind",type:"string",required:!0,constraint:"Dotted event namespace, not a built-in or reserved prefix; events are published as `<kind>.<local event>`."},{kind:"flag",name:"name",type:"string",required:!0,constraint:"Object name unique under its owner and kind."},{kind:"flag",name:"owner",type:"string",required:!1,constraint:"Owner ref (repo, app, person or profile); omitted owner resolves from your current principal."},{kind:"flag",name:"description",type:"string",required:!0,constraint:"Human-readable description of the object."},{kind:"flag",name:"events",type:"string",required:!0,constraint:'JSON object of up to 64 local event names to `{ "level": 1..10, "supersedes"?: boolean }` declarations. These levels cap publishes.'},{kind:"flag",name:"receiver",type:"enum",choices:["queue","url","argv"],required:!1,constraint:"How this object receives watched events. Omit when it will only publish. On re-registration, omission removes the previous receiver and cancels its pending deliveries. Queue is pulled with receive and ack."},{kind:"flag",name:"url",type:"string",required:!1,constraint:"HTTPS receiver URL resolving only to public IP addresses; required exactly when --receiver url. Redirects are not followed."},{kind:"flag",name:"argv",type:"string",required:!1,constraint:"JSON array of nonempty command and arguments; required exactly when --receiver argv. Only a person or node can register an argv receiver."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Absolute working directory for argv; required exactly when --receiver argv."},{kind:"flag",name:"rotate-token",type:"bool",required:!1,constraint:"Issue a replacement publish token; invalidates the previous one. Save the returned token now; it is not shown again."}],output:[{name:"id",type:"string",required:!0,constraint:"Canvas object id."},{name:"name",type:"string",required:!0,constraint:"Resolved object name."},{name:"token",type:"string",required:!1,constraint:"New publish token on creation or rotation only; store securely for callers without owner authority."}],outputKind:"object",effects:["Creates or updates the object and its catalog. Changes publish a configured event; a rotation invalidates its prior token."]},run:c(async e=>{const r=e.receiver,s=e.url,a=e.argv,i=e.cwd;if((r==="url"?s===void 0||a!==void 0||i!==void 0:s!==void 0)||(r==="argv"?a===void 0||i===void 0:a!==void 0||i!==void 0))throw d("receiver flags must match: url needs --url; argv needs --argv and --cwd; queue needs neither",{field:"receiver",next:"Run `crtr custom-object register -h` and supply one receiver shape."});let n;if(r==="queue")n="queue";else if(r==="url")n={url:s};else if(r==="argv"){const t=u("argv",a);if(!Array.isArray(t)||t.length<1||!t.every(l=>typeof l=="string"&&l.length>0))throw d("--argv must be a nonempty JSON array of nonempty strings",{field:"argv",next:"Run `crtr custom-object register -h` for the receiver shape."});n={argv:t,cwd:i}}const o=u("events",e.events);if(o===null||typeof o!="object"||Array.isArray(o))throw d("--events must be a JSON object mapping local event names to declarations",{field:"events",next:"Run `crtr custom-object register -h` for the catalog shape."});const g={kind:e.kind,name:e.name,description:e.description,events:o,...e.owner?{owner:e.owner}:{},...n?{receiver:n}:{},...e.rotateToken?{rotate_token:!0}:{}};try{return{...await f().request("POST",p.customObjects(),g)}}catch(t){h(t)}},"run"),render:c(e=>`<registered id="${e.id}" name="${e.name}">${e.token?`
|
|
1
|
+
var v=Object.defineProperty;var c=(e,r)=>v(e,"name",{value:r,configurable:!0});import{defineLeaf as m}from"../../core/command.js";import{usage as d}from"../../core/errors.js";import{routes as p}from"../../api/routes.js";import{cliClient as f,rethrowAsCliError as h}from"../api-client.js";import{jsonValue as u}from"./shared.js";const O=m({name:"register",description:"register or re-register a custom canvas object",whenToUse:"you have an external service, script or app whose declared events should be visible and watchable on the canvas; use this again to change its catalog or receiver, or rotate its token.",help:{name:"custom-object register",summary:"register or replace a named custom object\u2019s catalog and receiver",params:[{kind:"flag",name:"kind",type:"string",required:!0,constraint:"Dotted event namespace, not a built-in or reserved prefix; events are published as `<kind>.<local event>`."},{kind:"flag",name:"name",type:"string",required:!0,constraint:"Object name unique under its owner and kind."},{kind:"flag",name:"owner",type:"string",required:!1,constraint:"Owner ref (repo, app, person or profile); omitted owner resolves from your current principal."},{kind:"flag",name:"description",type:"string",required:!0,constraint:"Human-readable description of the object."},{kind:"flag",name:"events",type:"string",required:!0,constraint:'JSON object of up to 64 local event names to `{ "level": 1..10, "supersedes"?: boolean, "ends_wait"?: boolean }` declarations. These levels cap publishes; `ends_wait` marks the event that ends a watching node\'s wait on the object.'},{kind:"flag",name:"receiver",type:"enum",choices:["queue","url","argv"],required:!1,constraint:"How this object receives watched events. Omit when it will only publish. On re-registration, omission removes the previous receiver and cancels its pending deliveries. Queue is pulled with receive and ack."},{kind:"flag",name:"url",type:"string",required:!1,constraint:"HTTPS receiver URL resolving only to public IP addresses; required exactly when --receiver url. Redirects are not followed."},{kind:"flag",name:"argv",type:"string",required:!1,constraint:"JSON array of nonempty command and arguments; required exactly when --receiver argv. Only a person or node can register an argv receiver."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Absolute working directory for argv; required exactly when --receiver argv."},{kind:"flag",name:"rotate-token",type:"bool",required:!1,constraint:"Issue a replacement publish token; invalidates the previous one. Save the returned token now; it is not shown again."}],output:[{name:"id",type:"string",required:!0,constraint:"Canvas object id."},{name:"name",type:"string",required:!0,constraint:"Resolved object name."},{name:"token",type:"string",required:!1,constraint:"New publish token on creation or rotation only; store securely for callers without owner authority."}],outputKind:"object",effects:["Creates or updates the object and its catalog. Changes publish a configured event; a rotation invalidates its prior token."]},run:c(async e=>{const r=e.receiver,s=e.url,a=e.argv,i=e.cwd;if((r==="url"?s===void 0||a!==void 0||i!==void 0:s!==void 0)||(r==="argv"?a===void 0||i===void 0:a!==void 0||i!==void 0))throw d("receiver flags must match: url needs --url; argv needs --argv and --cwd; queue needs neither",{field:"receiver",next:"Run `crtr custom-object register -h` and supply one receiver shape."});let n;if(r==="queue")n="queue";else if(r==="url")n={url:s};else if(r==="argv"){const t=u("argv",a);if(!Array.isArray(t)||t.length<1||!t.every(l=>typeof l=="string"&&l.length>0))throw d("--argv must be a nonempty JSON array of nonempty strings",{field:"argv",next:"Run `crtr custom-object register -h` for the receiver shape."});n={argv:t,cwd:i}}const o=u("events",e.events);if(o===null||typeof o!="object"||Array.isArray(o))throw d("--events must be a JSON object mapping local event names to declarations",{field:"events",next:"Run `crtr custom-object register -h` for the catalog shape."});const g={kind:e.kind,name:e.name,description:e.description,events:o,...e.owner?{owner:e.owner}:{},...n?{receiver:n}:{},...e.rotateToken?{rotate_token:!0}:{}};try{return{...await f().request("POST",p.customObjects(),g)}}catch(t){h(t)}},"run"),render:c(e=>`<registered id="${e.id}" name="${e.name}">${e.token?`
|
|
2
2
|
token: ${e.token}
|
|
3
3
|
`:""}</registered>`,"render")});export{O as registerLeaf};
|
|
@@ -253,19 +253,6 @@ export declare function rosterNodes(): RosterRow[];
|
|
|
253
253
|
* last session HERE"), so it never teleports across projects. */
|
|
254
254
|
export declare function listResumableRoots(cwd: string): NodeRow[];
|
|
255
255
|
export * from './tree.js';
|
|
256
|
-
/** Whether a node explicitly awaits a controller that can still deliver. A
|
|
257
|
-
* parent relationship never implies this wait; the node must declare it. */
|
|
258
|
-
export declare function hasLiveMessageWait(nodeId: string): boolean;
|
|
259
|
-
/** Settle an explicit message wait before appending the qualifying delivery.
|
|
260
|
-
* This ordering makes the delivery's one wake observe cleared durable state. */
|
|
261
|
-
export declare function setMessageWait(nodeId: string, controller: string): void;
|
|
262
|
-
/** Append a qualifying delivery and settle its matching wait while holding the
|
|
263
|
-
* canvas write lock. A concurrent `node wait controller` runs before or after this whole
|
|
264
|
-
* boundary, never between the durable inbox append and its compare-and-clear. */
|
|
265
|
-
export declare function deliverAndSettleMessageWait<T>(nodeId: string, from: string | null, deliver: () => T): T;
|
|
266
|
-
/** Write one controller-death notice and settle only the still-current dead
|
|
267
|
-
* wait. The check, notice append, and clear share one canvas write boundary. */
|
|
268
|
-
export declare function settleDeadMessageWait<T>(nodeId: string, controller: string, deliver: () => T): T | null;
|
|
269
256
|
/** The outcome of {@link withFreshTerminalGuard} — exactly one of three
|
|
270
257
|
* tagged states, never conflated:
|
|
271
258
|
* - `'ran'`: the fresh read found a live, non-terminal row and `body` (the
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var Z=Object.defineProperty;var r=(e,n)=>Z(e,"name",{value:n,configurable:!0});import{prepared as
|
|
1
|
+
var Z=Object.defineProperty;var r=(e,n)=>Z(e,"name",{value:n,configurable:!0});import{prepared as d}from"../sqlite-statements.js";import{envNodeId as A}from"../../shared/env.js";import{rmdirSync as ee,rmSync as ne,statSync as te}from"node:fs";import{dirname as oe,join as x,resolve as re}from"node:path";import{removeTreeBeneath as j}from"../spaces/open-beneath.js";import{emitEvent as ie}from"../events/emit.js";import{openDb as a,prepared as W,withCanvasWrite as p}from"./db.js";import{conversationStore as se,ConversationNotFoundError as de}from"../conversation-store/index.js";import{hasUnseenWakeMail as ae}from"./deliveries.js";import{isAppRun as b}from"./app-run.js";import{registerOutcomeAction as F}from"./outcome-actions.js";import{publish as le}from"../graph/events.js";import{nodeObject as ue}from"../graph/objects.js";import{findNodeBySessionFileSql as _e}from"./sessions.js";import{hydrateFault as ce}from"./recovery.js";import{hasUnreconciledWorktree as pe,openWorktree as fe,readWorktree as Ee,worktreeFromRow as me}from"./worktrees.js";import{isPidAlive as Ne,isPidPresent as H,recordedPidLiveness as Re}from"./pid.js";import{ensureHome as ye,jobDir as Se,nodeDir as Oe,nodeRunDir as I}from"./paths.js";import{appForNode as we,ensureNodeDirs as Te,nodeAgentDir as he}from"./node-agent-paths.js";import{appSpace as C}from"../layout.js";import{createObject as Le,getById as U,ownerForGrantee as M,setObjectKind as ge,setObjectName as De}from"../graph/objects.js";import{deleteNodeWithOwned as ve}from"../graph/deletion.js";function m(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}r(m,"jsonValue");function rn(e,n){if(d(e,"SELECT deleting_at FROM nodes WHERE node_id = ?").get(n)?.deleting_at)throw new Error("run is deleting")}r(rn,"assertRunNotDeleting");function ke(e,n){const t=M(n,e.grantee??"app:terminal");Le(n,{id:e.node_id,type:"node",kind:e.kind,owner:t.rowid,privacy:"public",name:e.name,preview:""}),d(n,`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,m(e.persona_ack,"persona_ack"),m(e.review_binding,"review_binding"),m(e.launch,"launch"),m(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)}r(ke,"seedRow");function P(e){if(e.fault_id==null)return null;const n=Object.entries(e).filter(([t])=>t.startsWith("fault_")).map(([t,o])=>[t==="fault_id"?t:t.slice(6),o]);return ce(Object.fromEntries(n))}r(P,"faultFrom");function E(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=H(n.pi_pid),o=P(e);return n.fault=o?.link==="pi\u2192provider"&&o.retry.by==="daemon"&&o.retry.disposition==="auto"&&!t?null:o,n.streaming=e.turn_open_at!==null&&e.turn_closed_at===null&&t,n}r(E,"rowFrom");function q(e,n=Ee(e.node_id)){return{...E(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}}}r(q,"metaFrom");function sn(e,n={}){return ye(),p(t=>{ke(e,t),e.managed_worktree!==void 0&&e.managed_worktree!==null&&fe(e.node_id,e.managed_worktree,t),n.outcomeDelivery!==void 0&&F(t,e.node_id,n.outcomeDelivery),n.withinCreate?.(t,e)}),Te(e.node_id),y(e.node_id)}r(sn,"createNode");function y(e){const n=W(a(),"SELECT * FROM node_rows WHERE node_id = ?").get(e);return n===void 0?null:q(n)}r(y,"getNode");const Ae=1440*60*1e3;function $(e){return{requestKey:e.request_key,nodeId:e.node_id,state:e.state}}r($,"createRequestRecord");function dn(e){const n=a().prepare("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return n===void 0?null:$(n)}r(dn,"findCreateRequest");function an(e){return p(n=>{const t=Date.now();n.prepare("DELETE FROM create_requests WHERE expires_at <= ?").run(t);const o=n.prepare("SELECT request_key, node_id, state FROM create_requests WHERE request_key = ?").get(e);return o!==void 0?$(o):(n.prepare("INSERT INTO create_requests (request_key, node_id, expires_at, state) VALUES (?, NULL, ?, 'reserved')").run(e,t+Ae),{requestKey:e,nodeId:null,state:"reserved"})})}r(an,"reserveCreateRequest");function ln(e=Date.now()){return p(n=>Number(n.prepare("DELETE FROM create_requests WHERE expires_at <= ?").run(e).changes))}r(ln,"pruneExpiredCreateRequests");function un(e,n){p(t=>{t.prepare("UPDATE create_requests SET node_id = ?, state = 'complete' WHERE request_key = ?").run(n,e)})}r(un,"recordCreateRequestNode");function _n(e,n){p(t=>{t.prepare("UPDATE create_requests SET node_id = ?, state = 'reserved' WHERE request_key = ?").run(n,e)})}r(_n,"reserveCreateRequestNode");function cn(e,n){p(t=>{t.prepare("UPDATE create_requests SET state = 'complete' WHERE request_key = ? AND node_id = ?").run(e,n)})}r(cn,"completeCreateRequest");function pn(e,n){p(t=>{if(n===null){t.prepare("DELETE FROM create_requests WHERE request_key = ? AND node_id IS NULL").run(e);return}t.prepare("DELETE FROM create_requests WHERE request_key = ? AND node_id = ?").run(e,n)})}r(pn,"abandonCreateRequest");function fn(e){return re(e)}r(fn,"canonicalSessionFile");function En(e){const n=_e(e);return n===null?null:y(n)}r(En,"findNodeBySessionFile");function mn(e){const n=d(a(),"SELECT * FROM node_rows WHERE node_id = ?").get(e);return n?E(n):null}r(mn,"getRow");function Nn(e){const n=d(a(),"SELECT * FROM node_rows WHERE pane = ?").get(e);return n?E(n):null}r(Nn,"getRowByPane");function Rn(e){return d(a(),`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(E)}r(Rn,"dueNodeDeadlines");function
|
|
5
|
-
WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),i=
|
|
6
|
-
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = 'user:local'`,s=e.prepare(`${o} LIMIT 1`).get()!==void 0?Number(e.prepare(`UPDATE objects SET owner = ? WHERE rowid IN (${o})`).run(M(e,"app:terminal").rowid).changes):0;return Number(
|
|
4
|
+
ORDER BY deadline_at, created, node_id`).all(e).map(E)}r(Rn,"dueNodeDeadlines");function yn(e,n){return Number(d(a(),"UPDATE nodes SET deadline_at = ? WHERE node_id = ?").run(n,e).changes)===1}r(yn,"setNodeDeadline");function Sn(e,n){return!Number.isFinite(n)||n<=0?0:p(t=>{const o=d(t,`SELECT node_id, deadline_at FROM nodes
|
|
5
|
+
WHERE profile_id = ? AND deadline_at IS NOT NULL AND status IN ('active', 'idle')`).all(e),i=d(t,"UPDATE nodes SET deadline_at = ? WHERE node_id = ? AND deadline_at = ?");let s=0;for(const l of o){const c=Date.parse(l.deadline_at);Number.isNaN(c)||(s+=Number(i.run(new Date(c+n).toISOString(),l.node_id,l.deadline_at).changes))}return s})}r(Sn,"shiftProfileNodeDeadlines");function On(e,n,t){const o=`SELECT o.rowid FROM objects o JOIN identities i ON i.object = o.owner
|
|
6
|
+
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = 'user:local'`,s=e.prepare(`${o} LIMIT 1`).get()!==void 0?Number(e.prepare(`UPDATE objects SET owner = ? WHERE rowid IN (${o})`).run(M(e,"app:terminal").rowid).changes):0;return Number(d(e,"UPDATE nodes SET sub = ? WHERE sub = 'user:local'").run(n).changes)+s+Number(d(e,`UPDATE nodes SET sub = ? WHERE sub IS NULL AND node_id IN (
|
|
7
7
|
SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner
|
|
8
|
-
WHERE o.type = 'node' AND i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(n).changes)+Number(
|
|
8
|
+
WHERE o.type = 'node' AND i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(n).changes)+Number(d(e,"UPDATE nodes SET grant_id = NULL WHERE grant_id = ?").run(t).changes)}r(On,"rewriteLocalNodeIdentity");function w(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`)}r(w,"sqlInput");function wn(e,n){const t=[],o=r((s,l=s)=>{Object.prototype.hasOwnProperty.call(n,s)&&t.push([l,w(n[s],s)])},"add");if(o("description"),o("title"),o("icon"),o("cycles"),o("mode"),o("lifecycle"),o("cwd"),o("host_kind"),o("profile_id"),o("parent"),o("spawned_by"),o("creator"),o("fork_from"),o("fork_source_file"),o("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",m(n.persona_ack,"persona_ack")]),Object.prototype.hasOwnProperty.call(n,"review_binding")&&t.push(["review_binding_json",m(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",m(n.scopes,"scopes")]),Object.prototype.hasOwnProperty.call(n,"launch")&&t.push(["launch_config_json",m(n.launch,"launch")]);const i=r(s=>Object.prototype.hasOwnProperty.call(n,s),"has");return p(s=>{const l=U(s,e);if(l===null||l.type!=="node")throw new Error(`unknown node: ${e}`);if(i("name")&&De(s,l,w(n.name,"name")),i("kind")&&ge(s,l,w(n.kind,"kind")),t.length===0)return;if(s.prepare(`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}`)}),y(e)}r(wn,"updateNode");function Tn(e,n){d(a(),"UPDATE nodes SET status = ? WHERE node_id = ?").run(n,e)}r(Tn,"setStatus");function hn(e,n){d(a(),"UPDATE nodes SET intent = ? WHERE node_id = ?").run(n??null,e)}r(hn,"setIntent");function Ln(e,n,t={}){if(t.outcome===void 0){const i=[],s=[];Object.prototype.hasOwnProperty.call(n,"status")&&(i.push("status = ?"),s.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(i.push("intent = ?"),s.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(i.push("terminal_reason = ?"),s.push(n.terminal_reason??null));const l=["node_id = ?"];s.push(e),t.fromStatuses!==void 0&&(l.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),s.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&l.push("final_report IS NULL");const c=a().prepare(`UPDATE nodes SET ${i.join(", ")} WHERE ${l.join(" AND ")}`).run(...s);return Number(c.changes)}const o=t.outcome;return p(i=>{const s=[],l=[];Object.prototype.hasOwnProperty.call(n,"status")&&(s.push("status = ?"),l.push(n.status??null)),Object.prototype.hasOwnProperty.call(n,"intent")&&(s.push("intent = ?"),l.push(n.intent??null)),Object.prototype.hasOwnProperty.call(n,"terminal_reason")&&(s.push("terminal_reason = ?"),l.push(n.terminal_reason??null));const c=r((R,_)=>o.supersede===!0?"?":`CASE WHEN outcome_at IS NULL THEN ? ELSE ${_} END`,"outcomeValue");s.push(`outcome_kind = ${c(o.kind,"outcome_kind")}`,`outcome_reason = ${c(o.reason,"outcome_reason")}`,`outcome_detail_json = ${c(o.detailJson,"outcome_detail_json")}`,`outcome_revision = ${o.supersede===!0?"outcome_revision + 1":"CASE WHEN outcome_at IS NULL THEN outcome_revision + 1 ELSE outcome_revision END"}`,`outcome_at = ${c(o.at,"outcome_at")}`),l.push(o.kind,o.reason,o.detailJson,o.at);const u=["node_id = ?"];l.push(e),t.fromStatuses!==void 0&&(u.push(`status IN (${t.fromStatuses.map(()=>"?").join(", ")})`),l.push(...t.fromStatuses)),t.requireNoFinalReport===!0&&u.push("final_report IS NULL");const f=i.prepare(`UPDATE nodes SET ${s.join(", ")} WHERE ${u.join(" AND ")}`).run(...l);if(Number(f.changes)===0)return 0;const O=d(i,"SELECT outcome_at FROM nodes WHERE node_id = ?").get(e);return(o.supersede===!0||O.outcome_at===o.at)&&o.documentJson!==null&&o.documentJson!==void 0&&le(i,{event:"outcome",object:ue(i,e),actor:null,attrs:{revision:Number(d(i,"SELECT outcome_revision FROM nodes WHERE node_id = ?").get(e).outcome_revision)},messageBody:JSON.parse(o.documentJson)}),Number(f.changes)})}r(Ln,"transitionStatusIntent");function gn(e){return d(a(),"SELECT final_report FROM nodes WHERE node_id = ?").get(e)?.final_report??null}r(gn,"getFinalReport");function Dn(e,n){return d(a(),"UPDATE nodes SET final_report = NULL, finalized_at = NULL WHERE node_id = ? AND final_report = ?").run(e,n).changes>0}r(Dn,"clearFinalReportIfMatches");function vn(e,n){d(a(),'UPDATE nodes SET tmux_session = ?, "window" = ?, pane = ? WHERE node_id = ?').run(n.tmux_session??null,n.window??null,n.pane??null,e)}r(vn,"setPresence");function kn(e,n){d(a(),"UPDATE nodes SET launched_at = ?, frozen_at = NULL, respawn_not_before = NULL WHERE node_id = ?").run(n,e)}r(kn,"recordLaunch");function An(e,n){d(a(),"UPDATE nodes SET last_settled_at = ? WHERE node_id = ?").run(n,e)}r(An,"recordSettledTurn");function xn(e,n){d(a(),"UPDATE nodes SET frozen_at = ? WHERE node_id = ?").run(n,e)}r(xn,"setFrozen");function jn(e){d(a(),"UPDATE nodes SET frozen_at = NULL WHERE node_id = ?").run(e)}r(jn,"clearFrozen");function Wn(e,n){d(a(),"UPDATE nodes SET respawn_failures = ?, respawn_not_before = ? WHERE node_id = ?").run(n.failures,n.notBefore,e)}r(Wn,"recordRespawnAttempt");const N="node_id NOT IN (SELECT node_id FROM warm_pool)",z=["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 xe(e){return e.worktree_state===null?null:me(Object.fromEntries(z.map(n=>[n,e[`worktree_${n}`]])))}r(xe,"worktreeFromProjection");function bn(e){const n=z.map(o=>`w.${o} AS worktree_${o}`).join(", ");return a().prepare(`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).map(o=>q(o,xe(o)))}r(bn,"listNodesByProfile");function Fn(){const e=a();return W(e,`SELECT
|
|
9
9
|
node_id, name, description, kind, mode, lifecycle, status, cwd, profile_id,
|
|
10
10
|
grantee, parent, created, frozen_at, terminal_reason, final_report,
|
|
11
11
|
telemetry_tokens_in, telemetry_updated_at, pi_pid, turn_open_at, turn_closed_at,
|
|
@@ -13,13 +13,13 @@ var Z=Object.defineProperty;var r=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
|
|
|
13
13
|
fault_operation_id, fault_anchor_entry_id, fault_retry_disposition,
|
|
14
14
|
fault_retry_by, fault_retry_attempt, fault_retry_max, fault_retry_next_at,
|
|
15
15
|
fault_provider_error_json
|
|
16
|
-
FROM node_rows WHERE ${N} ORDER BY created`).all().map(E)}r(Fn,"browseNodes");function
|
|
16
|
+
FROM node_rows WHERE ${N} ORDER BY created`).all().map(E)}r(Fn,"browseNodes");function Hn(e,n){d(a(),`UPDATE nodes
|
|
17
17
|
SET telemetry_tokens_in = ?,
|
|
18
18
|
telemetry_context_tokens = COALESCE(?, telemetry_context_tokens),
|
|
19
19
|
telemetry_last_activity = COALESCE(?, telemetry_last_activity),
|
|
20
20
|
telemetry_updated_at = ?
|
|
21
21
|
WHERE node_id = ?
|
|
22
|
-
AND (telemetry_updated_at IS NULL OR telemetry_updated_at < ?)`).run(n.tokensIn,n.contextTokens,n.lastActivity,n.updatedAt,e,n.updatedAt)}r(
|
|
22
|
+
AND (telemetry_updated_at IS NULL OR telemetry_updated_at < ?)`).run(n.tokensIn,n.contextTokens,n.lastActivity,n.updatedAt,e,n.updatedAt)}r(Hn,"updateNodeTelemetry");function In(){return d(a(),`SELECT
|
|
23
23
|
node_id, name, description, cycles, kind, status, frozen_at,
|
|
24
24
|
telemetry_context_tokens, telemetry_last_activity,
|
|
25
25
|
pi_pid, turn_open_at, turn_closed_at,
|
|
@@ -27,14 +27,14 @@ var Z=Object.defineProperty;var r=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
|
|
|
27
27
|
fault_operation_id, fault_anchor_entry_id, fault_retry_disposition,
|
|
28
28
|
fault_retry_by, fault_retry_attempt, fault_retry_max, fault_retry_next_at,
|
|
29
29
|
fault_provider_error_json
|
|
30
|
-
FROM node_rows WHERE ${N} ORDER BY created`).all().map(n=>{const t=n.pi_pid??null,o=
|
|
30
|
+
FROM node_rows WHERE ${N} ORDER BY created`).all().map(n=>{const t=n.pi_pid??null,o=H(t),i=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:i?.link==="pi\u2192provider"&&i.retry.by==="daemon"&&i.retry.disposition==="auto"&&!o?null:i,streaming:n.turn_open_at!==null&&n.turn_closed_at===null&&o}})}r(In,"graphNodes");function je(e){const n=[N],t=[];if(e?.status!==void 0){const i=Array.isArray(e.status)?e.status:[e.status];n.push(`status IN (${i.map(()=>"?").join(",")})`),t.push(...i)}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)"),a().prepare(`SELECT * FROM node_rows WHERE ${n.join(" AND ")} ORDER BY created`).all(...t).map(E)}r(je,"listNodes");const We=`SELECT
|
|
31
31
|
node_id, created, launched_at, last_settled_at, finalized_at,
|
|
32
32
|
outcome_at, last_activity_at, pane, "window", tmux_session
|
|
33
33
|
FROM nodes INDEXED BY idx_nodes_terminal_placement_created
|
|
34
34
|
WHERE ${N}
|
|
35
35
|
AND status IN ('done', 'canceled', 'dead')
|
|
36
36
|
AND (pane IS NOT NULL OR "window" IS NOT NULL OR tmux_session IS NOT NULL)
|
|
37
|
-
ORDER BY created`;function
|
|
37
|
+
ORDER BY created`;function Cn(){return d(a(),We).all()}r(Cn,"listTerminalPlacementResidue");const be=`WITH candidates AS MATERIALIZED (
|
|
38
38
|
SELECT node_id FROM nodes WHERE status IN ('active', 'idle')
|
|
39
39
|
UNION
|
|
40
40
|
SELECT node_id FROM nodes INDEXED BY idx_nodes_supervision_frozen
|
|
@@ -48,18 +48,16 @@ var Z=Object.defineProperty;var r=(e,n)=>Z(e,"name",{value:n,configurable:!0});i
|
|
|
48
48
|
AND v.node_id NOT IN (SELECT node_id FROM warm_pool)
|
|
49
49
|
AND v.kind != 'human'
|
|
50
50
|
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)))
|
|
51
|
-
ORDER BY v.created`;function Un(){return a(
|
|
51
|
+
ORDER BY v.created`;function Un(){return d(a(),be).all().map(E)}r(Un,"listNodesForSupervision");function Mn(){return d(a(),`SELECT node_id, name, created, grantee FROM node_rows WHERE ${N} ORDER BY created`).all()}r(Mn,"listNodeIdentities");function Pn(e,n){p(t=>{d(t,"INSERT OR REPLACE INTO warm_pool (node_id, recipe_key, created) VALUES (?, ?, ?)").run(e,n,new Date().toISOString())})}r(Pn,"registerWarmSpare");function qn(e){return p(n=>d(n,"DELETE FROM warm_pool WHERE node_id = ?").run(e).changes>0)}r(qn,"unregisterWarmSpare");function T(e,n){const t=`SELECT w.node_id AS node_id, w.recipe_key AS recipe_key, w.created AS created,
|
|
52
52
|
n.status AS status, n.pi_pid AS pi_pid, n.pi_pid_identity AS pi_pid_identity
|
|
53
|
-
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?e.prepare(t).all():e.prepare(t).all(n)).map(i=>({node_id:i.node_id,recipe_key:i.recipe_key,created:i.created,status:i.status,pi_pid:i.pi_pid??null,pi_pid_identity:i.pi_pid_identity??null}))}r(
|
|
54
|
-
FROM node_rows WHERE ${N} 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}))}r(Vn,"rosterNodes");function Xn(e){return
|
|
53
|
+
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?e.prepare(t).all():e.prepare(t).all(n)).map(i=>({node_id:i.node_id,recipe_key:i.recipe_key,created:i.created,status:i.status,pi_pid:i.pi_pid??null,pi_pid_identity:i.pi_pid_identity??null}))}r(T,"warmSpareRowsFor");function $n(){return T(a())}r($n,"listWarmSpares");function zn(e){return d(a(),"SELECT 1 FROM warm_pool WHERE node_id = ?").get(e)!==void 0}r(zn,"isWarmSpare");function B(e){return e.status!=="active"&&e.status!=="idle"?!1:Re(e.pi_pid,e.pi_pid_identity)==="alive"}r(B,"spareIsClaimable");function Bn(e,n,t={}){return p(o=>{const i=T(o,e).find(B);return i===void 0||t.requestKey!==void 0&&o.prepare("UPDATE create_requests SET node_id = ?, state = 'warm_claimed' WHERE request_key = ? AND node_id IS NULL").run(i.node_id,t.requestKey).changes===0||d(o,"DELETE FROM warm_pool WHERE node_id = ?").run(i.node_id).changes===0?null:(d(o,"UPDATE nodes SET created = ?, deadline_at = ? WHERE node_id = ?").run(n,t.deadlineAt??null,i.node_id),t.outcomeDelivery!==void 0&&F(o,i.node_id,t.outcomeDelivery),i.node_id)})}r(Bn,"claimWarmSpare");function Jn(e){return T(a(),e).filter(B).length}r(Jn,"warmSpareCount");function Yn(e){return d(a(),"SELECT node_id FROM nodes WHERE parent = ? ORDER BY created").all(e).map(n=>n.node_id)}r(Yn,"childrenOf");function Vn(){return a().prepare(`SELECT node_id, name, kind, mode, lifecycle, status, cwd, host_kind, parent, created
|
|
54
|
+
FROM node_rows WHERE ${N} 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}))}r(Vn,"rosterNodes");function Xn(e){return a().prepare(`SELECT * FROM node_rows
|
|
55
55
|
WHERE parent IS NULL AND kind != 'human'
|
|
56
56
|
AND status IN ('active','idle') AND cwd = ?
|
|
57
57
|
AND ${N}
|
|
58
|
-
ORDER BY created DESC`).all(e).map(E)}r(Xn,"listResumableRoots");export*from"./tree.js";function Gn(e){const
|
|
59
|
-
|
|
60
|
-
WHERE waiter.node_id = ?`).get(e),s=i?.controller_status==="active"||i?.controller_status==="idle";if(i?.waiting_for!==n||s)return null;const l=t();return a(o,"UPDATE nodes SET waiting_for = NULL WHERE node_id = ? AND waiting_for = ? AND waiting_for_generation = ?").run(e,n,i.waiting_for_generation),l})}r(Zn,"settleDeadMessageWait");function et(e,n,t){return p(o=>{const i=a(o,"SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return i===void 0?{kind:"missing"}:n(i)?{kind:"terminal",status:i.status,final_report:i.final_report}:{kind:"ran",result:t()}})}r(et,"withFreshTerminalGuard");function y(e){return pe(e)}r(y,"hasUnreconciledManagedWorktree");function J(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||y(e.node_id)||e.node_id===k()||H(e)?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}r(J,"isCollectible");function T(e){if(e.length===0)return[];const n=e.map(()=>"?").join(",");return d().prepare(`SELECT DISTINCT session_id FROM sessions WHERE node_id IN (${n}) AND session_id IS NOT NULL`).all(...e).map(({session_id:o})=>o)}r(T,"nodeConversationIds");function h(e){const n=d(),t=a(n,"SELECT 1 FROM sessions WHERE session_id = ? LIMIT 1"),o=a(n,`SELECT 1 FROM nodes n WHERE n.fork_source_file LIKE '%\\_' || ? || '.jsonl' ESCAPE '\\'
|
|
61
|
-
AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const i of e)if(!(t.get(i)!==void 0||o.get(i)!==void 0))try{se().delete(i)}catch(s){if(!(s instanceof ae))throw s}}r(h,"deleteNodeConversations");function L(e,n){const t=U(e,n);return t===null||t.deleted_at!==null?!1:(ve(e,t),!0)}r(L,"deleteNodeObject");function D(e){return{nodeId:e,app:R(e)===null?null:ge(e)}}r(D,"nodeFiles");function Y({nodeId:e,app:n}){n!==null&&W(I(n).nodes,Te(e,n)),W(oe(C(e)),C(e))}r(Y,"removeNodeAppTrees");function V({nodeId:e}){return[Se(e)]}r(V,"nodeOwnedDirs");function X({nodeId:e,app:n}){if(n!==null)try{ee(x(I(n).conversations,e))}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}r(X,"removeNodeConversationDir");function v(e){Y(e);for(const n of V(e))ne(n,{recursive:!0,force:!0});X(e)}r(v,"removeNodeFiles");function nt(e){if(y(e))return{deleted:!1};const n=D(e),t=T([e]),o=p(i=>(L(i,e),{deleted:!0}));return h(t),v(n),o}r(nt,"deleteNode");function tt(e){const n=[...new Set(e)];if(n.length===0)return[];const t=n.filter(y);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const o=n.map(D),i=T(n),s=n.map(()=>"?").join(","),c=d().prepare(`SELECT node_id FROM nodes WHERE node_id IN (${s}) ORDER BY created`).all(...n).map(({node_id:u})=>u).filter(u=>p(f=>L(f,u)));h(i);for(const u of c){const f=o[n.indexOf(u)];A(f,()=>v(f))}return c}r(tt,"deleteNodes");function ot(e){const n=e.dryRun??!1,t=e.includeStale??!1,o=Date.now()-e.ttlDays*864e5,i=new Date(o).toISOString(),s=k()??"",l=d(),c=r(_=>K(_)<o,"quiet"),u=r(_=>({node_id:_.node_id,status:_.status,created:_.created}),"toPruned"),f=a(l,`SELECT * FROM node_rows
|
|
58
|
+
ORDER BY created DESC`).all(e).map(E)}r(Xn,"listResumableRoots");export*from"./tree.js";function Gn(e,n,t){return p(o=>{const i=d(o,"SELECT status, final_report, frozen_at FROM nodes WHERE node_id = ?").get(e);return i===void 0?{kind:"missing"}:n(i)?{kind:"terminal",status:i.status,final_report:i.final_report}:{kind:"ran",result:t()}})}r(Gn,"withFreshTerminalGuard");function S(e){return pe(e)}r(S,"hasUnreconciledManagedWorktree");function J(e,n={}){return!["done","dead","canceled"].includes(e.status)||e.pi_pid!==null||e.frozen_at!==null||S(e.node_id)||e.node_id===A()||b(e)?!1:n.pastTtl===!0||!["crashed","stranded",null].includes(e.terminal_reason??null)}r(J,"isCollectible");function h(e){if(e.length===0)return[];const n=e.map(()=>"?").join(",");return a().prepare(`SELECT DISTINCT session_id FROM sessions WHERE node_id IN (${n}) AND session_id IS NOT NULL`).all(...e).map(({session_id:o})=>o)}r(h,"nodeConversationIds");function L(e){const n=a(),t=d(n,"SELECT 1 FROM sessions WHERE session_id = ? LIMIT 1"),o=d(n,`SELECT 1 FROM nodes n WHERE n.fork_source_file LIKE '%\\_' || ? || '.jsonl' ESCAPE '\\'
|
|
59
|
+
AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.node_id = n.node_id) LIMIT 1`);for(const i of e)if(!(t.get(i)!==void 0||o.get(i)!==void 0))try{se().delete(i)}catch(s){if(!(s instanceof de))throw s}}r(L,"deleteNodeConversations");function g(e,n){const t=U(e,n);return t===null||t.deleted_at!==null?!1:(ve(e,t),!0)}r(g,"deleteNodeObject");function D(e){return{nodeId:e,app:y(e)===null?null:we(e)}}r(D,"nodeFiles");function Y({nodeId:e,app:n}){n!==null&&j(C(n).nodes,he(e,n)),j(oe(I(e)),I(e))}r(Y,"removeNodeAppTrees");function V({nodeId:e}){return[Oe(e)]}r(V,"nodeOwnedDirs");function X({nodeId:e,app:n}){if(n!==null)try{ee(x(C(n).conversations,e))}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}r(X,"removeNodeConversationDir");function v(e){Y(e);for(const n of V(e))ne(n,{recursive:!0,force:!0});X(e)}r(v,"removeNodeFiles");function Qn(e){if(S(e))return{deleted:!1};const n=D(e),t=h([e]),o=p(i=>(g(i,e),{deleted:!0}));return L(t),v(n),o}r(Qn,"deleteNode");function Kn(e){const n=[...new Set(e)];if(n.length===0)return[];const t=n.filter(S);if(t.length>0)throw new Error(`refusing to delete nodes with unreconciled managed worktrees: ${t.join(", ")}`);const o=n.map(D),i=h(n),s=n.map(()=>"?").join(","),c=a().prepare(`SELECT node_id FROM nodes WHERE node_id IN (${s}) ORDER BY created`).all(...n).map(({node_id:u})=>u).filter(u=>p(f=>g(f,u)));L(i);for(const u of c){const f=o[n.indexOf(u)];k(f,()=>v(f))}return c}r(Kn,"deleteNodes");function Zn(e){const n=e.dryRun??!1,t=e.includeStale??!1,o=Date.now()-e.ttlDays*864e5,i=new Date(o).toISOString(),s=A()??"",l=a(),c=r(_=>K(_)<o,"quiet"),u=r(_=>({node_id:_.node_id,status:_.status,created:_.created}),"toPruned"),f=d(l,`SELECT * FROM node_rows
|
|
62
60
|
WHERE status IN ('dead', 'done', 'canceled') AND created < ?
|
|
63
|
-
ORDER BY created`).all(i).map(E).filter(_=>J(_,{pastTtl:!0})&&c(_)&&!e.held(_.node_id)).map(u),
|
|
61
|
+
ORDER BY created`).all(i).map(E).filter(_=>J(_,{pastTtl:!0})&&c(_)&&!e.held(_.node_id)).map(u),O=t?d(l,`SELECT * FROM node_rows
|
|
64
62
|
WHERE status IN ('active', 'idle') AND created < ?
|
|
65
|
-
ORDER BY created`).all(i).map(E).filter(_=>_.node_id!==s&&!Ne(_.pi_pid??null)&&(_.frozen_at??null)===null&&(_.respawn_not_before??null)===null&&_.intent!=="idle-release"&&!
|
|
63
|
+
ORDER BY created`).all(i).map(E).filter(_=>_.node_id!==s&&!Ne(_.pi_pid??null)&&(_.frozen_at??null)===null&&(_.respawn_not_before??null)===null&&_.intent!=="idle-release"&&!b(_)&&!ae(_.node_id)&&!S(_.node_id)&&c(_)&&!e.held(_.node_id)).map(u):[],R=G([...f,...O]);return n||R.length===0?{pruned:R,dryRun:n}:(Q(R,e.removeDirs),{pruned:R,dryRun:n})}r(Zn,"pruneNodes");function G(e){const n=a(),t=d(n,"SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ?"),o=new Set(e.map(i=>i.node_id));return e.filter(i=>t.all(i.node_id,i.node_id).every(s=>o.has(s.node_id)))}r(G,"retainRunRootsWithMembers");function Q(e,n){if(e.length===0)return;const t=e.map(i=>D(i.node_id)),o=h(e.map(i=>i.node_id));for(const i of e)p(s=>g(s,i.node_id));if(L(o),n!==void 0){for(const i of t)k(i,()=>{Y(i),X(i)});n(t.flatMap(V));return}for(const i of t)k(i,()=>v(i))}r(Q,"deletePrunedNodes");function k(e,n){try{n()}catch(t){ie({level:"error",event:"canvas.node_files.remove_failed",error:t,fields:{node_id:e.nodeId}})}}r(k,"eachNodeBestEffort");function K(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 o=Date.parse(t);Number.isFinite(o)&&o>n&&(n=o)}try{const t=te(x(Se(e.node_id),"telemetry.json"),{throwIfNoEntry:!1});t!==void 0&&t.mtimeMs>n&&(n=t.mtimeMs)}catch{}return n}r(K,"lastActivityMs");function et(e){const n=e.dryRun??!1,t=je(),o=t.filter(u=>J(u)&&!e.held(u.node_id)),i=t.length-o.length,s=Math.max(0,e.maxNodes-i),l=o.map(u=>({row:u,recency:K(u)})).sort((u,f)=>f.recency-u.recency).slice(s).map(({row:u})=>({node_id:u.node_id,status:u.status,created:u.created})),c=G(l);return n||c.length===0?{pruned:c,dryRun:n}:(Q(c),{pruned:c,dryRun:n})}r(et,"pruneToLimit");export{pn as abandonCreateRequest,rn as assertRunNotDeleting,Fn as browseNodes,fn as canonicalSessionFile,Yn as childrenOf,Bn as claimWarmSpare,Dn as clearFinalReportIfMatches,jn as clearFrozen,cn as completeCreateRequest,sn as createNode,Qn as deleteNode,Kn as deleteNodes,Rn as dueNodeDeadlines,dn as findCreateRequest,En as findNodeBySessionFile,gn as getFinalReport,y as getNode,mn as getRow,Nn as getRowByPane,In as graphNodes,J as isCollectible,zn as isWarmSpare,K as lastActivityMs,Mn as listNodeIdentities,je as listNodes,bn as listNodesByProfile,Un as listNodesForSupervision,Xn as listResumableRoots,Cn as listTerminalPlacementResidue,$n as listWarmSpares,D as nodeFiles,be as nodesForSupervisionSql,ln as pruneExpiredCreateRequests,Zn as pruneNodes,et as pruneToLimit,un as recordCreateRequestNode,kn as recordLaunch,Wn as recordRespawnAttempt,An as recordSettledTurn,Pn as registerWarmSpare,v as removeNodeFiles,an as reserveCreateRequest,_n as reserveCreateRequestNode,On as rewriteLocalNodeIdentity,Vn as rosterNodes,xn as setFrozen,hn as setIntent,yn as setNodeDeadline,vn as setPresence,Tn as setStatus,Sn as shiftProfileNodeDeadlines,We as terminalPlacementResidueSql,Ln as transitionStatusIntent,qn as unregisterWarmSpare,wn as updateNode,Hn as updateNodeTelemetry,Jn as warmSpareCount,Gn as withFreshTerminalGuard};
|
|
@@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS edges (
|
|
|
23
23
|
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(type, to_id);
|
|
24
24
|
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(type, from_id);
|
|
25
25
|
CREATE INDEX IF NOT EXISTS idx_nodes_status ON nodes(status);
|
|
26
|
-
`)}E(Ue,"baselineSchema");function b(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(n=>n.name))}E(b,"tableColumns");function $(e,t,n,o){t.has(n)||(e.exec(o),t.add(n))}E($,"addColumnIfMissing");function
|
|
26
|
+
`)}E(Ue,"baselineSchema");function b(e,t){return new Set(e.prepare(`PRAGMA table_info(${t})`).all().map(n=>n.name))}E(b,"tableColumns");function $(e,t,n,o){t.has(n)||(e.exec(o),t.add(n))}E($,"addColumnIfMissing");function O(e){return b(e,"nodes")}E(O,"nodeColumns");const N=$;function Ce(e){const t=O(e);N(e,t,"intent","ALTER TABLE nodes ADD COLUMN intent TEXT;"),N(e,t,"pi_pid","ALTER TABLE nodes ADD COLUMN pi_pid INTEGER;"),N(e,t,"window","ALTER TABLE nodes ADD COLUMN window TEXT;"),N(e,t,"tmux_session","ALTER TABLE nodes ADD COLUMN tmux_session TEXT;")}E(Ce,"addRuntimeColumns");function Se(e){const t=h();if(!U(t))return;const n=e.prepare('UPDATE nodes SET intent = ?, pi_pid = ?, "window" = ?, tmux_session = ? WHERE node_id = ?');for(const o of k(t)){const T=x(o);if(!U(T))continue;let i;try{i=JSON.parse(M(T,"utf8"))}catch{continue}n.run(i.intent??null,i.pi_pid??null,i.window??null,i.tmux_session??null,o)}}E(Se,"backfillRuntime");function De(e){B(e,3,()=>{if(!(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'edges'").get()!==void 0)){e.exec(`
|
|
27
27
|
CREATE TABLE edges (
|
|
28
28
|
type TEXT NOT NULL,
|
|
29
29
|
from_id TEXT NOT NULL,
|
|
@@ -57,14 +57,14 @@ DROP TABLE edges;
|
|
|
57
57
|
ALTER TABLE edges_new RENAME TO edges;
|
|
58
58
|
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(type, to_id);
|
|
59
59
|
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(type, from_id);
|
|
60
|
-
`);const o=e.prepare("SELECT COUNT(*) AS n FROM edges").get().n;if(o!==n)throw new Error(`edges FK rebuild lost rows: expected ${n} non-orphan edge(s), got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`edges FK rebuild left ${T.length} foreign-key violation(s)`)})}E(De,"edgesForeignKeyCascade");function ge(e){const t=
|
|
60
|
+
`);const o=e.prepare("SELECT COUNT(*) AS n FROM edges").get().n;if(o!==n)throw new Error(`edges FK rebuild lost rows: expected ${n} non-orphan edge(s), got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`edges FK rebuild left ${T.length} foreign-key violation(s)`)})}E(De,"edgesForeignKeyCascade");function ge(e){const t=O(e);N(e,t,"pane","ALTER TABLE nodes ADD COLUMN pane TEXT;")}E(ge,"addPaneColumn");function we(e){e.exec(`
|
|
61
61
|
CREATE TABLE IF NOT EXISTS focuses (
|
|
62
62
|
focus_id TEXT PRIMARY KEY, -- stable internal id for the viewport
|
|
63
63
|
pane TEXT, -- the durable %pane_id realizing the focus
|
|
64
64
|
session TEXT, -- derived cache of the user session (reconciled from pane)
|
|
65
65
|
node_id TEXT NOT NULL UNIQUE -- the node shown; UNIQUE \u2192 a node occupies <=1 focus
|
|
66
66
|
);
|
|
67
|
-
`)}E(
|
|
67
|
+
`)}E(we,"addFocusesTable");function ye(e){e.exec(`
|
|
68
68
|
CREATE TABLE IF NOT EXISTS wakeups (
|
|
69
69
|
wakeup_id TEXT PRIMARY KEY,
|
|
70
70
|
node_id TEXT, -- TARGET + node-anchored cancel anchor; NULL = canvas-detached
|
|
@@ -80,7 +80,7 @@ CREATE INDEX IF NOT EXISTS idx_wakeups_fire ON wakeups(fire_at);
|
|
|
80
80
|
CREATE INDEX IF NOT EXISTS idx_wakeups_node ON wakeups(node_id); -- by-node cancel / list
|
|
81
81
|
CREATE INDEX IF NOT EXISTS idx_wakeups_owner ON wakeups(owner_id); -- by-owner reap (ruling A)
|
|
82
82
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_wakeups_deadline ON wakeups(node_id) WHERE kind = 'deadline';
|
|
83
|
-
`)}E(
|
|
83
|
+
`)}E(ye,"appendWakeupsTable");function ve(e){e.exec(`
|
|
84
84
|
CREATE TABLE IF NOT EXISTS triggers (
|
|
85
85
|
trigger_id TEXT PRIMARY KEY,
|
|
86
86
|
owner_id TEXT NOT NULL,
|
|
@@ -131,12 +131,12 @@ SELECT
|
|
|
131
131
|
FROM wakeups;
|
|
132
132
|
|
|
133
133
|
DROP TABLE wakeups;
|
|
134
|
-
`)}E(ve,"migrateWakeupsToTriggers");function he(e){const t=
|
|
134
|
+
`)}E(ve,"migrateWakeupsToTriggers");function he(e){const t=O(e);N(e,t,"host_kind","ALTER TABLE nodes ADD COLUMN host_kind TEXT;")}E(he,"addHostKindColumn");function xe(e){e.exec(`
|
|
135
135
|
CREATE TABLE IF NOT EXISTS canvas_meta (
|
|
136
136
|
key TEXT PRIMARY KEY,
|
|
137
137
|
value TEXT NOT NULL
|
|
138
138
|
);
|
|
139
|
-
`)}E(xe,"addCanvasMetaTable");function Fe(e){const t=
|
|
139
|
+
`)}E(xe,"addCanvasMetaTable");function Fe(e){const t=O(e);N(e,t,"profile_id","ALTER TABLE nodes ADD COLUMN profile_id TEXT;")}E(Fe,"addProfileIdColumn");function Me(e){const t=O(e);N(e,t,"pi_pid_identity","ALTER TABLE nodes ADD COLUMN pi_pid_identity TEXT;")}E(Me,"addPidIdentityColumn");function ke(e){const t=O(e);N(e,t,"waiting_for","ALTER TABLE nodes ADD COLUMN waiting_for TEXT;")}E(ke,"addMessageWaitColumn");function J(e){const t=O(e);if(t.size===0)return;N(e,t,"final_report","ALTER TABLE nodes ADD COLUMN final_report TEXT;"),N(e,t,"finalized_at","ALTER TABLE nodes ADD COLUMN finalized_at TEXT;");const n=e.prepare("SELECT node_id FROM nodes WHERE status = 'done' AND final_report IS NULL").all(),o=e.prepare("UPDATE nodes SET final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL");for(const{node_id:T}of n){const i=j(h(),T,"reports");if(!U(i))continue;let a=null;for(const c of k(i))if(c.endsWith(".md"))try{const L=M(j(i,c),"utf8"),l=/^---\nnode: [^\n]+\nkind: final\nts: ([^\n]+)\n---\n/.exec(L);if(l===null||Number.isNaN(Date.parse(l[1])))continue;const r={name:c,ts:l[1]};(a===null||r.ts>a.ts||r.ts===a.ts&&r.name>a.name)&&(a=r)}catch{}a!==null&&o.run(a.name,a.ts,T)}}E(J,"addCanonicalFinalColumns");function je(e){const t=h();if(U(t))for(const n of k(t)){const o=x(n);U(o)&&q(o,T=>{const i=T.launch;if(typeof i!="object"||i===null||Array.isArray(i))return!1;const a=i.extensions;if(!Array.isArray(a)||!a.every(L=>typeof L=="string"))return!1;const c=me(a);return c.length===a.length?!1:(i.extensions=c,!0)})}}E(je,"normalizePersistedLaunchExtensions");function He(e){const t=O(e);N(e,t,"waiting_for_generation","ALTER TABLE nodes ADD COLUMN waiting_for_generation INTEGER NOT NULL DEFAULT 0;")}E(He,"addMessageWaitGenerationColumn");function Ge(e){e.exec(`
|
|
140
140
|
CREATE TABLE IF NOT EXISTS consult_outbox (
|
|
141
141
|
node_id TEXT PRIMARY KEY, -- legacy work node id
|
|
142
142
|
dir TEXT NOT NULL, -- legacy ticket directory
|
|
@@ -216,19 +216,19 @@ CREATE INDEX IF NOT EXISTS idx_cron_runs_cron ON cron_runs(cron_id, started);
|
|
|
216
216
|
`)}E(We,"addCronsTables");function g(e){return`'${e.replace(/'/g,`'"'"'`)}'`}E(g,"shellSingleQuote");function Pe(e,t){let n=0;for(;;){const o=`${t}_${n}`;if(!e.split(`
|
|
217
217
|
`).includes(o))return o;n++}}E(Pe,"uniqueHeredocDelimiter");function Q(e,t,n){const o=Pe(t,n);return`${e} <<'${o}'
|
|
218
218
|
${t}
|
|
219
|
-
${o}`}E(Q,"heredocCommand");function Ye(e){if(typeof e!="string")return{};try{const t=JSON.parse(e);return typeof t!="object"||t===null||Array.isArray(t)?{}:t}catch{return{}}}E(Ye,"migrationPayload");function X(e,t,n){const o=e[t];if(typeof o!="string"||o.trim()==="")throw new Error(`trigger ${n} payload requires non-empty ${t}`);return o}E(X,"requiredString");function H(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(H,"optionalString");function
|
|
219
|
+
${o}`}E(Q,"heredocCommand");function Ye(e){if(typeof e!="string")return{};try{const t=JSON.parse(e);return typeof t!="object"||t===null||Array.isArray(t)?{}:t}catch{return{}}}E(Ye,"migrationPayload");function X(e,t,n){const o=e[t];if(typeof o!="string"||o.trim()==="")throw new Error(`trigger ${n} payload requires non-empty ${t}`);return o}E(X,"requiredString");function H(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(H,"optionalString");function w(e,t){const n=e[t];return typeof n=="string"&&n.trim()!==""?n:void 0}E(w,"optionalColumn");function z(e,t,n,o){return Q(`crtr node message send --to ${g(e)} --tier ${g(t)}`,n,`CRTR_MIGRATED_${o.replace(/[^A-Za-z0-9]/g,"_")}`)}E(z,"migratedMessageCommand");function Ke(e,t){return`printf '%s\\n' "$CRTR_GATE_STDOUT" | crtr node message send --to ${g(e)} --tier ${g(t)}`}E(Ke,"migratedGateStdoutMessageCommand");function qe(e,t){const n=[`crtr node new --kind ${g(X(e,"kind",t))}`],o=[["mode","mode"],["cwd","cwd"],["name","name"],["parent","parent"],["worktreeBase","worktree"],["forkFrom","fork-from"],["model","model"],["profile","profile"],["situationalContext","situational-context"]];for(const[i,a]of o){const c=H(e,i);c!==void 0&&n.push(`--${a} ${g(c)}`)}e.root===!0&&n.push("--root");const T=X(e,"prompt",t);return Q(n.join(" "),T,`CRTR_MIGRATED_${t.replace(/[^A-Za-z0-9]/g,"_")}`)}E(qe,"migratedSpawnCommand");const V="migration.v22.skipped";function $e(e){const t=e.prepare("SELECT cwd FROM nodes WHERE parent IS NULL ORDER BY created LIMIT 1").get();return(t!==void 0?w(t,"cwd"):void 0)??process.cwd()}E($e,"ambientMigrationCwd");function Je(e){let t;try{t=e.prepare("SELECT eval_pid FROM triggers WHERE eval_state = 'running' AND eval_pid IS NOT NULL").all()}catch{return}for(const n of t){const o=n.eval_pid;if(!(typeof o!="number"||!Number.isInteger(o)||o<=1))try{process.kill(-o,"SIGTERM")}catch{}}}E(Je,"reapRunningPredicateEvaluations");function Qe(e){const t=[],n=e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'triggers'").get()!==void 0;n&&Je(e);let o=[];if(n)try{o=e.prepare("SELECT * FROM triggers ORDER BY created, trigger_id").all()}catch(a){t.push({trigger_id:"<unreadable table>",reason:`triggers table could not be read: ${a instanceof Error?a.message:String(a)}`})}const T=$e(e),i=e.prepare(`
|
|
220
220
|
INSERT OR REPLACE INTO crons (
|
|
221
221
|
cron_id, name, created_by, command, fire_at, recur, tz, expires_at,
|
|
222
222
|
anchor_node, cancel_on_wake, cwd, env_json, profile, scope,
|
|
223
223
|
run_timeout_s, overlap, on_output, sink, tier, created, updated
|
|
224
|
-
) VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, NULL, ?, 'profile', ?, 'skip', 'on-failure', '{}', ?, ?, ?)`);for(const a of o){const c=
|
|
224
|
+
) VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, NULL, ?, 'profile', ?, 'skip', 'on-failure', '{}', ?, ?, ?)`);for(const a of o){const c=w(a,"trigger_id");if(c===void 0){t.push({trigger_id:"<unidentified row>",reason:"row carries no trigger_id"});continue}try{ze(e,i,a,c,T)}catch(L){t.push({trigger_id:c,reason:L instanceof Error?L.message:String(L)})}}t.length>0&&(e.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(V,JSON.stringify(t)),console.warn(`[canvas migration v22] ${t.length} retired schedule(s) could not be converted to crons and were dropped; see canvas_meta['${V}']: `+t.map(a=>`${a.trigger_id} (${a.reason})`).join("; "))),e.exec(`
|
|
225
225
|
DROP INDEX IF EXISTS idx_triggers_fire;
|
|
226
226
|
DROP INDEX IF EXISTS idx_triggers_node;
|
|
227
227
|
DROP INDEX IF EXISTS idx_triggers_owner;
|
|
228
228
|
DROP INDEX IF EXISTS idx_triggers_eval;
|
|
229
229
|
DROP INDEX IF EXISTS idx_triggers_deadline;
|
|
230
230
|
DROP TABLE IF EXISTS triggers;
|
|
231
|
-
`)}E(Qe,"migrateTriggersToCrons");function ze(e,t,n,o,T){const i=X(n,"owner_id",o),a=e.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(i),c=(a===void 0?void 0:
|
|
231
|
+
`)}E(Qe,"migrateTriggersToCrons");function ze(e,t,n,o,T){const i=X(n,"owner_id",o),a=e.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(i),c=(a===void 0?void 0:w(a,"cwd"))??T,L=a===void 0?null:w(a,"profile_id")??null,l=w(n,"node_id")??null,r=X(n,"action",o),_=X(n,"action_mode",o),d=X(n,"trigger_type",o),u=Ye(n.payload),p=w(n,"created")??new Date().toISOString(),I=_==="deadline_message"?"urgent":H(u,"tier")??"normal",R=H(u,"label");let s,A,m=!1;if(r==="msg"&&(_==="inbox_message"||_==="deadline_message")){if(l===null)throw new Error("has no message target");const f=H(u,"body");f!==void 0?s=z(l,I,f,o):d==="when"?(m=!0,s=Ke(l,I)):s=z(l,I,R??"Scheduled message (no body was recorded when this schedule was armed).",o),A=R??(_==="deadline_message"?"deadline":"scheduled message")}else if(r==="msg"&&_==="fresh_revive"){if(l===null)throw new Error("has no revive target");s=`crtr node lifecycle revive ${g(l)} --fresh`,A=R??"scheduled fresh revive"}else if(r==="new"&&_==="node_birth")s=qe(u,o),A=H(u,"name")??`scheduled ${X(u,"kind",o)} node`;else throw new Error(`has unsupported action ${r}/${_}`);let D,y,G=null;if(d==="when"){D=X(n,"next_eval_at",o),y=X(n,"eval_every",o),G=w(n,"timeout_at")??null;const f=X(n,"when_script",o);s=`${m?`if ! CRTR_GATE_STDOUT="$(
|
|
232
232
|
${f}
|
|
233
233
|
)"; then`:`if ! (
|
|
234
234
|
${f}
|
|
@@ -237,7 +237,7 @@ ${f}
|
|
|
237
237
|
fi
|
|
238
238
|
{
|
|
239
239
|
${s}
|
|
240
|
-
} && crtr cron cancel "$CRTR_CRON_ID"`}else if(d==="at"||d==="every"||d==="until")D=X(n,"fire_at",o),
|
|
240
|
+
} && crtr cron cancel "$CRTR_CRON_ID"`}else if(d==="at"||d==="every"||d==="until")D=X(n,"fire_at",o),y=d==="every"?X(n,"recur",o):null;else throw new Error(`has unknown timing type ${d}`);if(_==="deadline_message"&&l!==null){const f=e.prepare("SELECT cron_id FROM crons WHERE anchor_node = ? AND cancel_on_wake = 1 AND cron_id <> ?").get(l,o);if(f!==void 0)throw new Error(`node ${l} already has a migrated deadline (${String(f.cron_id)}); only one is allowed`)}t.run(o,A,i,s,D,y,G,l,_==="deadline_message"?1:0,c,L,300,I,p,p)}E(ze,"convertTriggerRow");function Ve(e){const t=b(e,"crons");t.size===0||t.has("run_pid_identity")||e.exec("ALTER TABLE crons ADD COLUMN run_pid_identity TEXT;")}E(Ve,"addCronRunPidIdentityColumn");function Ze(e){const t=b(e,"crons");t.size!==0&&(t.has("run_out_of_band")||e.exec("ALTER TABLE crons ADD COLUMN run_out_of_band INTEGER NOT NULL DEFAULT 0;"),t.has("queued")&&e.exec("ALTER TABLE crons DROP COLUMN queued;"))}E(Ze,"addCronOutOfBandColumn");function et(e){e.exec(`
|
|
241
241
|
CREATE TABLE IF NOT EXISTS warm_pool (
|
|
242
242
|
node_id TEXT PRIMARY KEY REFERENCES nodes(node_id) ON DELETE CASCADE,
|
|
243
243
|
recipe_key TEXT NOT NULL, -- frozen launch tuple this spare was minted for
|
|
@@ -378,7 +378,7 @@ CREATE TABLE human_action_deliveries (
|
|
|
378
378
|
updated_at INTEGER NOT NULL
|
|
379
379
|
);
|
|
380
380
|
CREATE INDEX idx_human_action_deliveries_due ON human_action_deliveries(state, next_attempt_at);
|
|
381
|
-
`)}E(Tt,"addHumanActionDeliveries");function at(e){const t=
|
|
381
|
+
`)}E(Tt,"addHumanActionDeliveries");function at(e){const t=O(e);N(e,t,"pi_session_file","ALTER TABLE nodes ADD COLUMN pi_session_file TEXT;");for(const n of k(h(),{withFileTypes:!0}))if(n.isDirectory())try{const o=JSON.parse(M(x(n.name),"utf8"));typeof o.pi_session_file=="string"&&e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?").run(o.pi_session_file,n.name)}catch{}e.exec("CREATE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(at,"addNodeSessionFileIndex");function Z(e,t){const n=E(c=>{const L=Y(c);return U(L)?le(L):L},"canonical"),o=e.prepare("UPDATE nodes SET pi_session_file = ? WHERE node_id = ?");e.exec("DROP INDEX IF EXISTS idx_nodes_pi_session_file;");const T=e.prepare("SELECT node_id FROM nodes ORDER BY created ASC, node_id ASC").all();for(const{node_id:c}of T){const L=x(c);if(K(L)===null){o.run(null,c);continue}const l=fe(L,()=>{const r=K(L);if(r===null)throw new Error(`node ${c} session metadata changed during ownership migration`);if(typeof r.pi_session_file!="string")return null;const _=r.pi_session_file,d=n(_);return d!==_&&(r.pi_session_file=d,Xe(L,r)),d});o.run(l,c)}const i=e.prepare(`
|
|
382
382
|
SELECT pi_session_file
|
|
383
383
|
FROM nodes
|
|
384
384
|
WHERE pi_session_file IS NOT NULL
|
|
@@ -389,7 +389,7 @@ SELECT node_id
|
|
|
389
389
|
FROM nodes
|
|
390
390
|
WHERE pi_session_file = ?
|
|
391
391
|
ORDER BY created ASC, node_id ASC
|
|
392
|
-
`).all(c);for(const{node_id:l}of L.slice(1)){if(!q(x(l),_=>{const d=_.pi_session_file;if(typeof d!="string"||n(d)!==c)throw new Error(`node ${l} session metadata changed during ownership migration`);return _.pi_session_id=null,_.pi_session_file=null,!0}))throw new Error(`node ${l} session metadata changed during ownership migration`);a.run(l)}}e.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(Z,"reconcileNodeSessionFileOwners");function dt(e){Z(e,!0)}E(dt,"makeNodeSessionFileUnique");function _t(e){Z(e,!1)}E(_t,"repairNodeSessionFileUniqueIndex");function ct(e){const t=
|
|
392
|
+
`).all(c);for(const{node_id:l}of L.slice(1)){if(!q(x(l),_=>{const d=_.pi_session_file;if(typeof d!="string"||n(d)!==c)throw new Error(`node ${l} session metadata changed during ownership migration`);return _.pi_session_id=null,_.pi_session_file=null,!0}))throw new Error(`node ${l} session metadata changed during ownership migration`);a.run(l)}}e.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_nodes_pi_session_file ON nodes(pi_session_file);")}E(Z,"reconcileNodeSessionFileOwners");function dt(e){Z(e,!0)}E(dt,"makeNodeSessionFileUnique");function _t(e){Z(e,!1)}E(_t,"repairNodeSessionFileUniqueIndex");function ct(e){const t=O(e);N(e,t,"frozen_at","ALTER TABLE nodes ADD COLUMN frozen_at TEXT;"),N(e,t,"respawn_failures","ALTER TABLE nodes ADD COLUMN respawn_failures INTEGER NOT NULL DEFAULT 0;"),N(e,t,"respawn_not_before","ALTER TABLE nodes ADD COLUMN respawn_not_before TEXT;"),N(e,t,"launched_at","ALTER TABLE nodes ADD COLUMN launched_at TEXT;"),N(e,t,"last_settled_at","ALTER TABLE nodes ADD COLUMN last_settled_at TEXT;"),N(e,t,"terminal_reason","ALTER TABLE nodes ADD COLUMN terminal_reason TEXT;"),e.exec(`
|
|
393
393
|
UPDATE nodes SET terminal_reason = CASE
|
|
394
394
|
WHEN status = 'done' AND final_report IS NOT NULL THEN 'finalized'
|
|
395
395
|
WHEN status = 'done' AND intent = 'parked' THEN 'parked'
|
|
@@ -398,7 +398,7 @@ UPDATE nodes SET terminal_reason = CASE
|
|
|
398
398
|
WHEN status = 'dead' THEN 'crashed'
|
|
399
399
|
END
|
|
400
400
|
WHERE status IN ('done','canceled','dead') AND terminal_reason IS NULL;
|
|
401
|
-
`)}E(ct,"addNodeLifecycleColumns");function Nt(e){const t=
|
|
401
|
+
`)}E(ct,"addNodeLifecycleColumns");function Nt(e){const t=O(e);N(e,t,"description","ALTER TABLE nodes ADD COLUMN description TEXT;"),N(e,t,"cycles","ALTER TABLE nodes ADD COLUMN cycles INTEGER;");const n=h();if(!U(n))return;const o=e.prepare("UPDATE nodes SET description = ?, cycles = ? WHERE node_id = ?");for(const T of k(n)){const i=x(T);if(!U(i))continue;let a;try{a=JSON.parse(M(i,"utf8"))}catch{continue}const c=typeof a.description=="string"?a.description:null,L=typeof a.cycles=="number"?a.cycles:null;o.run(c,L,T)}}E(Nt,"addNodeLabelColumns");function Lt(e){const t=O(e);N(e,t,"outcome_kind","ALTER TABLE nodes ADD COLUMN outcome_kind TEXT;"),N(e,t,"outcome_reason","ALTER TABLE nodes ADD COLUMN outcome_reason TEXT;"),N(e,t,"outcome_at","ALTER TABLE nodes ADD COLUMN outcome_at TEXT;"),N(e,t,"outcome_revision","ALTER TABLE nodes ADD COLUMN outcome_revision INTEGER NOT NULL DEFAULT 0;"),N(e,t,"outcome_detail_json","ALTER TABLE nodes ADD COLUMN outcome_detail_json TEXT;"),N(e,t,"deadline_at","ALTER TABLE nodes ADD COLUMN deadline_at TEXT;"),e.exec(`
|
|
402
402
|
CREATE TABLE IF NOT EXISTS node_outcome_deliveries (
|
|
403
403
|
node_id TEXT PRIMARY KEY,
|
|
404
404
|
state TEXT NOT NULL,
|
|
@@ -431,7 +431,7 @@ UPDATE nodes SET outcome_kind='failure',
|
|
|
431
431
|
outcome_reason=COALESCE(terminal_reason,'crashed'),
|
|
432
432
|
outcome_at=COALESCE(finalized_at, created), outcome_revision=1
|
|
433
433
|
WHERE final_report IS NULL AND status IN ('done','dead','canceled') AND outcome_at IS NULL;
|
|
434
|
-
`)}E(Lt,"addNodeOutcomeAndDeadline");function lt(e){const t=
|
|
434
|
+
`)}E(Lt,"addNodeOutcomeAndDeadline");function lt(e){const t=O(e);N(e,t,"telemetry_tokens_in","ALTER TABLE nodes ADD COLUMN telemetry_tokens_in INTEGER;"),N(e,t,"telemetry_context_tokens","ALTER TABLE nodes ADD COLUMN telemetry_context_tokens INTEGER;"),N(e,t,"telemetry_last_activity","ALTER TABLE nodes ADD COLUMN telemetry_last_activity TEXT;"),N(e,t,"telemetry_updated_at","ALTER TABLE nodes ADD COLUMN telemetry_updated_at TEXT;");const n=e.prepare(`UPDATE nodes
|
|
435
435
|
SET telemetry_tokens_in = ?, telemetry_context_tokens = ?,
|
|
436
436
|
telemetry_last_activity = ?, telemetry_updated_at = ?
|
|
437
437
|
WHERE node_id = ?`);for(const{node_id:o}of e.prepare("SELECT node_id FROM nodes").all()){const T=j(h(),o,"job","telemetry.json");if(U(T))try{const i=JSON.parse(M(T,"utf8")),a=typeof i.tokens_in=="number"&&Number.isFinite(i.tokens_in)?i.tokens_in:null,c=typeof i.context_tokens=="number"&&Number.isFinite(i.context_tokens)?i.context_tokens:null,L=typeof i.last_activity=="string"?i.last_activity:null,l=ue(T).mtime.toISOString();n.run(a,c,L,l,o)}catch{}}}E(lt,"addNodeTelemetryColumns");function ut(e){e.exec(`
|
|
@@ -441,7 +441,7 @@ CREATE INDEX IF NOT EXISTS deliveries_external_due_order
|
|
|
441
441
|
DROP INDEX IF EXISTS deliveries_external_due;
|
|
442
442
|
CREATE INDEX IF NOT EXISTS idx_nodes_parent_created ON nodes(parent, created);
|
|
443
443
|
CREATE INDEX IF NOT EXISTS idx_edges_type_created ON edges(type, created);
|
|
444
|
-
`)}E(ut,"addRecurringLaneIndexes");function pt(e){_e(e)}E(pt,"projectLiveNodeState");function Rt(e){N(e,
|
|
444
|
+
`)}E(ut,"addRecurringLaneIndexes");function pt(e){_e(e)}E(pt,"projectLiveNodeState");function Rt(e){N(e,O(e),"scopes_json","ALTER TABLE nodes ADD COLUMN scopes_json TEXT;")}E(Rt,"addNodeScopes");function At(e){const t=O(e);N(e,t,"grantee","ALTER TABLE nodes ADD COLUMN grantee TEXT NOT NULL DEFAULT 'user:local';"),N(e,t,"sub","ALTER TABLE nodes ADD COLUMN sub TEXT;"),N(e,t,"grant_id","ALTER TABLE nodes ADD COLUMN grant_id TEXT;"),N(e,t,"client_id","ALTER TABLE nodes ADD COLUMN client_id TEXT;"),N(e,t,"metadata_json","ALTER TABLE nodes ADD COLUMN metadata_json TEXT;"),N(e,t,"run_id","ALTER TABLE nodes ADD COLUMN run_id TEXT;"),N(e,t,"event_cursor","ALTER TABLE nodes ADD COLUMN event_cursor INTEGER;"),N(e,t,"usage_json","ALTER TABLE nodes ADD COLUMN usage_json TEXT;"),N(e,t,"deleting_at","ALTER TABLE nodes ADD COLUMN deleting_at TEXT;"),e.exec(`
|
|
445
445
|
ALTER TABLE sessions ADD COLUMN event_offset INTEGER;
|
|
446
446
|
CREATE INDEX idx_nodes_run_id ON nodes(run_id);
|
|
447
447
|
-- Child nodes may be pruned while their root run and event history remain.
|
|
@@ -723,7 +723,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
723
723
|
url TEXT NOT NULL, created_by TEXT NOT NULL, created_at TEXT NOT NULL, expires_at TEXT,
|
|
724
724
|
status TEXT NOT NULL CHECK (status IN ('on', 'off')), object_deleted_at TEXT
|
|
725
725
|
);
|
|
726
|
-
CREATE INDEX IF NOT EXISTS idx_shares_created_by ON shares(created_by);`)}E(gt,"addFileTransfer");function
|
|
726
|
+
CREATE INDEX IF NOT EXISTS idx_shares_created_by ON shares(created_by);`)}E(gt,"addFileTransfer");function wt(e){e.exec(`CREATE TABLE IF NOT EXISTS daemon_actions (
|
|
727
727
|
action_id TEXT PRIMARY KEY,
|
|
728
728
|
adapter_json TEXT NOT NULL,
|
|
729
729
|
body_json TEXT,
|
|
@@ -762,7 +762,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
762
762
|
DELETE FROM messages
|
|
763
763
|
WHERE message_id IN (SELECT message_id FROM moved_actions WHERE message_id IS NOT NULL)
|
|
764
764
|
AND NOT EXISTS (SELECT 1 FROM deliveries d WHERE d.message_id = messages.message_id);
|
|
765
|
-
DROP TABLE moved_actions;`)}E(
|
|
765
|
+
DROP TABLE moved_actions;`)}E(wt,"moveDaemonActions");function yt(e){B(e,61,()=>{if(!C(e,"objects"))return;const t=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n,n=e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%objects%'").all();for(const i of n)e.exec(`DROP VIEW "${i.name}"`);e.exec(`
|
|
766
766
|
CREATE TABLE objects_new (
|
|
767
767
|
rowid INTEGER PRIMARY KEY,
|
|
768
768
|
id TEXT NOT NULL UNIQUE,
|
|
@@ -783,7 +783,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
783
783
|
CREATE UNIQUE INDEX objects_handle ON objects(type, name) WHERE type IN ('person','app','repo','profile');
|
|
784
784
|
CREATE INDEX objects_owner_type ON objects(owner, type, kind);
|
|
785
785
|
CREATE INDEX objects_type_kind ON objects(type, kind);
|
|
786
|
-
`);for(const i of n)e.exec(i.sql);const o=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n;if(o!==t)throw new Error(`objects rebuild lost rows: expected ${t}, got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`objects rebuild left ${T.length} foreign-key violation(s)`)})}E(
|
|
786
|
+
`);for(const i of n)e.exec(i.sql);const o=e.prepare("SELECT COUNT(*) AS n FROM objects").get().n;if(o!==t)throw new Error(`objects rebuild lost rows: expected ${t}, got ${o}`);const T=e.prepare("PRAGMA foreign_key_check").all();if(T.length>0)throw new Error(`objects rebuild left ${T.length} foreign-key violation(s)`)})}E(yt,"objectsWithoutTypeCheck");function vt(e){C(e,"deliveries")&&e.exec(`
|
|
787
787
|
CREATE INDEX IF NOT EXISTS deliveries_destination ON deliveries(destination_id, wake, state, created_at);
|
|
788
788
|
DROP INDEX IF EXISTS deliveries_node_inbox;
|
|
789
789
|
`)}E(vt,"addDeliveriesDestinationIndex");function ht(e){e.exec(`
|
|
@@ -881,7 +881,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
881
881
|
VALUES (?, ?, 1, NULL, ?) RETURNING rowid`),l=e.prepare(`INSERT INTO watch_subscriptions
|
|
882
882
|
(watch, pattern, filter_json, config_json, started_by, ends_on, created_at)
|
|
883
883
|
VALUES (?, 'outcome', NULL, '{"1":"after-turn"}', 'spawn', NULL, ?)`),r=e.prepare("UPDATE deliveries SET destination_id = ?, idempotency_key = NULL WHERE delivery_id = ?"),_=e.prepare("SELECT body_json FROM messages WHERE message_id = ?"),d=e.prepare(`UPDATE messages SET body_json = ?, event = 'outcome', object_id = ?, level = 1
|
|
884
|
-
WHERE message_id = ?`);for(const s of i){if(s.owner===null)throw new Error(`v67 outcome node ${s.node_id} has no owner`);const A=JSON.parse(s.adapter_json);if(A.adapter!=="subprocess"||!Array.isArray(A.argv)||typeof A.cwd!="string"||typeof A.config_origin!="string")throw new Error(`v67 invalid outcome adapter on ${s.delivery_id}`);const m=P(16).toString("hex"),D=new Date(s.created_at).toISOString(),
|
|
884
|
+
WHERE message_id = ?`);for(const s of i){if(s.owner===null)throw new Error(`v67 outcome node ${s.node_id} has no owner`);const A=JSON.parse(s.adapter_json);if(A.adapter!=="subprocess"||!Array.isArray(A.argv)||typeof A.cwd!="string"||typeof A.config_origin!="string")throw new Error(`v67 invalid outcome adapter on ${s.delivery_id}`);const m=P(16).toString("hex"),D=new Date(s.created_at).toISOString(),y=a.get(m,s.owner,s.privacy,`outcome/${s.node_id}`,D);c.run(y.rowid,JSON.stringify({argv:A.argv,cwd:A.cwd,config_origin:A.config_origin,name:s.destination_id}),JSON.stringify(A.payload??null));const G=L.get(y.rowid,e.prepare("SELECT rowid FROM objects WHERE id = ?").get(s.node_id).rowid,D);if(l.run(G.rowid,D),s.message_id===null){if(s.state!=="armed")throw new Error(`v67 delivery ${s.delivery_id} has no message but is ${s.state}`);continue}const f=_.get(s.message_id);if(!f||f.body_json===null)throw new Error(`v67 delivery ${s.delivery_id} has no frozen outcome document`);if(e.prepare("SELECT COUNT(*) AS n FROM deliveries WHERE message_id = ?").get(s.message_id).n!==1)throw new Error(`v67 outcome message ${s.message_id} is shared`);const v=JSON.parse(f.body_json);if(v===null||Array.isArray(v)||typeof v!="object")throw new Error(`v67 invalid outcome body on ${s.delivery_id}`);delete v.action,delete v.delivery,d.run(JSON.stringify(v),s.node_id,s.message_id),r.run(m,s.delivery_id)}const u=e.prepare("SELECT COUNT(*) AS n FROM deliveries WHERE state = 'armed'").get();if(u.n!==i.filter(s=>s.state==="armed").length)throw new Error(`v67 found ${u.n} armed deliveries but only ${i.length} mapped outcome rows`);const p=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n-u.n,I=e.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND sql LIKE '%deliveries%'").all();for(const s of I)e.exec(`DROP VIEW "${s.name.replaceAll('"','""')}"`);e.exec(`
|
|
885
885
|
CREATE TABLE deliveries_new (
|
|
886
886
|
delivery_id TEXT PRIMARY KEY,
|
|
887
887
|
message_id TEXT NOT NULL REFERENCES messages(message_id),
|
|
@@ -916,7 +916,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
916
916
|
CREATE INDEX deliveries_handed_off ON deliveries(claim_owner) WHERE state = 'handed_off';
|
|
917
917
|
CREATE INDEX deliveries_message ON deliveries(message_id);
|
|
918
918
|
CREATE UNIQUE INDEX deliveries_idempotency ON deliveries(idempotency_key) WHERE idempotency_key IS NOT NULL;
|
|
919
|
-
`);for(const s of
|
|
919
|
+
`);for(const s of I)e.exec(s.sql);const R=e.prepare("SELECT COUNT(*) AS n FROM deliveries").get().n;if(R!==p)throw new Error(`v67 deliveries rebuild lost rows: expected ${p}, got ${R}`)}const t=e.prepare("PRAGMA foreign_key_check").all();if(t.length)throw new Error(`v67 left ${t.length} foreign-key violation(s)`)})}E(jt,"outcomeActionsOnObjects");function Ht(e){e.exec(`
|
|
920
920
|
CREATE TABLE IF NOT EXISTS create_requests (
|
|
921
921
|
request_key TEXT PRIMARY KEY,
|
|
922
922
|
node_id TEXT,
|
|
@@ -924,7 +924,7 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
924
924
|
state TEXT NOT NULL DEFAULT 'reserved' CHECK (state IN ('reserved', 'warm_claimed', 'complete'))
|
|
925
925
|
);
|
|
926
926
|
CREATE INDEX IF NOT EXISTS idx_create_requests_expires ON create_requests(expires_at);
|
|
927
|
-
`)}E(Ht,"addCreateRequests");function Gt(e){for(const[r,_]of[["sub","TEXT"],["grant_id","TEXT"],["scopes_json","TEXT"],["origin_run_id","TEXT"],["run_execution_id","TEXT"]])S(e,"crons",r)||e.exec(`ALTER TABLE crons ADD COLUMN ${r} ${_}`);const t=[],n=E(r=>e.prepare("SELECT id, sub, resolved_scopes_json FROM grants WHERE grantee = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r),"grantRow"),o=E(r=>e.prepare("SELECT grantee, sub, resolved_scopes_json FROM grants WHERE id = ?").get(r),"grantById"),T=E(r=>{try{const _=JSON.parse(r);return Array.isArray(_)?_.flatMap(d=>d&&d.mode==="always"&&typeof d.scope=="string"?[d.scope]:[]):[]}catch{return[]}},"snapshot"),i=E((r,_)=>{if(_===null)return null;const d=e.prepare("SELECT grantee, sub, grant_id, scopes_json, run_id FROM node_rows WHERE node_id = ?").get(_);if(d===void 0||d.grantee!==r)return null;const u=r==="app:terminal";let p=null;if(d.scopes_json!==null){let A;try{A=JSON.parse(d.scopes_json)}catch{return{pause:"bad_scopes"}}if(!Array.isArray(A)||!A.every(m=>typeof m=="string"))return{pause:"bad_scopes"};p=A}const
|
|
927
|
+
`)}E(Ht,"addCreateRequests");function Gt(e){for(const[r,_]of[["sub","TEXT"],["grant_id","TEXT"],["scopes_json","TEXT"],["origin_run_id","TEXT"],["run_execution_id","TEXT"]])S(e,"crons",r)||e.exec(`ALTER TABLE crons ADD COLUMN ${r} ${_}`);const t=[],n=E(r=>e.prepare("SELECT id, sub, resolved_scopes_json FROM grants WHERE grantee = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r),"grantRow"),o=E(r=>e.prepare("SELECT grantee, sub, resolved_scopes_json FROM grants WHERE id = ?").get(r),"grantById"),T=E(r=>{try{const _=JSON.parse(r);return Array.isArray(_)?_.flatMap(d=>d&&d.mode==="always"&&typeof d.scope=="string"?[d.scope]:[]):[]}catch{return[]}},"snapshot"),i=E((r,_)=>{if(_===null)return null;const d=e.prepare("SELECT grantee, sub, grant_id, scopes_json, run_id FROM node_rows WHERE node_id = ?").get(_);if(d===void 0||d.grantee!==r)return null;const u=r==="app:terminal";let p=null;if(d.scopes_json!==null){let A;try{A=JSON.parse(d.scopes_json)}catch{return{pause:"bad_scopes"}}if(!Array.isArray(A)||!A.every(m=>typeof m=="string"))return{pause:"bad_scopes"};p=A}const I=u?n(r):void 0;let R=d.grant_id??I?.id??null;R===null&&!u&&d.sub!==null&&(R=e.prepare("SELECT id FROM grants WHERE grantee = ? AND sub = ? ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, rev DESC LIMIT 1").get(r,d.sub)?.id??null);const s=R===null?void 0:o(R);return R!==null&&(s===void 0||s.grantee!==r||d.sub!==null&&s.sub!==d.sub)?{pause:"no_grant"}:R===null&&!u?{pause:"no_grant"}:(p===null&&!u&&(p=T(s.resolved_scopes_json)),{principal:{sub:d.sub??s?.sub??I?.sub??"user:local",grant_id:R,scopes:p,origin_run_id:d.run_id}})},"fromCreator"),a=E(r=>{const _=n(r);return r==="app:terminal"?{sub:_?.sub??"user:local",grant_id:_?.id??null,scopes:null,origin_run_id:null}:_===void 0?null:{sub:_.sub,grant_id:_.id,scopes:T(_.resolved_scopes_json),origin_run_id:null}},"fromGrantee"),c=e.prepare("SELECT cron_id, grantee, created_by, isolated, cwd FROM crons WHERE sub IS NULL").all(),L=e.prepare("UPDATE crons SET sub = ?, grant_id = ?, scopes_json = ?, origin_run_id = ? WHERE cron_id = ?"),l=new Map;for(const r of c){const _=i(r.grantee,r.created_by),d=_===null?a(r.grantee):"principal"in _?_.principal:null;if(d===null){const u=_!==null&&"pause"in _?_.pause:"no_grant";L.run("user:local",null,null,null,r.cron_id),e.prepare("UPDATE crons SET state = 'paused' WHERE cron_id = ?").run(r.cron_id),t.push({event:`cron.migrated.${u}`,fields:{cron_id:r.cron_id,grantee:r.grantee}})}else l.set(r.cron_id,d),L.run(d.sub,d.grant_id,d.scopes===null?null:JSON.stringify(d.scopes),d.origin_run_id,r.cron_id);if(r.isolated!==0){const u=j(Re(r.grantee).root,"crons",r.cron_id);e.prepare("UPDATE crons SET cwd = ? WHERE cron_id = ?").run(u,r.cron_id),t.push({event:"cron.migrated.isolated_cwd",fields:{cron_id:r.cron_id,old_cwd:r.cwd,cwd:u}})}}if(C(e,"daemon_actions")){const r=e.prepare("SELECT action_id, adapter_json FROM daemon_actions WHERE state IN ('pending', 'handed_off') AND json_extract(adapter_json, '$.adapter') = 'cron_spawn' AND json_extract(adapter_json, '$.principal') IS NULL").all();for(const _ of r){const d=JSON.parse(_.adapter_json),u=typeof d.cronId=="string"?d.cronId:null,p=u===null?void 0:e.prepare("SELECT grantee, sub, grant_id, scopes_json, origin_run_id, isolated, created_by FROM crons WHERE cron_id = ?").get(u);let I=null;if(p!==void 0&&!(p.grant_id===null&&p.grantee!=="app:terminal"))I={cron_id:u,grantee:p.grantee,sub:p.sub,grant_id:p.grant_id,scopes:p.scopes_json===null?null:JSON.parse(p.scopes_json),origin_run_id:p.origin_run_id,isolated:p.isolated!==0,creator:p.created_by};else if(p===void 0){const R=typeof d.parent=="string"?d.parent:null,s=R===null?void 0:e.prepare("SELECT grantee FROM node_rows WHERE node_id = ?").get(R),A=s===void 0?null:i(s.grantee,R),m=A===null||!("principal"in A)?null:A.principal;s!==void 0&&m!==null&&(I={cron_id:u,grantee:s.grantee,sub:m.sub,grant_id:m.grant_id,scopes:m.scopes,origin_run_id:m.origin_run_id,isolated:d.isolated===!0,creator:R})}if(I!==null)e.prepare("UPDATE daemon_actions SET adapter_json = ? WHERE action_id = ?").run(JSON.stringify({...d,principal:I}),_.action_id);else{const R=Date.now();e.prepare("UPDATE daemon_actions SET state = 'permanent_failed', failed_at = ?, updated_at = ?, claimed_at = NULL, claim_owner = NULL, next_attempt_at = NULL, last_failure_json = ? WHERE action_id = ?").run(R,R,JSON.stringify({kind:"grant_refused",message:"the cron has no derivable principal to authorize this birth"}),_.action_id),t.push({event:"cron.birth.refused",fields:{cron_id:u,action_id:_.action_id,reason:"grant_missing"}})}}}for(const{event:r,fields:_}of t)Ae({level:"warn",event:r,fields:_})}E(Gt,"addCronPrincipal");const F=[Ue,Ce,Se,De,ge,we,ye,he,ve,xe,Fe,Me,ke,J,je,J,He,Ge,be,Be,We,Qe,Ve,Ze,et,tt,nt,Et,ot,it,st,rt,Tt,at,ct,dt,_t,Nt,Lt,e=>{de(e),ce(e),Ne(e),Le(e)},ut,pt,lt,Rt,At,Ot,mt,Ut,ft,Xt,ee,te,ne,Ee,Ct,St,oe,Dt,Ie,gt,wt,yt,vt,kt,Mt,Ft,jt,xt,e=>e.exec(`
|
|
928
928
|
CREATE TABLE audit_rows (
|
|
929
929
|
id INTEGER PRIMARY KEY, request_id TEXT NOT NULL, time TEXT NOT NULL, grantee TEXT, sub TEXT,
|
|
930
930
|
client_id TEXT, class TEXT, operation TEXT NOT NULL, scope_checked TEXT,
|
|
@@ -1046,4 +1046,22 @@ CREATE INDEX idx_structured_requests_effects ON structured_requests(effects_done
|
|
|
1046
1046
|
CREATE UNIQUE INDEX objects_named ON objects(owner, name)
|
|
1047
1047
|
WHERE deleted_at IS NULL AND home_machine IS NULL AND (type = 'document' OR instr(type, '.') > 0);
|
|
1048
1048
|
CREATE UNIQUE INDEX objects_handle ON objects(type, name) WHERE home_machine IS NULL AND type IN ('person','app','repo','profile');
|
|
1049
|
-
`),e=>e.exec("ALTER TABLE grants ADD COLUMN inference_endpoint_json TEXT"),e=>e.exec("ALTER TABLE nodes ADD COLUMN reply_at TEXT; ALTER TABLE nodes ADD COLUMN read_at TEXT;")];function
|
|
1049
|
+
`),e=>e.exec("ALTER TABLE grants ADD COLUMN inference_endpoint_json TEXT"),e=>e.exec("ALTER TABLE nodes ADD COLUMN reply_at TEXT; ALTER TABLE nodes ADD COLUMN read_at TEXT;"),Bt,bt];function bt(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'waits'").get()===void 0&&e.exec("CREATE TABLE waits (wait_id TEXT PRIMARY KEY, node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE, kind TEXT, target_id TEXT, generation INTEGER, created_at INTEGER, satisfied_at INTEGER)");const t=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;e.exec(`
|
|
1050
|
+
CREATE TABLE waits_new (
|
|
1051
|
+
wait_id TEXT PRIMARY KEY,
|
|
1052
|
+
node_id TEXT NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,
|
|
1053
|
+
kind TEXT NOT NULL CHECK (kind IN ('controller', 'object')),
|
|
1054
|
+
target_id TEXT NOT NULL,
|
|
1055
|
+
generation INTEGER NOT NULL,
|
|
1056
|
+
created_at INTEGER NOT NULL,
|
|
1057
|
+
satisfied_at INTEGER
|
|
1058
|
+
);
|
|
1059
|
+
INSERT INTO waits_new (rowid, wait_id, node_id, kind, target_id, generation, created_at, satisfied_at)
|
|
1060
|
+
SELECT rowid, wait_id, node_id, kind, target_id, generation, created_at, satisfied_at FROM waits;
|
|
1061
|
+
DROP TABLE waits;
|
|
1062
|
+
ALTER TABLE waits_new RENAME TO waits;
|
|
1063
|
+
CREATE UNIQUE INDEX waits_live ON waits(node_id) WHERE satisfied_at IS NULL AND kind = 'controller';
|
|
1064
|
+
CREATE UNIQUE INDEX waits_live_object ON waits(node_id, target_id) WHERE satisfied_at IS NULL AND kind = 'object';
|
|
1065
|
+
CREATE INDEX waits_target ON waits(target_id) WHERE satisfied_at IS NULL;
|
|
1066
|
+
CREATE INDEX waits_node ON waits(node_id);
|
|
1067
|
+
`);const n=e.prepare("SELECT COUNT(*) AS n FROM waits").get().n;if(n!==t)throw new Error(`v96 waits rebuild lost rows: expected ${t}, got ${n}`)}E(bt,"addObjectWaits");function Bt(e){const t=O(e);for(const n of["waiting_for","waiting_for_generation"])t.has(n)&&e.exec(`ALTER TABLE nodes DROP COLUMN ${n}`)}E(Bt,"dropNodeWaitColumns");function B(e,t,n){const o=e.prepare("PRAGMA foreign_keys").get().foreign_keys;e.exec("PRAGMA foreign_keys = OFF;");try{e.exec("BEGIN IMMEDIATE");try{W(e)===t&&(n(),e.exec(`PRAGMA user_version = ${t+1}`)),e.exec("COMMIT")}catch(T){try{e.exec("ROLLBACK")}catch{}throw T}}finally{e.exec(`PRAGMA foreign_keys = ${o};`)}}E(B,"selfTransactionalMigration");const Wt=new Set([3,61,63,66]);function W(e){return e.prepare("PRAGMA user_version").get().user_version}E(W,"currentUserVersion");function se(e,t){F[t](e),e.exec(`PRAGMA user_version = ${t+1}`)}E(se,"applyMigration");function rn(e){const t=W(e);if(t>F.length)throw new Error(`unsupported canvas schema version ${t} (latest supported ${F.length})`);if(t===F.length)return;const n=e.prepare("PRAGMA busy_timeout").get().timeout;e.exec("PRAGMA busy_timeout = 60000;");try{Pt(e)}finally{e.exec(`PRAGMA busy_timeout = ${n};`)}}E(rn,"migrate");function Pt(e){for(;;){const t=W(e);if(t>=F.length)return;if(Wt.has(t)){if(e.isTransaction)throw new Error(`canvas migration v${t+1} requires autocommit`);F[t](e);continue}if(e.isTransaction){se(e,t);continue}e.exec("BEGIN IMMEDIATE");try{W(e)===t&&se(e,t),e.exec("COMMIT")}catch(n){try{e.exec("ROLLBACK")}catch{}throw n}}}E(Pt,"runPendingMigrations");export{F as MIGRATIONS,rn as migrate};
|