@north-light/crouter 0.3.350 → 0.3.352

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 (48) hide show
  1. package/dist/api/node-transport.js +1 -1
  2. package/dist/clients/attach/viewer.js +924 -908
  3. package/dist/core/canvas/migrations.js +42 -26
  4. package/dist/core/canvas/recovery.js +1 -1
  5. package/dist/core/grants/remove.js +1 -1
  6. package/dist/core/grants/sync.d.ts +21 -0
  7. package/dist/core/grants/sync.js +1 -1
  8. package/dist/core/human/page-schema.d.ts +1 -1
  9. package/dist/core/human/requests.d.ts +3 -0
  10. package/dist/core/human/requests.js +15 -14
  11. package/dist/core/human/scan.js +1 -1
  12. package/dist/core/runs/operations.d.ts +24 -3
  13. package/dist/core/runs/operations.js +5 -5
  14. package/dist/core/runs/questions.d.ts +54 -0
  15. package/dist/core/runs/questions.js +4 -0
  16. package/dist/core/storage/attachments.d.ts +33 -0
  17. package/dist/core/storage/attachments.js +1 -0
  18. package/dist/core/storage/client.d.ts +67 -0
  19. package/dist/core/storage/client.js +3 -0
  20. package/dist/core/storage/download.d.ts +23 -0
  21. package/dist/core/storage/download.js +1 -0
  22. package/dist/core/storage/shares.d.ts +32 -0
  23. package/dist/core/storage/shares.js +1 -0
  24. package/dist/core/storage/tables.d.ts +59 -0
  25. package/dist/core/storage/tables.js +3 -0
  26. package/dist/daemon/api/app-listener.js +12 -12
  27. package/dist/daemon/api/handlers/app-profiles.d.ts +17 -0
  28. package/dist/daemon/api/handlers/app-profiles.js +1 -0
  29. package/dist/daemon/api/handlers/questions.d.ts +7 -0
  30. package/dist/daemon/api/handlers/questions.js +1 -0
  31. package/dist/daemon/api/handlers/runs.js +1 -1
  32. package/dist/daemon/api/handlers/transfer.d.ts +15 -0
  33. package/dist/daemon/api/handlers/transfer.js +1 -0
  34. package/dist/daemon/api/operations.d.ts +2 -1
  35. package/dist/daemon/api/operations.js +1 -1
  36. package/dist/daemon/cron-run.js +1 -1
  37. package/dist/daemon/crtrd.js +7 -7
  38. package/dist/daemon/human/finish.d.ts +5 -0
  39. package/dist/daemon/human/finish.js +3 -3
  40. package/dist/daemon/human/settle.js +1 -1
  41. package/dist/daemon/reconcilers/storage-due-work.d.ts +32 -0
  42. package/dist/daemon/reconcilers/storage-due-work.js +1 -0
  43. package/dist/daemon/runs/append-section.js +2 -2
  44. package/dist/daemon/runs/observer.js +2 -2
  45. package/dist/types.d.ts +6 -0
  46. package/package.json +2 -2
  47. package/packages/crouter-identity/package.json +1 -1
  48. package/runtime.lock.json +11 -11
@@ -1,42 +1,43 @@
1
- var de=Object.defineProperty;var i=(e,t)=>de(e,"name",{value:t,configurable:!0});import{createHash as ue,randomBytes as j}from"node:crypto";import{existsSync as g,mkdirSync as A,readFileSync as V,readdirSync as ce,realpathSync as O,statSync as le,writeFileSync as _e}from"node:fs";import{basename as w,join as c}from"node:path";import{z as d}from"zod";import{crtrHome as z,isSafeNodeId as pe,nodesRoot as N}from"../canvas/paths.js";import{openDb as _,withCanvasWrite as f}from"../canvas/db.js";import{syncDirectory as me,syncFile as fe}from"../fs-utils.js";import{newNodeId as Ee}from"../runtime/nodes.js";import{pageManifestPath as ge,pageModulePath as ye,pagePath as he}from"./convention.js";import{preparePageSource as be}from"./page-authoring.js";import{pageDeliverySchema as qe,validatePageManifest as G}from"./page-schema.js";function Q(e){return e===1||e===!0}i(Q,"bool");function Y(e){return{request_id:e.request_id,kind:e.kind,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,presentation_dir:e.presentation_dir,requester_node_id:e.requester_node_id,companion_node_id:e.companion_node_id,idempotency_key:e.idempotency_key,state:e.state,outcome:e.outcome,inbox_listed:Q(e.inbox_listed),settleable:Q(e.settleable),title:e.title,subtitle:e.subtitle,file:e.file,specification_json:e.specification_json,action_json:e.action_json,progress_json:e.progress_json,feedback_json:e.feedback_json,result_json:e.result_json,anchor_base_sha256:e.anchor_base_sha256,anchor_base_bytes:e.anchor_base_bytes===null?null:Buffer.from(e.anchor_base_bytes),created_at:e.created_at,opened_at:e.opened_at,submit_requested_at:e.submit_requested_at,settled_at:e.settled_at,settlement_delivery_id:e.settlement_delivery_id,action_delivery_id:e.action_delivery_id,submit_note_delivery_id:e.submit_note_delivery_id,projected_at:e.projected_at,projection_error:e.projection_error,companion_retired_at:e.companion_retired_at,updated_at:e.updated_at}}i(Y,"recordFromRow");function b(e,t,...r){const s=e.prepare(`SELECT * FROM human_requests WHERE ${t}`).get(...r);return s===void 0?null:Y(s)}i(b,"one");function T(e,t,r=[],s="created_at ASC, request_id ASC"){return e.prepare(`SELECT * FROM human_requests WHERE ${t} ORDER BY ${s}`).all(...r).map(Y)}i(T,"many");function Z(){return c(z(),"requests")}i(Z,"humanRequestsRoot");function C(e){if(!pe(e))throw new TypeError(`request_id must be a safe path segment: ${e}`);const t=Z();return A(t,{recursive:!0,mode:448}),c(O(t),e)}i(C,"requestDir");function P(){return j(32).toString("hex")}i(P,"randomTicketId");function U(e,t){return ue("sha256").update(`${O(e)}\0${t}`,"utf8").digest("hex")}i(U,"legacyTicketId");const Ne={writeFile(e,t){_e(e,t,{flag:"wx",mode:384})},syncFile:fe,syncDirectory:me};function Te(e){return c(e,"revisions")}i(Te,"revisionRoot");function ee(e,t,r=Ne){A(e,{recursive:!0,mode:448});const s=Te(e);A(s,{recursive:!0,mode:448});const n=c(s,j(16).toString("hex"));A(n,{mode:448});const o=he(n,t.manifest.dialect);if(r.writeFile(o,t.document),r.syncFile(o),t.manifest.dialect==="jsx"){const a=ye(n);r.writeFile(a,t.module),r.syncFile(a)}const u=ge(n);return r.writeFile(u,`${JSON.stringify(t.manifest,null,2)}
2
- `),r.syncFile(u),r.syncDirectory(n),r.syncDirectory(s),r.syncDirectory(e),r.syncDirectory(Z()),n}i(ee,"publishPageRevision");function ze(e){if(e.kind!=="page"||e.presentation_dir===null)throw new Error(`page request has no selected presentation: ${e.request_id}`);return e.presentation_dir}i(ze,"presentationDir");function Ge(e){const t=e.request_id??Ee(),r=C(t),s=ee(r,e.prepared),n=new Date().toISOString(),o=e.prepared.manifest;return f(u=>{u.prepare(`
1
+ var de=Object.defineProperty;var i=(e,t)=>de(e,"name",{value:t,configurable:!0});import{createHash as ue,randomBytes as j}from"node:crypto";import{existsSync as g,mkdirSync as A,readFileSync as V,readdirSync as ce,realpathSync as L,statSync as le,writeFileSync as _e}from"node:fs";import{basename as w,join as c}from"node:path";import{z as d}from"zod";import{crtrHome as Q,isSafeNodeId as pe,nodesRoot as b}from"../canvas/paths.js";import{openDb as _,withCanvasWrite as f}from"../canvas/db.js";import{syncDirectory as me,syncFile as fe}from"../fs-utils.js";import{newNodeId as Ee}from"../runtime/nodes.js";import{pageManifestPath as ge,pageModulePath as ye,pagePath as he}from"./convention.js";import{preparePageSource as qe}from"./page-authoring.js";import{pageDeliverySchema as Ne,validatePageManifest as z}from"./page-schema.js";import{appendWaitingOnUser as be}from"../runs/questions.js";function G(e){return e===1||e===!0}i(G,"bool");function Y(e){return{request_id:e.request_id,kind:e.kind,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,presentation_dir:e.presentation_dir,requester_node_id:e.requester_node_id,companion_node_id:e.companion_node_id,idempotency_key:e.idempotency_key,state:e.state,outcome:e.outcome,inbox_listed:G(e.inbox_listed),settleable:G(e.settleable),title:e.title,subtitle:e.subtitle,file:e.file,specification_json:e.specification_json,action_json:e.action_json,progress_json:e.progress_json,feedback_json:e.feedback_json,result_json:e.result_json,anchor_base_sha256:e.anchor_base_sha256,anchor_base_bytes:e.anchor_base_bytes===null?null:Buffer.from(e.anchor_base_bytes),created_at:e.created_at,opened_at:e.opened_at,submit_requested_at:e.submit_requested_at,settled_at:e.settled_at,settlement_delivery_id:e.settlement_delivery_id,action_delivery_id:e.action_delivery_id,submit_note_delivery_id:e.submit_note_delivery_id,projected_at:e.projected_at,projection_error:e.projection_error,companion_retired_at:e.companion_retired_at,updated_at:e.updated_at}}i(Y,"recordFromRow");function q(e,t,...r){const s=e.prepare(`SELECT * FROM human_requests WHERE ${t}`).get(...r);return s===void 0?null:Y(s)}i(q,"one");function T(e,t,r=[],s="created_at ASC, request_id ASC"){return e.prepare(`SELECT * FROM human_requests WHERE ${t} ORDER BY ${s}`).all(...r).map(Y)}i(T,"many");function Z(){return c(Q(),"requests")}i(Z,"humanRequestsRoot");function C(e){if(!pe(e))throw new TypeError(`request_id must be a safe path segment: ${e}`);const t=Z();return A(t,{recursive:!0,mode:448}),c(L(t),e)}i(C,"requestDir");function U(){return j(32).toString("hex")}i(U,"randomTicketId");function P(e,t){return ue("sha256").update(`${L(e)}\0${t}`,"utf8").digest("hex")}i(P,"legacyTicketId");const Te={writeFile(e,t){_e(e,t,{flag:"wx",mode:384})},syncFile:fe,syncDirectory:me};function Se(e){return c(e,"revisions")}i(Se,"revisionRoot");function ee(e,t,r=Te){A(e,{recursive:!0,mode:448});const s=Se(e);A(s,{recursive:!0,mode:448});const n=c(s,j(16).toString("hex"));A(n,{mode:448});const o=he(n,t.manifest.dialect);if(r.writeFile(o,t.document),r.syncFile(o),t.manifest.dialect==="jsx"){const a=ye(n);r.writeFile(a,t.module),r.syncFile(a)}const u=ge(n);return r.writeFile(u,`${JSON.stringify(t.manifest,null,2)}
2
+ `),r.syncFile(u),r.syncDirectory(n),r.syncDirectory(s),r.syncDirectory(e),r.syncDirectory(Z()),n}i(ee,"publishPageRevision");function Ye(e){if(e.kind!=="page"||e.presentation_dir===null)throw new Error(`page request has no selected presentation: ${e.request_id}`);return e.presentation_dir}i(Ye,"presentationDir");function Ze(e){const t=e.request_id??Ee(),r=C(t),s=ee(r,e.prepared),n=new Date().toISOString(),o=e.prepared.manifest;return f(u=>{u.prepare(`
3
3
  INSERT INTO human_requests (
4
4
  request_id, kind, inbox_ticket_id, request_dir, presentation_dir, requester_node_id, state, inbox_listed,
5
5
  settleable, title, subtitle, specification_json, action_json, created_at, updated_at
6
6
  ) VALUES (?, 'page', ?, ?, ?, ?, 'open', ?, ?, ?, ?, ?, ?, ?, ?)
7
- `).run(t,e.inbox_ticket_id??P(),r,s,e.requester_node_id??null,o.delivery.inbox?1:0,o.delivery.inbox||o.delivery.reply?1:0,o.title,o.subtitle??null,JSON.stringify(o),e.action_json??null,n,n);const a=b(u,"request_id = ?",t);if(a===null)throw new Error(`page request insert did not produce a row: ${t}`);return a})}i(Ge,"createPageRequest");function Qe(e){return f(t=>{const r=t.prepare(`
7
+ `).run(t,e.inbox_ticket_id??U(),r,s,e.requester_node_id??null,o.delivery.inbox?1:0,o.delivery.inbox||o.delivery.reply?1:0,o.title,o.subtitle??null,JSON.stringify(o),e.action_json??null,n,n);const a=q(u,"request_id = ?",t);if(a===null)throw new Error(`page request insert did not produce a row: ${t}`);return be(u,a),a})}i(Ze,"createPageRequest");function et(e){return f(t=>{const r=t.prepare(`
8
8
  INSERT INTO human_requests (
9
9
  request_id, kind, inbox_ticket_id, request_dir, requester_node_id, companion_node_id,
10
10
  idempotency_key, state, inbox_listed, settleable, title, subtitle, file,
11
11
  specification_json, anchor_base_sha256, anchor_base_bytes, created_at, updated_at
12
12
  ) VALUES (?, 'review', ?, ?, ?, ?, ?, 'binding', ?, 1, ?, ?, ?, ?, ?, ?, ?, ?)
13
13
  ON CONFLICT(idempotency_key) DO NOTHING
14
- `).run(e.request_id,P(),e.request_dir,e.requester_node_id,e.companion_node_id,e.idempotency_key,e.inbox_listed?1:0,w(e.file),e.subtitle??null,e.file,JSON.stringify(e.specification),e.anchor_base_sha256,e.anchor_base_bytes,e.created_at,e.created_at),s=b(t,"idempotency_key = ?",e.idempotency_key);if(s===null)throw new Error(`review binding insert did not produce a row: ${e.idempotency_key}`);return{request_id:s.request_id,won:r.changes>0}})}i(Qe,"commitBindingRequest");function Ye(e){return b(_(),"request_id = ?",e)}i(Ye,"getRequest");function Ze(e){return b(_(),"inbox_ticket_id = ?",e)}i(Ze,"getRequestByInboxTicket");function et(e){let t=e;try{t=O(e)}catch{}return b(_(),"request_dir = ?",t)}i(et,"getRequestByDirectory");function tt(e){return b(_(),"companion_node_id = ? AND state <> 'binding'",e)}i(tt,"getRequestByCompanion");function nt(e){return b(_(),"idempotency_key = ?",e)}i(nt,"getRequestByIdempotencyKey");function rt(){return T(_(),"state = 'open' AND inbox_listed = 1",[],"created_at DESC, request_id DESC")}i(rt,"listOpenInboxRequests");function Se(e){return T(_(),"state = 'open' AND requester_node_id = ?",[e],"created_at DESC, request_id DESC")}i(Se,"openRequestsByRequester");function it(e){return Se(e).some(t=>t.kind==="review"?!0:JSON.parse(t.specification_json).delivery?.reply===!0)}i(it,"hasOpenReplyBearingRequestByRequester");function st(){return T(_(),"state = 'open' AND inbox_listed = 1 AND requester_node_id IS NOT NULL",[],"created_at DESC, request_id DESC")}i(st,"listOpenReplyBearingRequests");function ot(){return T(_(),"kind = 'review' AND state = 'binding'")}i(ot,"listBindingRequests");function at(){return T(_(),"kind = 'review' AND state = 'open' AND submit_requested_at IS NOT NULL")}i(at,"listSubmitRequestedRequests");function dt(){return T(_(),"kind = 'review' AND state = 'settled' AND projected_at IS NULL")}i(dt,"listUnprojectedReviews");function ut(e={}){const t=["1"],r=[];for(const[s,n]of Object.entries(e))n!==void 0&&(t.push(`${s} = ?`),r.push(n));return T(_(),t.join(" AND "),r)}i(ut,"listRequests");function ct(e,t){return f(r=>r.prepare("UPDATE human_requests SET state = 'open', opened_at = ?, updated_at = ? WHERE request_id = ? AND state = 'binding'").run(t,t,e).changes>0)}i(ct,"openRequest");function lt(e,t,r){return f(s=>s.prepare(`
14
+ `).run(e.request_id,U(),e.request_dir,e.requester_node_id,e.companion_node_id,e.idempotency_key,e.inbox_listed?1:0,w(e.file),e.subtitle??null,e.file,JSON.stringify(e.specification),e.anchor_base_sha256,e.anchor_base_bytes,e.created_at,e.created_at),s=q(t,"idempotency_key = ?",e.idempotency_key);if(s===null)throw new Error(`review binding insert did not produce a row: ${e.idempotency_key}`);return{request_id:s.request_id,won:r.changes>0}})}i(et,"commitBindingRequest");function tt(e){return q(_(),"request_id = ?",e)}i(tt,"getRequest");function nt(e){return q(_(),"inbox_ticket_id = ?",e)}i(nt,"getRequestByInboxTicket");function rt(e){let t=e;try{t=L(e)}catch{}return q(_(),"request_dir = ?",t)}i(rt,"getRequestByDirectory");function it(e){return q(_(),"companion_node_id = ? AND state <> 'binding'",e)}i(it,"getRequestByCompanion");function st(e){return q(_(),"idempotency_key = ?",e)}i(st,"getRequestByIdempotencyKey");const ve=`NOT (kind = 'page' AND EXISTS (SELECT 1 FROM nodes n WHERE n.node_id = human_requests.requester_node_id
15
+ AND n.run_id IS NOT NULL AND n.grantee IS NOT NULL AND n.grantee <> 'app:terminal'))`;function ot(){return T(_(),`state = 'open' AND inbox_listed = 1 AND ${ve}`,[],"created_at DESC, request_id DESC")}i(ot,"listOpenInboxRequests");function Re(e){return T(_(),"state = 'open' AND requester_node_id = ?",[e],"created_at DESC, request_id DESC")}i(Re,"openRequestsByRequester");function at(e){return Re(e).some(t=>t.kind==="review"?!0:JSON.parse(t.specification_json).delivery?.reply===!0)}i(at,"hasOpenReplyBearingRequestByRequester");function dt(){return T(_(),"state = 'open' AND inbox_listed = 1 AND requester_node_id IS NOT NULL",[],"created_at DESC, request_id DESC")}i(dt,"listOpenReplyBearingRequests");function ut(){return T(_(),"kind = 'review' AND state = 'binding'")}i(ut,"listBindingRequests");function ct(){return T(_(),"kind = 'review' AND state = 'open' AND submit_requested_at IS NOT NULL")}i(ct,"listSubmitRequestedRequests");function lt(){return T(_(),"kind = 'review' AND state = 'settled' AND projected_at IS NULL")}i(lt,"listUnprojectedReviews");function _t(e={}){const t=["1"],r=[];for(const[s,n]of Object.entries(e))n!==void 0&&(t.push(`${s} = ?`),r.push(n));return T(_(),t.join(" AND "),r)}i(_t,"listRequests");function pt(e,t){return f(r=>r.prepare("UPDATE human_requests SET state = 'open', opened_at = ?, updated_at = ? WHERE request_id = ? AND state = 'binding'").run(t,t,e).changes>0)}i(pt,"openRequest");function mt(e,t,r){return f(s=>s.prepare(`
15
16
  UPDATE human_requests SET state = 'settled', outcome = 'canceled', result_json = ?, settled_at = ?, updated_at = ?
16
17
  WHERE request_id = ? AND kind = 'review' AND state = 'binding'
17
- `).run(JSON.stringify({schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:t,reason:r}),t,t,e).changes>0)}i(lt,"cancelBindingRequest");function _t(e,t){return f(r=>r.prepare("UPDATE human_requests SET submit_requested_at = ?, updated_at = ? WHERE request_id = ? AND kind = 'review' AND state = 'open' AND submit_requested_at IS NULL").run(t,t,e).changes>0)}i(_t,"requestSubmit");function pt(e,t){return e.prepare(`
18
+ `).run(JSON.stringify({schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:t,reason:r}),t,t,e).changes>0)}i(mt,"cancelBindingRequest");function ft(e,t){return f(r=>r.prepare("UPDATE human_requests SET submit_requested_at = ?, updated_at = ? WHERE request_id = ? AND kind = 'review' AND state = 'open' AND submit_requested_at IS NULL").run(t,t,e).changes>0)}i(ft,"requestSubmit");function Et(e,t){return e.prepare(`
18
19
  UPDATE human_requests SET state = 'settled', outcome = ?, result_json = ?, settled_at = ?,
19
20
  progress_json = NULL, updated_at = ?
20
21
  WHERE request_id = ? AND state = 'open'
21
- `).run(t.outcome,t.result_json,t.settled_at,t.settled_at,t.request_id).changes===0?null:b(e,"request_id = ?",t.request_id)}i(pt,"settleRequestLocked");function mt(e,t,r){e.prepare("UPDATE human_requests SET settlement_delivery_id = ?, action_delivery_id = ?, updated_at = ? WHERE request_id = ?").run(r.settlement_delivery_id??null,r.action_delivery_id??null,new Date().toISOString(),t)}i(mt,"setSettlementDeliveryMarksLocked");function ft(e,t,r){return e.prepare("UPDATE human_requests SET submit_note_delivery_id = ?, updated_at = ? WHERE request_id = ? AND state = 'open' AND submit_note_delivery_id IS NULL").run(r,new Date().toISOString(),t).changes>0}i(ft,"setSubmitNoteDeliveryLocked");function Et(e,t){return f(r=>r.prepare(`
22
+ `).run(t.outcome,t.result_json,t.settled_at,t.settled_at,t.request_id).changes===0?null:q(e,"request_id = ?",t.request_id)}i(Et,"settleRequestLocked");function gt(e,t,r){e.prepare("UPDATE human_requests SET settlement_delivery_id = ?, action_delivery_id = ?, updated_at = ? WHERE request_id = ?").run(r.settlement_delivery_id??null,r.action_delivery_id??null,new Date().toISOString(),t)}i(gt,"setSettlementDeliveryMarksLocked");function yt(e,t,r){return e.prepare("UPDATE human_requests SET submit_note_delivery_id = ?, updated_at = ? WHERE request_id = ? AND state = 'open' AND submit_note_delivery_id IS NULL").run(r,new Date().toISOString(),t).changes>0}i(yt,"setSubmitNoteDeliveryLocked");function ht(e,t){return f(r=>r.prepare(`
22
23
  UPDATE human_requests SET presentation_dir = ?, specification_json = ?, title = ?, subtitle = ?, inbox_listed = ?, settleable = ?, updated_at = ?
23
24
  WHERE request_id = ? AND kind = 'page' AND state = 'open'
24
- `).run(t.presentation_dir,t.specification_json,t.title,t.subtitle,t.inbox_listed?1:0,t.settleable?1:0,new Date().toISOString(),e).changes>0)}i(Et,"revisePageRequest");function gt(e,t){return f(r=>r.prepare(`
25
+ `).run(t.presentation_dir,t.specification_json,t.title,t.subtitle,t.inbox_listed?1:0,t.settleable?1:0,new Date().toISOString(),e).changes>0)}i(ht,"revisePageRequest");function qt(e,t){return f(r=>r.prepare(`
25
26
  UPDATE human_requests SET progress_json = ?, updated_at = ?
26
27
  WHERE inbox_ticket_id = ? AND kind = 'page' AND state = 'open' AND settleable = 1
27
- `).run(JSON.stringify({kind:"page",responses:t,savedAt:new Date().toISOString()}),new Date().toISOString(),e).changes>0)}i(gt,"writeProgress");function yt(e,t){f(r=>r.prepare("UPDATE human_requests SET projected_at = ?, projection_error = NULL, updated_at = ? WHERE request_id = ?").run(t,t,e))}i(yt,"markProjected");function ht(e,t){f(r=>r.prepare("UPDATE human_requests SET projection_error = ?, updated_at = ? WHERE request_id = ? AND projected_at IS NULL").run(t,new Date().toISOString(),e))}i(ht,"markProjectionError");function bt(e,t){f(r=>r.prepare("UPDATE human_requests SET companion_retired_at = ?, updated_at = ? WHERE request_id = ? AND companion_retired_at IS NULL").run(t,t,e))}i(bt,"markCompanionRetired");function qt(e){const t=_().prepare("SELECT anchor_base_bytes, anchor_base_sha256 FROM human_requests WHERE request_id = ?").get(e);return t===void 0||t.anchor_base_bytes===null||t.anchor_base_sha256===null?null:{bytes:Buffer.from(t.anchor_base_bytes),sha256:t.anchor_base_sha256}}i(qt,"readAnchorBase");function Nt(e,t,r,s){e.prepare("UPDATE human_requests SET anchor_base_bytes = ?, anchor_base_sha256 = ?, updated_at = ? WHERE request_id = ?").run(r,s,new Date().toISOString(),t)}i(Nt,"replaceAnchorBaseLocked");function ve(e){if(typeof e!="object"||e===null)throw new Error("result is not an object");const t=e;return t.kind==="canceled"?{outcome:t.disposition==="dismissed"?"dismissed":"canceled",settledAt:String(t.canceledAt)}:{outcome:"answered",settledAt:String(t.completedAt)}}i(ve,"legacyPageResult");function R(e){try{return JSON.parse(V(e,"utf8"))}catch(t){throw new Error(`corrupt required input: ${e}`,{cause:t})}}i(R,"readJson");function H(){return j(16).toString("hex")}i(H,"migrationId");function Re(e){return Number(e.prepare("SELECT COALESCE(MAX(seq), 0) AS seq FROM messages").get().seq)+1}i(Re,"nextMessageSeq");function Ae(e,t,r,s){return(s==="page"?e.prepare(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id
28
+ `).run(JSON.stringify({kind:"page",responses:t,savedAt:new Date().toISOString()}),new Date().toISOString(),e).changes>0)}i(qt,"writeProgress");function Nt(e,t){f(r=>r.prepare("UPDATE human_requests SET projected_at = ?, projection_error = NULL, updated_at = ? WHERE request_id = ?").run(t,t,e))}i(Nt,"markProjected");function bt(e,t){f(r=>r.prepare("UPDATE human_requests SET projection_error = ?, updated_at = ? WHERE request_id = ? AND projected_at IS NULL").run(t,new Date().toISOString(),e))}i(bt,"markProjectionError");function Tt(e,t){f(r=>r.prepare("UPDATE human_requests SET companion_retired_at = ?, updated_at = ? WHERE request_id = ? AND companion_retired_at IS NULL").run(t,t,e))}i(Tt,"markCompanionRetired");function St(e){const t=_().prepare("SELECT anchor_base_bytes, anchor_base_sha256 FROM human_requests WHERE request_id = ?").get(e);return t===void 0||t.anchor_base_bytes===null||t.anchor_base_sha256===null?null:{bytes:Buffer.from(t.anchor_base_bytes),sha256:t.anchor_base_sha256}}i(St,"readAnchorBase");function vt(e,t,r,s){e.prepare("UPDATE human_requests SET anchor_base_bytes = ?, anchor_base_sha256 = ?, updated_at = ? WHERE request_id = ?").run(r,s,new Date().toISOString(),t)}i(vt,"replaceAnchorBaseLocked");function Ae(e){if(typeof e!="object"||e===null)throw new Error("result is not an object");const t=e;return t.kind==="canceled"?{outcome:t.disposition==="dismissed"?"dismissed":"canceled",settledAt:String(t.canceledAt)}:{outcome:"answered",settledAt:String(t.completedAt)}}i(Ae,"legacyPageResult");function R(e){try{return JSON.parse(V(e,"utf8"))}catch(t){throw new Error(`corrupt required input: ${e}`,{cause:t})}}i(R,"readJson");function H(){return j(16).toString("hex")}i(H,"migrationId");function De(e){return Number(e.prepare("SELECT COALESCE(MAX(seq), 0) AS seq FROM messages").get().seq)+1}i(De,"nextMessageSeq");function Oe(e,t,r,s){return(s==="page"?e.prepare(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id
28
29
  WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND m.sender_node_id = ?
29
30
  AND m.disposition IN ('human-answer', 'human-canceled') LIMIT 1`).get(r,t):e.prepare(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id
30
- WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND m.body_json LIKE ? LIMIT 1`).get(r,`%"review_id":"${t}"%`))?.delivery_id??null}i(Ae,"importedTerminalDelivery");function te(e,t,r){if(t===null||r===null)return!1;const s=e.prepare("SELECT status, final_report FROM nodes WHERE node_id = ?").get(t);return s?.status==="canceled"||r==="approved"&&s?.status==="done"&&s.final_report!==null}i(te,"companionRetirementProven");function ne(e){if(typeof e!="object"||e===null)return"no reason was given";const t=e.reason;return typeof t=="string"&&t!==""?t:"no reason was given"}i(ne,"migratedCancellationReason");function De(e,t){const r=e.outcome==="canceled"||e.outcome==="dismissed";return[e.kind==="review"?r?`Review ${e.requestId} was canceled \u2014 ${ne(t)}.`:`Review ${e.requestId} was approved by the user.`:r?`Human request ${e.requestId} was canceled \u2014 ${ne(t)}.`:`Human request ${e.requestId} was answered.`,...e.kind==="review"?[`The review result is at ${e.requestDir}/result.json.`]:[],`Result:
31
+ WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND m.body_json LIKE ? LIMIT 1`).get(r,`%"review_id":"${t}"%`))?.delivery_id??null}i(Oe,"importedTerminalDelivery");function te(e,t,r){if(t===null||r===null)return!1;const s=e.prepare("SELECT status, final_report FROM nodes WHERE node_id = ?").get(t);return s?.status==="canceled"||r==="approved"&&s?.status==="done"&&s.final_report!==null}i(te,"companionRetirementProven");function ne(e){if(typeof e!="object"||e===null)return"no reason was given";const t=e.reason;return typeof t=="string"&&t!==""?t:"no reason was given"}i(ne,"migratedCancellationReason");function Ie(e,t){const r=e.outcome==="canceled"||e.outcome==="dismissed";return[e.kind==="review"?r?`Review ${e.requestId} was canceled \u2014 ${ne(t)}.`:`Review ${e.requestId} was approved by the user.`:r?`Human request ${e.requestId} was canceled \u2014 ${ne(t)}.`:`Human request ${e.requestId} was answered.`,...e.kind==="review"?[`The review result is at ${e.requestDir}/result.json.`]:[],`Result:
31
32
  ${JSON.stringify(t,null,2)}`].join(`
32
33
 
33
- `)}i(De,"migratedTerminalBody");function ke(e,t){const r=H(),s=H(),n=Date.parse(t.settledAt),o=Number.isFinite(n)?n:0,u=t.outcome==="answered"||t.outcome==="approved"?"human-answer":"human-canceled",a=JSON.parse(t.resultJson),l=De(t,a);return e.prepare(`INSERT INTO messages
34
+ `)}i(Ie,"migratedTerminalBody");function Le(e,t){const r=H(),s=H(),n=Date.parse(t.settledAt),o=Number.isFinite(n)?n:0,u=t.outcome==="answered"||t.outcome==="approved"?"human-answer":"human-canceled",a=JSON.parse(t.resultJson),l=Ie(t,a);return e.prepare(`INSERT INTO messages
34
35
  (message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition)
35
- VALUES (?, ?, ?, ?, NULL, 'crtrd', 'completed', ?, NULL, ?, ?)`).run(r,Re(e),H(),t.settledAt,l.split(`
36
+ VALUES (?, ?, ?, ?, NULL, 'crtrd', 'completed', ?, NULL, ?, ?)`).run(r,De(e),H(),t.settledAt,l.split(`
36
37
  `,1)[0],JSON.stringify({body:l,result:a}),u),e.prepare(`INSERT INTO deliveries
37
38
  (delivery_id, message_id, destination_kind, destination_id, urgency, wake, state, attempts, created_at, updated_at)
38
- VALUES (?, ?, 'node_inbox', ?, 'normal', 1, 'pending', 0, ?, ?)`).run(s,r,t.requesterNodeId,o,o),s}i(ke,"createMigratedTerminalDelivery");function re(e,t){if(t.requesterNodeId===null||t.outcome===null||t.resultJson===null||t.settledAt===null)return null;const r=Ae(e,t.requestId,t.requesterNodeId,t.kind);return r!==null?r:t.deliveredAt!==null&&t.deliveredAt!==void 0?null:ke(e,{requestId:t.requestId,requesterNodeId:t.requesterNodeId,kind:t.kind,outcome:t.outcome,resultJson:t.resultJson,settledAt:t.settledAt,requestDir:t.requestDir})}i(re,"terminalDeliveryMark");const Ie=d.object({sessionName:d.string().optional(),askedBy:d.string().optional(),blockedSince:d.string().optional(),profileName:d.string().optional(),nodeId:d.string().optional()}).strict(),Oe=d.object({id:d.string().regex(/^[A-Za-z0-9_-]{1,64}$/).optional(),kind:d.string().min(1),step:d.number().int().nonnegative(),config:d.record(d.string(),d.unknown()),unvalidated:d.literal(!0).optional(),display:d.literal(!0).optional()}).strict(),xe=d.object({schema:d.literal("crtr.page/v1"),dialect:d.enum(["md","html","jsx"]),title:d.string().trim().min(1),subtitle:d.string().optional(),placement:d.enum(["inline","panel"]),document:d.enum(["page.md","page.html","page.tsx"]),steps:d.number().int().positive(),slots:d.array(Oe),source:Ie.optional()}).strict().superRefine((e,t)=>{const r=e.dialect==="md"?"page.md":e.dialect==="html"?"page.html":"page.tsx";e.document!==r&&t.addIssue({code:"custom",path:["document"],message:"document must agree with dialect"}),e.dialect==="md"&&e.steps!==1&&t.addIssue({code:"custom",path:["steps"],message:"md pages have exactly one step"})});function Le(e){if(e.source===void 0)return;const{blockedSince:t,...r}=e.source,s={...r,...t!==void 0&&d.string().datetime({offset:!0}).safeParse(t).success?{emittedAt:t}:{}};return Object.keys(s).length===0?void 0:s}i(Le,"legacyPresentationSource");function je(e,t,r){return`export default function LegacyPage() { return <Page title={${JSON.stringify(e)}}${t===void 0?"":` subtitle={${JSON.stringify(t)}}`}><pre>{${JSON.stringify(r)}}</pre></Page>; }
39
- `}i(je,"legacyReplayDocument");function ie(e){return Array.isArray(e.slots)?{...e,slots:e.slots.map(t=>{if(typeof t!="object"||t===null||Array.isArray(t))return t;const r=t;if(r.kind!=="text"||typeof r.config!="object"||r.config===null||Array.isArray(r.config))return t;const{editable:s,...n}=r.config;return{...r,config:n}})}:e}i(ie,"withoutLegacyTextEditable");function we(e,t){const r=c(e,"page.json"),s=xe.safeParse(t);if(!s.success)throw new Error(s.error.message);const n=s.data,o=Le(n),u={placement:n.placement,inbox:!0,reply:n.source?.blockedSince!==void 0};G(ie({schema:"crtr.page/v2",dialect:"jsx",title:n.title,...n.subtitle===void 0?{}:{subtitle:n.subtitle},delivery:u,document:"page.tsx",steps:n.steps,slots:n.slots,...o===void 0?{}:{source:o}}));const a=c(e,n.document);if(!g(a))throw new Error(`corrupt required input: ${a}`);const l=V(a,"utf8"),m=be({dialect:"jsx",document:je(n.title,n.subtitle,l),source:o,delivery:u});if(o!==void 0)return m;const{source:E,...y}=m.manifest;return{...m,manifest:y}}i(we,"migrateLegacyPage");function Tt(e){e.exec(`
39
+ VALUES (?, ?, 'node_inbox', ?, 'normal', 1, 'pending', 0, ?, ?)`).run(s,r,t.requesterNodeId,o,o),s}i(Le,"createMigratedTerminalDelivery");function re(e,t){if(t.requesterNodeId===null||t.outcome===null||t.resultJson===null||t.settledAt===null)return null;const r=Oe(e,t.requestId,t.requesterNodeId,t.kind);return r!==null?r:t.deliveredAt!==null&&t.deliveredAt!==void 0?null:Le(e,{requestId:t.requestId,requesterNodeId:t.requesterNodeId,kind:t.kind,outcome:t.outcome,resultJson:t.resultJson,settledAt:t.settledAt,requestDir:t.requestDir})}i(re,"terminalDeliveryMark");const ke=d.object({sessionName:d.string().optional(),askedBy:d.string().optional(),blockedSince:d.string().optional(),profileName:d.string().optional(),nodeId:d.string().optional()}).strict(),xe=d.object({id:d.string().regex(/^[A-Za-z0-9_-]{1,64}$/).optional(),kind:d.string().min(1),step:d.number().int().nonnegative(),config:d.record(d.string(),d.unknown()),unvalidated:d.literal(!0).optional(),display:d.literal(!0).optional()}).strict(),je=d.object({schema:d.literal("crtr.page/v1"),dialect:d.enum(["md","html","jsx"]),title:d.string().trim().min(1),subtitle:d.string().optional(),placement:d.enum(["inline","panel"]),document:d.enum(["page.md","page.html","page.tsx"]),steps:d.number().int().positive(),slots:d.array(xe),source:ke.optional()}).strict().superRefine((e,t)=>{const r=e.dialect==="md"?"page.md":e.dialect==="html"?"page.html":"page.tsx";e.document!==r&&t.addIssue({code:"custom",path:["document"],message:"document must agree with dialect"}),e.dialect==="md"&&e.steps!==1&&t.addIssue({code:"custom",path:["steps"],message:"md pages have exactly one step"})});function we(e){if(e.source===void 0)return;const{blockedSince:t,...r}=e.source,s={...r,...t!==void 0&&d.string().datetime({offset:!0}).safeParse(t).success?{emittedAt:t}:{}};return Object.keys(s).length===0?void 0:s}i(we,"legacyPresentationSource");function Ce(e,t,r){return`export default function LegacyPage() { return <Page title={${JSON.stringify(e)}}${t===void 0?"":` subtitle={${JSON.stringify(t)}}`}><pre>{${JSON.stringify(r)}}</pre></Page>; }
40
+ `}i(Ce,"legacyReplayDocument");function ie(e){return Array.isArray(e.slots)?{...e,slots:e.slots.map(t=>{if(typeof t!="object"||t===null||Array.isArray(t))return t;const r=t;if(r.kind!=="text"||typeof r.config!="object"||r.config===null||Array.isArray(r.config))return t;const{editable:s,...n}=r.config;return{...r,config:n}})}:e}i(ie,"withoutLegacyTextEditable");function Ue(e,t){const r=c(e,"page.json"),s=je.safeParse(t);if(!s.success)throw new Error(s.error.message);const n=s.data,o=we(n),u={placement:n.placement,inbox:!0,reply:n.source?.blockedSince!==void 0};z(ie({schema:"crtr.page/v2",dialect:"jsx",title:n.title,...n.subtitle===void 0?{}:{subtitle:n.subtitle},delivery:u,document:"page.tsx",steps:n.steps,slots:n.slots,...o===void 0?{}:{source:o}}));const a=c(e,n.document);if(!g(a))throw new Error(`corrupt required input: ${a}`);const l=V(a,"utf8"),m=qe({dialect:"jsx",document:Ce(n.title,n.subtitle,l),source:o,delivery:u});if(o!==void 0)return m;const{source:E,...y}=m.manifest;return{...m,manifest:y}}i(Ue,"migrateLegacyPage");function Rt(e){e.exec(`
40
41
  CREATE TABLE human_requests (
41
42
  request_id TEXT PRIMARY KEY, kind TEXT NOT NULL CHECK (kind IN ('page','review')),
42
43
  inbox_ticket_id TEXT NOT NULL UNIQUE, request_dir TEXT NOT NULL, presentation_dir TEXT,
@@ -65,4 +66,4 @@ ${JSON.stringify(t,null,2)}`].join(`
65
66
  progress_json, feedback_json, result_json, anchor_base_sha256, anchor_base_bytes, created_at, opened_at,
66
67
  submit_requested_at, settled_at, settlement_delivery_id, action_delivery_id, projected_at, projection_error,
67
68
  companion_retired_at, updated_at
68
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);if(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'reviews'").get()!==void 0){const s=e.prepare("SELECT * FROM reviews").all();for(const n of s){const o=n.state,u=o==="approved"||o==="canceled",a=o==="canceled"&&n.result_json===null?JSON.stringify({schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:n.canceled_at,...n.cancel_reason===""||n.cancel_reason===null?{}:{reason:n.cancel_reason},...n.cancel_actor===null?{}:{actor:n.cancel_actor}}):n.result_json;if(u&&a===null)throw new Error(`corrupt required input: reviews/${n.review_id} has no terminal result`);const l=n.bridge_node_id===null?c(z(),"reviews",n.review_id):c(N(),n.bridge_node_id),m={origin_kind:n.origin_kind,bridge_node_id:n.bridge_node_id,origin_session_file:n.origin_session_file,origin_session_id:n.origin_session_id,origin_leaf_id:n.origin_leaf_id,model_spec:n.model_spec,branch_file:n.branch_file,baseline_sha256:n.baseline_sha256,baseline_bytes:n.baseline_bytes,captured_at:n.captured_at,output_path:n.output_path},E=u?o==="approved"?"approved":"canceled":null,y=u?o==="approved"?n.approved_at:n.canceled_at:null,S=re(e,{requestId:n.review_id,requesterNodeId:n.origin_node_id,kind:"review",outcome:E,resultJson:a,settledAt:y,requestDir:l,deliveredAt:n.delivered_at}),D=te(e,n.companion_node_id,E)?y:null;t.run(n.review_id,"review",n.origin_kind==="ticket"?U(N(),w(l)):P(),l,null,n.origin_node_id,n.companion_node_id,n.idempotency_key,u?"settled":o,E,n.origin_kind==="ticket"?1:0,1,w(n.file),n.subtitle,n.file,JSON.stringify(m),null,null,null,a,n.anchor_base_sha256,n.anchor_base_bytes,n.created,n.opened_at,n.submit_requested_at,y,S,null,n.projected_at,n.projection_error,D,n.created)}e.exec("DROP TABLE reviews")}for(const s of g(N())?ce(N(),{withFileTypes:!0}):[]){if(!s.isDirectory())continue;const n=c(N(),s.name),o=c(n,"page.json"),u=c(n,"review.json");if(!g(o)){if(g(u))continue;continue}if(e.prepare("SELECT 1 FROM human_requests WHERE request_id = ?").get(s.name)!==void 0)continue;let a,l,m,E;try{const p=R(o);if(typeof p!="object"||p===null||Array.isArray(p))throw new Error("page manifest must be an object");a=p,a.schema==="crtr.page/v1"?(l=we(n,p),a=l.manifest):a.schema==="crtr.page/v2"&&(a=ie(a));const v=qe.safeParse(a.delivery);if(typeof a.title!="string"||!v.success)throw new Error(v.success?"page title must be a string":v.error.message);E=v.data,m=G(a)}catch(p){const v=p instanceof Error&&p.cause instanceof Error?p.cause.message:p instanceof Error?p.message:String(p);console.warn(`skipping legacy page ${o}: ${v}`);continue}let y=O(n);l!==void 0&&(y=ee(C(s.name),l));const S=m.source,D=c(n,"response.json"),k=g(D)?R(D):null,h=k===null?null:ve(k),se=e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'deliveries'").get()===void 0?null:e.prepare("SELECT delivery_id FROM deliveries WHERE idempotency_key = ?").get(`human-action:${U(N(),s.name)}`),X=c(n,"action.json"),$=c(n,"progress.json"),x=c(n,"feedback-comments.json"),L=c(n,"reply-route.json"),q=g(x)?R(x):null;if(q!==null&&(typeof q!="object"||typeof q.companionNodeId<"u"&&typeof q.companionNodeId!="string"))throw new Error(`corrupt required input: ${x}`);const I=g(L)?R(L):null;if(I!==null&&(typeof I!="object"||typeof I.bridge_node_id!="string"))throw new Error(`corrupt required input: ${L}`);const M=I?.bridge_node_id,F=(typeof M!="string"||e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'nodes'").get()===void 0?null:e.prepare("SELECT parent FROM nodes WHERE node_id = ?").get(M))?.parent??(typeof S?.nodeId=="string"?S.nodeId:null),W=q?.companionNodeId,J=typeof S?.emittedAt=="string"?S.emittedAt:le(o).mtime.toISOString(),B=k===null?null:JSON.stringify(k),oe=re(e,{requestId:s.name,requesterNodeId:F,kind:"page",outcome:h?.outcome??null,resultJson:B,settledAt:h?.settledAt??null,requestDir:n}),ae=te(e,W??null,h?.outcome??null)?h?.settledAt??null:null,K=C(s.name);A(K,{recursive:!0,mode:448}),t.run(s.name,"page",U(N(),s.name),K,y,F,W??null,null,h===null?"open":"settled",h?.outcome??null,E.inbox?1:0,E.inbox||E.reply?1:0,m.title,m.subtitle??null,null,JSON.stringify(m),g(X)?JSON.stringify(R(X)):null,g($)&&h===null?JSON.stringify(R($)):null,q===null?null:JSON.stringify(q),B,null,null,J,null,null,h?.settledAt??null,oe,se?.delivery_id??null,null,null,ae,J)}const r=e.prepare("SELECT request_id FROM human_requests WHERE state = 'settled' AND result_json IS NULL").get();if(r!==void 0)throw new Error(`human request migration produced terminal row without result: ${r.request_id}`);if(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'review_comments'").get()!==void 0){const s=e.prepare("SELECT review_id FROM review_comments WHERE review_id NOT IN (SELECT request_id FROM human_requests WHERE kind = 'review') LIMIT 1").get();if(s!==void 0)throw new Error(`review comment has no migrated review request: ${s.review_id}`)}}i(Tt,"migrateHumanRequestsState");export{lt as cancelBindingRequest,Qe as commitBindingRequest,Ge as createPageRequest,Ye as getRequest,tt as getRequestByCompanion,et as getRequestByDirectory,nt as getRequestByIdempotencyKey,Ze as getRequestByInboxTicket,it as hasOpenReplyBearingRequestByRequester,Z as humanRequestsRoot,ot as listBindingRequests,rt as listOpenInboxRequests,st as listOpenReplyBearingRequests,ut as listRequests,at as listSubmitRequestedRequests,dt as listUnprojectedReviews,bt as markCompanionRetired,yt as markProjected,ht as markProjectionError,Tt as migrateHumanRequestsState,ct as openRequest,Se as openRequestsByRequester,ze as presentationDir,ee as publishPageRevision,qt as readAnchorBase,Nt as replaceAnchorBaseLocked,C as requestDir,_t as requestSubmit,Et as revisePageRequest,mt as setSettlementDeliveryMarksLocked,ft as setSubmitNoteDeliveryLocked,pt as settleRequestLocked,gt as writeProgress};
69
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);if(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'reviews'").get()!==void 0){const s=e.prepare("SELECT * FROM reviews").all();for(const n of s){const o=n.state,u=o==="approved"||o==="canceled",a=o==="canceled"&&n.result_json===null?JSON.stringify({schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:n.canceled_at,...n.cancel_reason===""||n.cancel_reason===null?{}:{reason:n.cancel_reason},...n.cancel_actor===null?{}:{actor:n.cancel_actor}}):n.result_json;if(u&&a===null)throw new Error(`corrupt required input: reviews/${n.review_id} has no terminal result`);const l=n.bridge_node_id===null?c(Q(),"reviews",n.review_id):c(b(),n.bridge_node_id),m={origin_kind:n.origin_kind,bridge_node_id:n.bridge_node_id,origin_session_file:n.origin_session_file,origin_session_id:n.origin_session_id,origin_leaf_id:n.origin_leaf_id,model_spec:n.model_spec,branch_file:n.branch_file,baseline_sha256:n.baseline_sha256,baseline_bytes:n.baseline_bytes,captured_at:n.captured_at,output_path:n.output_path},E=u?o==="approved"?"approved":"canceled":null,y=u?o==="approved"?n.approved_at:n.canceled_at:null,S=re(e,{requestId:n.review_id,requesterNodeId:n.origin_node_id,kind:"review",outcome:E,resultJson:a,settledAt:y,requestDir:l,deliveredAt:n.delivered_at}),D=te(e,n.companion_node_id,E)?y:null;t.run(n.review_id,"review",n.origin_kind==="ticket"?P(b(),w(l)):U(),l,null,n.origin_node_id,n.companion_node_id,n.idempotency_key,u?"settled":o,E,n.origin_kind==="ticket"?1:0,1,w(n.file),n.subtitle,n.file,JSON.stringify(m),null,null,null,a,n.anchor_base_sha256,n.anchor_base_bytes,n.created,n.opened_at,n.submit_requested_at,y,S,null,n.projected_at,n.projection_error,D,n.created)}e.exec("DROP TABLE reviews")}for(const s of g(b())?ce(b(),{withFileTypes:!0}):[]){if(!s.isDirectory())continue;const n=c(b(),s.name),o=c(n,"page.json"),u=c(n,"review.json");if(!g(o)){if(g(u))continue;continue}if(e.prepare("SELECT 1 FROM human_requests WHERE request_id = ?").get(s.name)!==void 0)continue;let a,l,m,E;try{const p=R(o);if(typeof p!="object"||p===null||Array.isArray(p))throw new Error("page manifest must be an object");a=p,a.schema==="crtr.page/v1"?(l=Ue(n,p),a=l.manifest):a.schema==="crtr.page/v2"&&(a=ie(a));const v=Ne.safeParse(a.delivery);if(typeof a.title!="string"||!v.success)throw new Error(v.success?"page title must be a string":v.error.message);E=v.data,m=z(a)}catch(p){const v=p instanceof Error&&p.cause instanceof Error?p.cause.message:p instanceof Error?p.message:String(p);console.warn(`skipping legacy page ${o}: ${v}`);continue}let y=L(n);l!==void 0&&(y=ee(C(s.name),l));const S=m.source,D=c(n,"response.json"),O=g(D)?R(D):null,h=O===null?null:Ae(O),se=e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'deliveries'").get()===void 0?null:e.prepare("SELECT delivery_id FROM deliveries WHERE idempotency_key = ?").get(`human-action:${P(b(),s.name)}`),X=c(n,"action.json"),$=c(n,"progress.json"),k=c(n,"feedback-comments.json"),x=c(n,"reply-route.json"),N=g(k)?R(k):null;if(N!==null&&(typeof N!="object"||typeof N.companionNodeId<"u"&&typeof N.companionNodeId!="string"))throw new Error(`corrupt required input: ${k}`);const I=g(x)?R(x):null;if(I!==null&&(typeof I!="object"||typeof I.bridge_node_id!="string"))throw new Error(`corrupt required input: ${x}`);const M=I?.bridge_node_id,F=(typeof M!="string"||e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'nodes'").get()===void 0?null:e.prepare("SELECT parent FROM nodes WHERE node_id = ?").get(M))?.parent??(typeof S?.nodeId=="string"?S.nodeId:null),W=N?.companionNodeId,J=typeof S?.emittedAt=="string"?S.emittedAt:le(o).mtime.toISOString(),B=O===null?null:JSON.stringify(O),oe=re(e,{requestId:s.name,requesterNodeId:F,kind:"page",outcome:h?.outcome??null,resultJson:B,settledAt:h?.settledAt??null,requestDir:n}),ae=te(e,W??null,h?.outcome??null)?h?.settledAt??null:null,K=C(s.name);A(K,{recursive:!0,mode:448}),t.run(s.name,"page",P(b(),s.name),K,y,F,W??null,null,h===null?"open":"settled",h?.outcome??null,E.inbox?1:0,E.inbox||E.reply?1:0,m.title,m.subtitle??null,null,JSON.stringify(m),g(X)?JSON.stringify(R(X)):null,g($)&&h===null?JSON.stringify(R($)):null,N===null?null:JSON.stringify(N),B,null,null,J,null,null,h?.settledAt??null,oe,se?.delivery_id??null,null,null,ae,J)}const r=e.prepare("SELECT request_id FROM human_requests WHERE state = 'settled' AND result_json IS NULL").get();if(r!==void 0)throw new Error(`human request migration produced terminal row without result: ${r.request_id}`);if(e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'review_comments'").get()!==void 0){const s=e.prepare("SELECT review_id FROM review_comments WHERE review_id NOT IN (SELECT request_id FROM human_requests WHERE kind = 'review') LIMIT 1").get();if(s!==void 0)throw new Error(`review comment has no migrated review request: ${s.review_id}`)}}i(Rt,"migrateHumanRequestsState");export{ve as NOT_OTHER_APP_QUESTION,mt as cancelBindingRequest,et as commitBindingRequest,Ze as createPageRequest,tt as getRequest,it as getRequestByCompanion,rt as getRequestByDirectory,st as getRequestByIdempotencyKey,nt as getRequestByInboxTicket,at as hasOpenReplyBearingRequestByRequester,Z as humanRequestsRoot,ut as listBindingRequests,ot as listOpenInboxRequests,dt as listOpenReplyBearingRequests,_t as listRequests,ct as listSubmitRequestedRequests,lt as listUnprojectedReviews,Tt as markCompanionRetired,Nt as markProjected,bt as markProjectionError,Rt as migrateHumanRequestsState,pt as openRequest,Re as openRequestsByRequester,Ye as presentationDir,ee as publishPageRevision,St as readAnchorBase,vt as replaceAnchorBaseLocked,C as requestDir,ft as requestSubmit,ht as revisePageRequest,gt as setSettlementDeliveryMarksLocked,yt as setSubmitNoteDeliveryLocked,Et as settleRequestLocked,qt as writeProgress};
@@ -1 +1 @@
1
- var p=Object.defineProperty;var n=(e,t)=>p(e,"name",{value:t,configurable:!0});import{pageAwaitsResponse as m,pageOverviewActions as u}from"./page-schema.js";import{listRequests as s}from"./requests.js";function a(e){try{const t=JSON.parse(e.specification_json);if(typeof t!="object"||t===null)throw new Error("not an object");return t}catch(t){throw new Error(`corrupt human request specification: ${e.request_id}`,{cause:t})}}n(a,"specification");function r(e){const t=a(e),{recommendedOptions:i,fastAction:o}=u(t),d=e.result_json===null?null:JSON.parse(e.result_json),c=e.state!=="settled"?e.settleable?"pending":"passive":e.outcome==="canceled"||e.outcome==="dismissed"?"canceled":"resolved";return{dir:e.request_dir,id:e.request_id,inboxTicketId:e.inbox_ticket_id,kind:"page",title:e.title,subtitle:e.subtitle??"",dialect:t.dialect,placement:t.delivery.placement,inbox:e.inbox_listed,steps:t.steps,slotKinds:t.slots.map(l=>l.kind),awaitsResponse:m(t),source:t.source??{},emittedAt:typeof t.source?.emittedAt=="string"?t.source.emittedAt:e.created_at,recommendedOptions:i,...o===void 0||c!=="pending"?{}:{fastAction:o},state:c,...d?.kind==="page"?{answerDigest:d.summary.replace(/\s+/g," ").trim()}:{}}}n(r,"pageSummary");function f(e){const t=a(e),i={nodeId:e.requester_node_id??void 0};return{dir:e.request_dir,id:e.request_id,inboxTicketId:e.inbox_ticket_id,kind:"review",title:e.title,subtitle:e.subtitle??"",file:e.file??"",output:typeof t.output_path=="string"?t.output_path:`${e.request_dir}/result.json`,source:i,blockedSince:e.created_at}}n(f,"reviewSummary");function b(){return s({state:"open"}).filter(e=>e.inbox_listed).map(e=>e.kind==="page"?r(e):f(e)).sort((e,t)=>(t.kind==="page"?t.emittedAt:t.blockedSince).localeCompare(e.kind==="page"?e.emittedAt:e.blockedSince)||e.id.localeCompare(t.id))}n(b,"scanInbox");function w(e){return s({kind:"page"}).map(r).filter(t=>e===void 0||t.source.nodeId===e).sort((t,i)=>Date.parse(t.emittedAt)-Date.parse(i.emittedAt)||t.id.localeCompare(i.id))}n(w,"scanPageHistory");export{b as scanInbox,w as scanPageHistory};
1
+ var l=Object.defineProperty;var n=(e,t)=>l(e,"name",{value:t,configurable:!0});import{pageAwaitsResponse as p,pageOverviewActions as m}from"./page-schema.js";import{listOpenInboxRequests as u,listRequests as f}from"./requests.js";function c(e){try{const t=JSON.parse(e.specification_json);if(typeof t!="object"||t===null)throw new Error("not an object");return t}catch(t){throw new Error(`corrupt human request specification: ${e.request_id}`,{cause:t})}}n(c,"specification");function a(e){const t=c(e),{recommendedOptions:i,fastAction:o}=m(t),d=e.result_json===null?null:JSON.parse(e.result_json),s=e.state!=="settled"?e.settleable?"pending":"passive":e.outcome==="canceled"||e.outcome==="dismissed"?"canceled":"resolved";return{dir:e.request_dir,id:e.request_id,inboxTicketId:e.inbox_ticket_id,kind:"page",title:e.title,subtitle:e.subtitle??"",dialect:t.dialect,placement:t.delivery.placement,inbox:e.inbox_listed,steps:t.steps,slotKinds:t.slots.map(r=>r.kind),awaitsResponse:p(t),source:t.source??{},emittedAt:typeof t.source?.emittedAt=="string"?t.source.emittedAt:e.created_at,recommendedOptions:i,...o===void 0||s!=="pending"?{}:{fastAction:o},state:s,...d?.kind==="page"?{answerDigest:d.summary.replace(/\s+/g," ").trim()}:{}}}n(a,"pageSummary");function _(e){const t=c(e),i={nodeId:e.requester_node_id??void 0};return{dir:e.request_dir,id:e.request_id,inboxTicketId:e.inbox_ticket_id,kind:"review",title:e.title,subtitle:e.subtitle??"",file:e.file??"",output:typeof t.output_path=="string"?t.output_path:`${e.request_dir}/result.json`,source:i,blockedSince:e.created_at}}n(_,"reviewSummary");function w(){return u().map(e=>e.kind==="page"?a(e):_(e)).sort((e,t)=>(t.kind==="page"?t.emittedAt:t.blockedSince).localeCompare(e.kind==="page"?e.emittedAt:e.blockedSince)||e.id.localeCompare(t.id))}n(w,"scanInbox");function x(e){return f({kind:"page"}).map(a).filter(t=>e===void 0||t.source.nodeId===e).sort((t,i)=>Date.parse(t.emittedAt)-Date.parse(i.emittedAt)||t.id.localeCompare(i.id))}n(x,"scanPageHistory");export{w as scanInbox,x as scanPageHistory};
@@ -1,6 +1,17 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import type { NodeMeta } from '../canvas/types.js';
3
3
  import type { AppPrincipal } from '../../daemon/api/principal.js';
4
+ import { type ResolvedAttachments } from '../storage/attachments.js';
5
+ import { type StorageClient, type StorageConfig } from '../storage/client.js';
6
+ /** Fetches the storage URLs of a run's text into the run's `attachments/`. */
7
+ export type AttachmentResolver = (runId: string, grantee: string, text: string) => Promise<ResolvedAttachments>;
8
+ /** Storage deletes `run.delete` waits for before it answers. */
9
+ export declare const RUN_DELETE_STORAGE_BUDGET_MS = 3000;
10
+ export interface StorageDeps {
11
+ config: () => StorageConfig | null;
12
+ client: () => StorageClient;
13
+ budgetMs?: number;
14
+ }
4
15
  /** OWN-11 for a joined runtime: the legacy `user:local` grantee is the terminal app. */
5
16
  export declare function rewriteLocalIdempotencyGrantee(db: DatabaseSync): number;
6
17
  export declare class RunError extends Error {
@@ -13,13 +24,14 @@ export declare class RunError extends Error {
13
24
  constructor(status: number, code: string, message: string, param?: string | undefined, details?: unknown | undefined, scope?: string | undefined, retryable?: boolean);
14
25
  }
15
26
  export declare function ownedRun(id: string, grantee: string, allowDeleting?: boolean): NodeMeta;
27
+ export type RunStatus = 'running' | 'waiting_on_user' | 'idle' | 'settled';
16
28
  export declare function runObject(root: NodeMeta): Record<string, unknown>;
17
29
  export declare function startRun(principal: AppPrincipal, input: {
18
30
  prompt: string;
19
31
  scopes: string[] | null;
20
32
  metadata: Record<string, unknown>;
21
33
  profile?: string;
22
- }, idempotencyKey?: string): Promise<Record<string, unknown>>;
34
+ }, idempotencyKey?: string, resolveAttachments?: AttachmentResolver): Promise<Record<string, unknown>>;
23
35
  export declare function listRuns(grantee: string | null, options: {
24
36
  status?: string;
25
37
  after?: string;
@@ -29,7 +41,7 @@ export declare function listRuns(grantee: string | null, options: {
29
41
  next: string | null;
30
42
  };
31
43
  export declare function waitRun(id: string, grantee: string, seconds: number): Promise<Record<string, unknown>>;
32
- export declare function messageRun(root: NodeMeta, message: string): Promise<{
44
+ export declare function messageRun(root: NodeMeta, original: string, resolveAttachments?: AttachmentResolver): Promise<{
33
45
  run_id: string;
34
46
  message_id: string;
35
47
  sequence_number: number;
@@ -38,6 +50,15 @@ export declare function interruptRun(root: NodeMeta, children?: 'stop' | 'contin
38
50
  export declare function cancelRun(root: NodeMeta, _options?: {
39
51
  keepSchedules?: boolean;
40
52
  }): Promise<Record<string, unknown>>;
41
- export declare function deleteRun(root: NodeMeta): Promise<void>;
53
+ /** The longest run name `run.rename` accepts. */
54
+ export declare const RUN_NAME_MAX = 200;
55
+ /** `run.rename`: set the root node's name — the name `crtr` shows for the node —
56
+ * through the same path as `PATCH /v1/nodes/:id/config` `name`. */
57
+ export declare function renameRun(root: NodeMeta, name: unknown): Record<string, unknown>;
58
+ /** Delete a run. Answers how many of the run's released uploads storage has
59
+ * not confirmed deleted; the due-work tick retries those. */
60
+ export declare function deleteRun(root: NodeMeta, storage?: StorageDeps): Promise<{
61
+ uploads_pending: number;
62
+ }>;
42
63
  export declare function traceRun(id: string, grantee: string, format?: string): Record<string, unknown>;
43
64
  export declare function requestedScopes(held: readonly string[], value: unknown, grantee: string): string[] | null;
@@ -1,12 +1,12 @@
1
- var te=Object.defineProperty;var u=(e,t)=>te(e,"name",{value:t,configurable:!0});import{createHash as ne}from"node:crypto";import{join as re}from"node:path";import{SessionManager as se}from"@earendil-works/pi-coding-agent";import{covers as b}from"@north-light/crouter-identity";import{openDb as oe,withCanvasWrite as F}from"../canvas/db.js";import{repairRunConversations as H}from"../canvas/sessions.js";import{getNode as w,nodeFiles as ie,removeNodeFiles as de}from"../canvas/canvas.js";import{liveExecutionForNode as x}from"../canvas/executions.js";import{nodeAgentDir as ae,reportsDir as ce}from"../canvas/node-agent-paths.js";import{isAbsentOrRefused as W,readdirBeneath as ue,readFileBeneath as me}from"../spaces/open-beneath.js";import{conversationStore as q,isConversationNotFound as pe}from"../conversation-store/index.js";import{enqueueNodeMail as _e}from"../feed/messages.js";import{ensureAppProfile as le,loadExactProfileManifest as fe}from"../profiles/manifest.js";import{stopNodeSandboxes as B}from"../spaces/stop.js";import{BrokerUnreachableError as Ee}from"../runtime/broker-request.js";import{interruptLive as ge}from"../runtime/interactive-deliver.js";import{isBrokerLive as j}from"../runtime/model-swap.js";import{newNodeId as ye}from"../runtime/nodes.js";import{writeGoal as Re}from"../runtime/kickoff.js";import{reviveNode as J}from"../runtime/revive.js";import{spawnChildPrepared as we}from"../runtime/spawn.js";import{cycleAwareMessages as he}from"../runtime/session-cycles.js";import{originFor as P}from"../runtime/stamp/protocol.js";import{readOutputResult as Se}from"../runtime/structured-output.js";import{toRunOutcomeDTO as Ne}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as ve}from"../../daemon/runs/observer.js";import{closeNode as $}from"../runtime/close.js";import{parseScope as Oe}from"@north-light/crouter-identity";import{appendRunEvent as U,subscribeRunEvents as Te}from"./events.js";import{appSpace as be}from"../layout.js";import{ensureAppSpace as De}from"../spaces/space.js";function at(e){return Number(e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}u(at,"rewriteLocalIdempotencyGrantee");class E extends Error{static{u(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,i,n,d,c,r,s=t===503){super(n),this.status=t,this.code=i,this.param=d,this.details=c,this.scope=r,this.retryable=s}}const D=u((e,t)=>new E(400,"invalid_request",e,t),"invalid"),C=u(()=>new E(404,"not_found","run not found"),"missing"),I=u(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),y=u(()=>oe(),"db");function L(e,t,i=!1){const n=w(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!i&&n.deleting_at)throw C();return n}u(L,"ownedRun");function O(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=y().prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
1
+ var ae=Object.defineProperty;var p=(e,t)=>ae(e,"name",{value:t,configurable:!0});import{createHash as ce}from"node:crypto";import{join as ue}from"node:path";import{SessionManager as me}from"@earendil-works/pi-coding-agent";import{covers as A}from"@north-light/crouter-identity";import{openDb as pe,withCanvasWrite as H}from"../canvas/db.js";import{repairRunConversations as W}from"../canvas/sessions.js";import{getNode as h,nodeFiles as le,removeNodeFiles as _e,updateNode as fe}from"../canvas/canvas.js";import{fullName as Ee}from"../canvas/labels.js";import{renameWindow as ge}from"../runtime/placement.js";import{liveExecutionForNode as q}from"../canvas/executions.js";import{nodeAgentDir as we,reportsDir as ye}from"../canvas/node-agent-paths.js";import{isAbsentOrRefused as U,readdirBeneath as Re,readFileBeneath as he}from"../spaces/open-beneath.js";import{conversationStore as B,isConversationNotFound as Se}from"../conversation-store/index.js";import{enqueueNodeMail as Ne}from"../feed/messages.js";import{ensureAppProfile as ve,loadExactProfileManifest as Oe}from"../profiles/manifest.js";import{stopNodeSandboxes as P}from"../spaces/stop.js";import{BrokerUnreachableError as Te}from"../runtime/broker-request.js";import{interruptLive as be}from"../runtime/interactive-deliver.js";import{isBrokerLive as j}from"../runtime/model-swap.js";import{newNodeId as De}from"../runtime/nodes.js";import{writeGoal as Me}from"../runtime/kickoff.js";import{reviveNode as J}from"../runtime/revive.js";import{spawnChildPrepared as Ae}from"../runtime/spawn.js";import{cycleAwareMessages as Le}from"../runtime/session-cycles.js";import{originFor as $}from"../runtime/stamp/protocol.js";import{readOutputResult as Ce}from"../runtime/structured-output.js";import{toRunOutcomeDTO as Ie}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as ke}from"../../daemon/runs/observer.js";import{closeNode as G}from"../runtime/close.js";import{parseScope as Fe}from"@north-light/crouter-identity";import{appendRunEvent as Y,subscribeRunEvents as xe}from"./events.js";import{cancelOpenQuestions as X,openQuestionIds as z}from"./questions.js";import{appSpace as He}from"../layout.js";import{ensureAppSpace as We}from"../spaces/space.js";import{assertUploadsUsable as Q,resolveStorageUrls as qe}from"../storage/attachments.js";import{storageClient as Ue,storageConfig as Be}from"../storage/client.js";import{deleteUploadRow as Pe,insertUploadUses as V,releaseRunUploads as je}from"../storage/tables.js";const Z=p((e,t,s)=>qe(t,e,s),"defaultResolver"),Je=3e3;function Lt(e){return Number(e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}p(Lt,"rewriteLocalIdempotencyGrantee");class y extends Error{static{p(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,s,n,c,d,i,r=t===503){super(n),this.status=t,this.code=s,this.param=c,this.details=d,this.scope=i,this.retryable=r}}const b=p((e,t)=>new y(400,"invalid_request",e,t),"invalid"),I=p(()=>new y(404,"not_found","run not found"),"missing"),k=p(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),S=p(()=>pe(),"db");function L(e,t,s=!1){const n=h(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!s&&n.deleting_at)throw I();return n}p(L,"ownedRun");const F=["waiting_on_user","idle","settled"];function D(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=S().prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
2
2
  (n.last_settled_at IS NULL OR EXISTS (
3
3
  SELECT 1 FROM run_events e WHERE e.run_id = ? AND e.node_id = n.node_id AND e.type = 'node.turn.started'
4
4
  AND e.sequence_number > COALESCE((SELECT MAX(c.sequence_number) FROM run_events c
5
5
  WHERE c.run_id = e.run_id AND c.node_id = e.node_id AND c.type = 'node.turn.completed'), 0)
6
- )) LIMIT 1`).get(e.node_id,e.node_id),i=y().prepare("SELECT 1 FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||i||!e.last_settled_at?"running":"idle"}u(O,"runStatus");function M(e){H(e.node_id),e=w(e.node_id)??e;const t=O(e),i=ae(e.node_id),n=ce(e.node_id);let d;try{d=ue(i,n).filter(o=>o.isFile()).map(o=>o.name).filter(o=>/-(?:update|urgent|final)\.md$/.test(o)).sort().at(-1)}catch(o){if(!W(o))throw o}let c;try{c=d?me(i,re(n,d)).toString("utf8").replace(/^---\n[\s\S]*?\n---\n/,""):void 0}catch(o){if(!W(o))throw o}const r=t==="settled"?Ne(e):null,s=r?.kind==="result"?Se(e.node_id,e.grantee):void 0;return{run_id:e.node_id,status:t,...r?{outcome:r}:{},...s===void 0?{}:{result:s},...c!==void 0?{last_report:c}:{},pending_question_ids:[],usage:JSON.parse(e.usage_json??JSON.stringify(I())),payer:"user",scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at}}u(M,"runObject");async function ct(e,t,i){const n=ne("sha256").update(JSON.stringify(t)).digest("hex");if(i){const o=y().prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e.grantee,i);if(o&&Date.now()-Date.parse(o.created_at)<864e5){if(o.body_hash!==n)throw new E(409,"idempotency_conflict","key used with a different request");const _=L(o.run_id,e.grantee);return!_.pi_pid&&O(_)==="running"&&await J(_.node_id,{resume:!0,capacity:"freeze"}),JSON.parse(o.response_json)}}await De(e.grantee);const d=t.profile===void 0?le(e.grantee):fe(t.profile),c=d.manifest.grantee??"app:terminal";if(c!==e.grantee){const o=`crtr:memory:rw:${c}:profile:${d.profileId}`;if(!e.resolved.some(_=>b(_,o))||t.scopes!==null&&!t.scopes.some(_=>b(_,o)))throw new E(403,"scope_missing",`missing scope ${o}`,"profile",void 0,o)}const r=ye();let s;if(await we({kind:"developer",mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:be(e.grantee).files,profile:d.profileId,prompt:t.prompt,nodeId:r,...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:r,event_cursor:1,usage_json:JSON.stringify(I())},withinCreate:u((o,_)=>{Re(r,t.prompt),s={run_id:r,node_id:r,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:_.created,metadata:t.metadata,sequence_number:0},U(o,r,r,"run.started",{served_model:_.launch?.model??null,scopes:t.scopes,payer:"user",usage:I()}),i&&(o.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(e.grantee,i,new Date(Date.now()-864e5).toISOString()),o.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(e.grantee,i,n,r,JSON.stringify(s),_.created))},"withinCreate")}),!s)throw new Error("run creation did not commit");return s}u(ct,"startRun");function ut(e,t){let i;if(t.after)try{const s=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!s||typeof s!="object"||!("activity"in s)||typeof s.activity!="string"||!("id"in s)||typeof s.id!="string")throw new Error("invalid cursor");i={activity:s.activity,id:s.id}}catch{throw D("invalid list cursor","after")}const d=y().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM nodes
6
+ )) LIMIT 1`).get(e.node_id,e.node_id),s=S().prepare("SELECT 1 FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||s||!e.last_settled_at?"running":z(e.node_id).length?"waiting_on_user":"idle"}p(D,"runStatus");function M(e){W(e.node_id),e=h(e.node_id)??e;const t=D(e),s=t==="settled"?[]:z(e.node_id),n=we(e.node_id),c=ye(e.node_id);let d;try{d=Re(n,c).filter(u=>u.isFile()).map(u=>u.name).filter(u=>/-(?:update|urgent|final)\.md$/.test(u)).sort().at(-1)}catch(u){if(!U(u))throw u}let i;try{i=d?he(n,ue(c,d)).toString("utf8").replace(/^---\n[\s\S]*?\n---\n/,""):void 0}catch(u){if(!U(u))throw u}const r=t==="settled"?Ie(e):null,o=r?.kind==="result"?Ce(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...r?{outcome:r}:{},...o===void 0?{}:{result:o},...i!==void 0?{last_report:i}:{},pending_question_ids:s,usage:JSON.parse(e.usage_json??JSON.stringify(k())),payer:"user",scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at}}p(M,"runObject");async function Ct(e,t,s,n=Z){const c=ce("sha256").update(JSON.stringify(t)).digest("hex");if(s){const a=S().prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e.grantee,s);if(a&&Date.now()-Date.parse(a.created_at)<864e5){if(a.body_hash!==c)throw new y(409,"idempotency_conflict","key used with a different request");const E=L(a.run_id,e.grantee);return!E.pi_pid&&D(E)==="running"&&await J(E.node_id,{resume:!0,capacity:"freeze"}),JSON.parse(a.response_json)}}await We(e.grantee);const d=t.profile===void 0?ve(e.grantee):Oe(t.profile),i=d.manifest.grantee??"app:terminal";if(i!==e.grantee){const a=`crtr:memory:rw:${i}:profile:${d.profileId}`;if(!e.resolved.some(E=>A(E,a))||t.scopes!==null&&!t.scopes.some(E=>A(E,a)))throw new y(403,"scope_missing",`missing scope ${a}`,"profile",void 0,a)}const r=De(),o=await n(r,e.grantee,t.prompt),u=o.text;let f;try{await Ae({kind:"developer",mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:He(e.grantee).files,profile:d.profileId,prompt:u,nodeId:r,...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:r,event_cursor:1,usage_json:JSON.stringify(k())},withinCreate:p((a,E)=>{o.uses.length&&(Q(e.grantee,o.uses,a),V(o.uses.map(({upload_id:l,path:g})=>({upload_id:l,path:g,run_id:r})),a)),Me(r,u),f={run_id:r,node_id:r,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:E.created,metadata:t.metadata,sequence_number:0},Y(a,r,r,"run.started",{served_model:E.launch?.model??null,scopes:t.scopes,payer:"user",usage:k()}),s&&(a.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(e.grantee,s,new Date(Date.now()-864e5).toISOString()),a.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(e.grantee,s,c,r,JSON.stringify(f),E.created))},"withinCreate")})}catch(a){throw h(r)||o.cleanup(),a}if(!f)throw new Error("run creation did not commit");return f}p(Ct,"startRun");function It(e,t){let s;if(t.after)try{const r=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!r||typeof r!="object"||!("activity"in r)||typeof r.activity!="string"||!("id"in r)||typeof r.id!="string")throw new Error("invalid cursor");s={activity:r.activity,id:r.id}}catch{throw b("invalid list cursor","after")}const c=S().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM nodes
7
7
  WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}
8
- ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({activity:s,node_id:o})=>!i||s<i.activity||s===i.activity&&o<i.id).map(s=>({root:w(s.node_id),activity:s.activity})).filter(({root:s})=>!t.status||O(s)===t.status),c=d.slice(0,t.limit),r=c.at(-1);return{runs:c.map(({root:s})=>M(s)),next:d.length>t.limit&&r?Buffer.from(JSON.stringify({activity:r.activity,id:r.root.node_id})).toString("base64url"):null}}u(ut,"listRuns");async function mt(e,t,i){const n=L(e,t),d=u(()=>M(L(e,t)),"read");return!i||["idle","settled"].includes(O(n))?d():new Promise((c,r)=>{const s=u(()=>{clearTimeout(T),clearInterval(_),o();try{c(d())}catch(h){r(h)}},"finish"),o=Te(e,()=>{try{["idle","settled"].includes(String(d().status))&&s()}catch(h){clearTimeout(T),clearInterval(_),o(),r(h)}}),_=setInterval(()=>{["idle","settled"].includes(String(d().status))&&s()},250),T=setTimeout(s,i*1e3)})}u(mt,"waitRun");async function pt(e,t){if(e.status==="canceled"||e.outcome_reason==="closed")throw new E(409,"run_settled","canceled run cannot receive a message");if(e.final_report&&!e.pi_pid){const{commitReopenResident:d}=await import("../runtime/reopen.js");d(e.node_id)}const i=_e(e.node_id,{kind:"message",label:t.slice(0,120),senderNodeId:"human",bodyJson:{body:t},urgency:"normal",wake:1,withinEnqueue:u((d,c)=>{U(d,e.node_id,e.node_id,"node.message.accepted",{message_id:c})},"withinEnqueue")}),n=y().prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e.node_id).event_cursor-1;return e.pi_pid||await J(e.node_id,{resume:!0,capacity:"freeze"}),{run_id:e.node_id,message_id:i.messageId,sequence_number:n}}u(pt,"messageRun");async function Le(e){const t=u(()=>new E(503,"server_error",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let i=0;i<2;i++){const n=w(e);if(!n)throw C();if(!j(n)){if(n.streaming)throw t();return}const d=x(e)?.executionId;try{await ge(e);return}catch(c){if(!(c instanceof Ee))throw c;const r=w(e);if(!r)throw C();if(!r.streaming)return;if(i===0&&j(r)&&x(e)?.executionId!==d)continue;throw t()}}throw t()}u(Le,"interruptNode");async function _t(e,t="stop"){const i=t==="stop"?y().prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:n})=>n):[e.node_id];return await Promise.all(i.map(n=>Le(n))),M(w(e.node_id)??e)}u(_t,"interruptRun");async function lt(e,t={}){const i=y().prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(r=>r.node_id),n=[];if(O(e)!=="settled")n.push(...$(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const r of i){if(r===e.node_id)continue;const s=w(r);s&&s.status!=="done"&&s.status!=="canceled"&&s.status!=="dead"&&n.push(...$(r,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if((await Promise.all([...new Set([e.node_id,...n])].map(r=>B(r,"run_canceled")))).some(r=>!r.confirmed))throw new E(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const c=w(e.node_id);return M(c??e)}u(lt,"cancelRun");async function ft(e){const t=F(r=>(r.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),r.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(s=>s.node_id)));if((await Promise.all(t.map(r=>B(r,"run_deleted",{deleting:!0})))).some(r=>!r.confirmed))throw new E(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const n=t.map(r=>{const s=ie(r);if(s.app===null)throw new Error(`run node missing during deletion: ${r}`);return s}),d=y().prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:r}of d)try{q().delete(r)}catch(s){if(!pe(s))throw s}F(r=>{r.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),r.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const s=r.prepare("SELECT message_id FROM messages WHERE sender_node_id IN (SELECT node_id FROM nodes WHERE run_id = ?) UNION SELECT message_id FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id,e.node_id);r.prepare("DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").run(e.node_id);for(const{message_id:o}of s)r.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(o,o);for(const o of t)r.prepare("DELETE FROM nodes WHERE node_id = ?").run(o)});for(const r of n)de(r);const{notifyRunDeleted:c}=await import("./events.js");c(e.node_id)}u(ft,"deleteRun");function Et(e,t,i){L(e,t),H(e);const n=y();n.exec("BEGIN");try{const c=n.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e).map(m=>({node_id:m.node_id,parent_node_id:m.parent,conversations:n.prepare("SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(m.node_id).map(({session_id:l})=>{const{header:S,entries:f}=q().read(l);if(i==="entries")return{conversation_id:l,header:S,entries:f};const G=se.inMemory(S.cwd,void 0,[S,...f]),X=he(G)??[],k=new Map(f.map((p,R)=>[p.id,R])),z=f.filter(p=>p.type==="custom"&&p.customType==="crtr-system-prompt").map(p=>({id:p.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in p?p.data:void 0,timestamp:p.timestamp}})),V=m.node_id===e?f.find(p=>{if(p.type!=="message"||p.message.role!=="user")return!1;const R=P(f,p.message.timestamp);return R?.type==="runtime"&&R.kind==="kickoff"})?.id:void 0,Q=[...X,...z].sort((p,R)=>(k.get(p.id)??Number.MAX_SAFE_INTEGER)-(k.get(R.id)??Number.MAX_SAFE_INTEGER)).map(({id:p,message:R})=>{const a=R,N=a.usage,A=a.role==="user"?P(f,Number(a.timestamp)):null,Z=A?.type==="human"||p===V,v=a.role==="toolResult"?"tool_result":a.role==="bashExecution"?"bash_execution":a.role==="compactionSummary"?"compaction_summary":a.role==="branchSummary"?"branch_summary":a.role==="custom"&&a.customType==="crtr-system-prompt"?"system":a.role==="user"?Z?"user":"custom":a.role,K=v==="custom"?a.role==="custom"?a.customType:A?.type==="runtime"?A.kind:"unknown":void 0,ee=v==="system"&&a.customType==="crtr-system-prompt"?[{type:"text",text:a.data?.text??""}]:typeof a.content=="string"?[{type:"text",text:a.content}]:Array.isArray(a.content)?a.content.map(g=>g.type==="toolCall"?{type:"tool_call",tool_call_id:g.id,name:g.name,arguments:g.arguments}:g.type==="image"?{type:"image",mime_type:g.mimeType}:g.type==="thinking"?{type:"thinking",text:g.thinking}:g):[];return{entry_id:p,role:v,...v==="custom"?{custom_type:K}:{},time:typeof a.timestamp=="string"?a.timestamp:new Date(Number(a.timestamp??Date.now())).toISOString(),content:ee,...v==="assistant"?{model:a.model,provider:a.provider,stop_reason:a.stopReason,...a.errorMessage?{error_message:a.errorMessage}:{},...N?{usage:{input_tokens:N.input??0,output_tokens:N.output??0,cache_read_tokens:N.cacheRead??0,cache_write_tokens:N.cacheWrite??0,cost_usd:N.cost?.total??0}}:{}}:{},...v==="tool_result"?{tool_call_id:a.toolCallId,tool_name:a.toolName,is_error:a.isError}:{}}})??[];return{conversation_id:l,messages:Q}})})),s=n.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,o=new Map(c.map(m=>[m.node_id,ve(m.node_id)])),_=n.prepare(`SELECT node_id, sequence_number FROM run_events
8
+ ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({activity:r,node_id:o})=>!s||r<s.activity||r===s.activity&&o<s.id).map(r=>({root:h(r.node_id),activity:r.activity})).filter(({root:r})=>!t.status||D(r)===t.status),d=c.slice(0,t.limit),i=d.at(-1);return{runs:d.map(({root:r})=>M(r)),next:c.length>t.limit&&i?Buffer.from(JSON.stringify({activity:i.activity,id:i.root.node_id})).toString("base64url"):null}}p(It,"listRuns");async function kt(e,t,s){const n=L(e,t),c=p(()=>M(L(e,t)),"read");return!s||F.includes(D(n))?c():new Promise((d,i)=>{const r=p(()=>{clearTimeout(f),clearInterval(u),o();try{d(c())}catch(a){i(a)}},"finish"),o=xe(e,()=>{try{F.includes(String(c().status))&&r()}catch(a){clearTimeout(f),clearInterval(u),o(),i(a)}}),u=setInterval(()=>{F.includes(String(c().status))&&r()},250),f=setTimeout(r,s*1e3)})}p(kt,"waitRun");async function Ft(e,t,s=Z){if(e.status==="canceled"||e.outcome_reason==="closed")throw new y(409,"run_settled","canceled run cannot receive a message");const n=e.grantee??"app:terminal",c=await s(e.node_id,n,t),d=c.text;let i;try{if(e.final_report&&!e.pi_pid){const{commitReopenResident:o}=await import("../runtime/reopen.js");o(e.node_id)}i=Ne(e.node_id,{kind:"message",label:d.slice(0,120),senderNodeId:"human",bodyJson:{body:d},urgency:"normal",wake:1,withinEnqueue:p((o,u)=>{c.uses.length&&(Q(n,c.uses,o),V(c.uses.map(({upload_id:f,path:a})=>({upload_id:f,path:a,run_id:e.node_id})),o)),Y(o,e.node_id,e.node_id,"node.message.accepted",{message_id:u})},"withinEnqueue")})}catch(o){throw c.cleanup(),o}const r=S().prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e.node_id).event_cursor-1;return e.pi_pid||await J(e.node_id,{resume:!0,capacity:"freeze"}),{run_id:e.node_id,message_id:i.messageId,sequence_number:r}}p(Ft,"messageRun");async function $e(e){const t=p(()=>new y(503,"server_error",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let s=0;s<2;s++){const n=h(e);if(!n)throw I();if(!j(n)){if(n.streaming)throw t();return}const c=q(e)?.executionId;try{await be(e);return}catch(d){if(!(d instanceof Te))throw d;const i=h(e);if(!i)throw I();if(!i.streaming)return;if(s===0&&j(i)&&q(e)?.executionId!==c)continue;throw t()}}throw t()}p($e,"interruptNode");async function xt(e,t="stop"){const s=t==="stop"?S().prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:n})=>n):[e.node_id];return await Promise.all(s.map(n=>$e(n))),M(h(e.node_id)??e)}p(xt,"interruptRun");async function Ht(e,t={}){const s=S().prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(i=>i.node_id),n=[];if(D(e)!=="settled")n.push(...G(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const i of s){if(i===e.node_id)continue;const r=h(i);r&&r.status!=="done"&&r.status!=="canceled"&&r.status!=="dead"&&n.push(...G(i,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await X({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(i=>P(i,"run_canceled")))).some(i=>!i.confirmed))throw new y(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=h(e.node_id);return M(d??e)}p(Ht,"cancelRun");const K=200;function Wt(e,t){if(typeof t!="string"||!t.trim())throw b("name is required","name");const s=t.trim();if(s.length>K)throw b(`name exceeds ${K} characters`,"name");const n=fe(e.node_id,{name:s});return n.window&&ge(n.window,Ee(n)),M(n)}p(Wt,"renameRun");async function qt(e,t={config:Be,client:Ue}){await X({run_id:e.node_id},"the run was deleted");const s=H(o=>(o.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),o.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(u=>u.node_id)));if((await Promise.all(s.map(o=>P(o,"run_deleted",{deleting:!0})))).some(o=>!o.confirmed))throw new y(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const c=s.map(o=>{const u=le(o);if(u.app===null)throw new Error(`run node missing during deletion: ${o}`);return u}),d=S().prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:o}of d)try{B().delete(o)}catch(u){if(!Se(u))throw u}const i=H(o=>{const u=je([e.node_id],o);o.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),o.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const f=o.prepare("SELECT message_id FROM messages WHERE sender_node_id IN (SELECT node_id FROM nodes WHERE run_id = ?) UNION SELECT message_id FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id,e.node_id);o.prepare("DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").run(e.node_id);for(const{message_id:a}of f)o.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(a,a);for(const a of s)o.prepare("DELETE FROM nodes WHERE node_id = ?").run(a);return u});for(const o of c)_e(o);const{notifyRunDeleted:r}=await import("./events.js");return r(e.node_id),{uploads_pending:await Ge(i,t)}}p(qt,"deleteRun");async function Ge(e,t){if(!e.length||!t.config())return e.length;let s;try{s=t.client()}catch{return e.length}const n=new Set,c=e.map(i=>s.deleteUpload(i).then(()=>{Pe(i),n.add(i)},()=>{}));let d;return await Promise.race([Promise.all(c),new Promise(i=>{d=setTimeout(i,t.budgetMs??Je),d.unref?.()})]),clearTimeout(d),e.length-n.size}p(Ge,"deleteReleasedUploads");function Ut(e,t,s){L(e,t),W(e);const n=S();n.exec("BEGIN");try{const d=n.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e).map(l=>({node_id:l.node_id,parent_node_id:l.parent,conversations:n.prepare("SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(l.node_id).map(({session_id:g})=>{const{header:v,entries:w}=B().read(g);if(s==="entries")return{conversation_id:g,header:v,entries:w};const ee=me.inMemory(v.cwd,void 0,[v,...w]),te=Le(ee)??[],x=new Map(w.map((_,N)=>[_.id,N])),ne=w.filter(_=>_.type==="custom"&&_.customType==="crtr-system-prompt").map(_=>({id:_.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in _?_.data:void 0,timestamp:_.timestamp}})),re=l.node_id===e?w.find(_=>{if(_.type!=="message"||_.message.role!=="user")return!1;const N=$(w,_.message.timestamp);return N?.type==="runtime"&&N.kind==="kickoff"})?.id:void 0,se=[...te,...ne].sort((_,N)=>(x.get(_.id)??Number.MAX_SAFE_INTEGER)-(x.get(N.id)??Number.MAX_SAFE_INTEGER)).map(({id:_,message:N})=>{const m=N,O=m.usage,C=m.role==="user"?$(w,Number(m.timestamp)):null,oe=C?.type==="human"||_===re,T=m.role==="toolResult"?"tool_result":m.role==="bashExecution"?"bash_execution":m.role==="compactionSummary"?"compaction_summary":m.role==="branchSummary"?"branch_summary":m.role==="custom"&&m.customType==="crtr-system-prompt"?"system":m.role==="user"?oe?"user":"custom":m.role,ie=T==="custom"?m.role==="custom"?m.customType:C?.type==="runtime"?C.kind:"unknown":void 0,de=T==="system"&&m.customType==="crtr-system-prompt"?[{type:"text",text:m.data?.text??""}]:typeof m.content=="string"?[{type:"text",text:m.content}]:Array.isArray(m.content)?m.content.map(R=>R.type==="toolCall"?{type:"tool_call",tool_call_id:R.id,name:R.name,arguments:R.arguments}:R.type==="image"?{type:"image",mime_type:R.mimeType}:R.type==="thinking"?{type:"thinking",text:R.thinking}:R):[];return{entry_id:_,role:T,...T==="custom"?{custom_type:ie}:{},time:typeof m.timestamp=="string"?m.timestamp:new Date(Number(m.timestamp??Date.now())).toISOString(),content:de,...T==="assistant"?{model:m.model,provider:m.provider,stop_reason:m.stopReason,...m.errorMessage?{error_message:m.errorMessage}:{},...O?{usage:{input_tokens:O.input??0,output_tokens:O.output??0,cache_read_tokens:O.cacheRead??0,cache_write_tokens:O.cacheWrite??0,cost_usd:O.cost?.total??0}}:{}}:{},...T==="tool_result"?{tool_call_id:m.toolCallId,tool_name:m.toolName,is_error:m.isError}:{}}})??[];return{conversation_id:g,messages:se}})})),r=n.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,o=new Map(d.map(l=>[l.node_id,ke(l.node_id)])),u=n.prepare(`SELECT node_id, sequence_number FROM run_events
9
9
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
10
- ORDER BY sequence_number`).all(e,s);for(const m of _){const l=o.get(m.node_id);l!=null&&m.sequence_number>=l&&o.set(m.node_id,null)}const T=n.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
10
+ ORDER BY sequence_number`).all(e,r);for(const l of u){const g=o.get(l.node_id);g!=null&&l.sequence_number>=g&&o.set(l.node_id,null)}const f=n.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
11
11
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
12
- ORDER BY sequence_number`).all(e,s),h=new Map;for(const m of T){const l=o.get(m.node_id);if(l==null||m.sequence_number<l)continue;const S=JSON.parse(m.body_json),f=h.get(m.node_id)??{thinking:"",text:""};m.type==="node.thinking.delta"?f.thinking+=S.delta:f.text+=S.delta,h.set(m.node_id,f)}const Y=c.map(m=>({...m,in_progress_message:o.get(m.node_id)==null?null:h.get(m.node_id)??{thinking:"",text:""}}));return n.exec("COMMIT"),{run_id:e,latest_sequence:s,nodes:Y}}catch(d){throw n.exec("ROLLBACK"),d}}u(Et,"traceRun");function gt(e,t,i){if(t===void 0){if(!e.some(n=>b(n,"crtr:llm")))throw new E(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw D("scopes must be a list of scope strings","scopes");for(const n of t){try{Oe(n)}catch{throw D(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===i.slice(4))throw D(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===i.slice(4))&&!e.some(c=>b(c,n)))throw new E(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new E(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}u(gt,"requestedScopes");export{E as RunError,lt as cancelRun,ft as deleteRun,_t as interruptRun,ut as listRuns,pt as messageRun,L as ownedRun,gt as requestedScopes,at as rewriteLocalIdempotencyGrantee,M as runObject,ct as startRun,Et as traceRun,mt as waitRun};
12
+ ORDER BY sequence_number`).all(e,r),a=new Map;for(const l of f){const g=o.get(l.node_id);if(g==null||l.sequence_number<g)continue;const v=JSON.parse(l.body_json),w=a.get(l.node_id)??{thinking:"",text:""};l.type==="node.thinking.delta"?w.thinking+=v.delta:w.text+=v.delta,a.set(l.node_id,w)}const E=d.map(l=>({...l,in_progress_message:o.get(l.node_id)==null?null:a.get(l.node_id)??{thinking:"",text:""}}));return n.exec("COMMIT"),{run_id:e,latest_sequence:r,nodes:E}}catch(c){throw n.exec("ROLLBACK"),c}}p(Ut,"traceRun");function Bt(e,t,s){if(t===void 0){if(!e.some(n=>A(n,"crtr:llm")))throw new y(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw b("scopes must be a list of scope strings","scopes");for(const n of t){try{Fe(n)}catch{throw b(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))throw b(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))&&!e.some(d=>A(d,n)))throw new y(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new y(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}p(Bt,"requestedScopes");export{Je as RUN_DELETE_STORAGE_BUDGET_MS,K as RUN_NAME_MAX,y as RunError,Ht as cancelRun,qt as deleteRun,xt as interruptRun,It as listRuns,Ft as messageRun,L as ownedRun,Wt as renameRun,Bt as requestedScopes,Lt as rewriteLocalIdempotencyGrantee,M as runObject,Ct as startRun,Ut as traceRun,kt as waitRun};
@@ -0,0 +1,54 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import { type HumanRequestRecord } from '../human/requests.js';
3
+ /**
4
+ * A question (daemon-operations §question.*) is a human page request that takes
5
+ * a response and whose asking node belongs to a run; `question_id` is the
6
+ * request id. The page mechanism is unchanged: this module only reads the
7
+ * request row and its asking node to carry the page on the run.
8
+ */
9
+ interface AskingNode {
10
+ node_id: string;
11
+ run_id: string;
12
+ grantee: string;
13
+ }
14
+ /** The question's run, asking node, and app, or null when the request is not a question. */
15
+ export declare function questionRun(request: HumanRequestRecord, db?: DatabaseSync): AskingNode | null;
16
+ /** Called inside the page request's creating write: carries a new question on its run's stream. */
17
+ export declare function appendWaitingOnUser(db: DatabaseSync, request: HumanRequestRecord): void;
18
+ /** Called inside the settling write: an answered question emits `question.answered`. */
19
+ export declare function appendQuestionAnswered(db: DatabaseSync, request: HumanRequestRecord): void;
20
+ /** Open questions raised by any node of the run, oldest first. */
21
+ export declare function openQuestionIds(runId: string, db?: DatabaseSync): string[];
22
+ export type QuestionStatus = 'open' | 'answered' | 'canceled';
23
+ export declare function questionStatus(request: HumanRequestRecord): QuestionStatus;
24
+ /** The stored answer or cancellation of a settled question. */
25
+ export declare function questionResult(request: HumanRequestRecord): unknown;
26
+ /** The `question.get` shape. */
27
+ export declare function questionObject(request: HumanRequestRecord, run: AskingNode): Record<string, unknown>;
28
+ /** A question by id, with its run, or null when the id names no question. */
29
+ export declare function getQuestion(questionId: string): {
30
+ request: HumanRequestRecord;
31
+ run: AskingNode;
32
+ } | null;
33
+ /** Open question ids scoped to a run, one asking node, or every run of an app. */
34
+ export declare function openQuestionIdsFor(target: {
35
+ run_id: string;
36
+ } | {
37
+ node_id: string;
38
+ } | {
39
+ grantee: string;
40
+ }): string[];
41
+ /**
42
+ * Cancel the open questions of a run, of one asking node, or of every run of an
43
+ * app, through the page mechanism's own cancel (`settleHumanRequest`, first
44
+ * writer wins): each becomes `canceled` and can never be answered afterwards.
45
+ * Answers how many this call canceled.
46
+ */
47
+ export declare function cancelOpenQuestions(target: {
48
+ run_id: string;
49
+ } | {
50
+ node_id: string;
51
+ } | {
52
+ grantee: string;
53
+ }, reason: string): Promise<number>;
54
+ export {};
@@ -0,0 +1,4 @@
1
+ var p=Object.defineProperty;var i=(n,e)=>p(n,"name",{value:e,configurable:!0});import{openDb as o}from"../canvas/db.js";import{getRequest as c}from"../human/requests.js";import{appendRunEvent as d}from"./events.js";function _(n,e){return e===null?null:n.prepare("SELECT node_id, run_id, grantee FROM nodes WHERE node_id = ? AND run_id IS NOT NULL").get(e)??null}i(_,"askingNode");function f(n){return JSON.parse(n.specification_json)}i(f,"manifestOf");function s(n,e=o()){return n.kind!=="page"||!n.settleable?null:_(e,n.requester_node_id)}i(s,"questionRun");function a(n,e){const t=f(n);return{question_id:n.request_id,initiating_app:e.grantee,title:n.title,...n.subtitle?{subtitle:n.subtitle}:{},steps:t.steps,slots:t.slots.map(r=>({...r.id===void 0?{}:{id:r.id},kind:r.kind,step:r.step,config:r.config}))}}i(a,"questionFields");function x(n,e){const t=s(e,n);t===null||e.state!=="open"||d(n,t.run_id,t.node_id,"waiting_on_user",a(e,t))}i(x,"appendWaitingOnUser");function D(n,e){if(e.outcome!=="answered"||e.result_json===null)return;const t=s(e,n);if(t===null)return;const r=JSON.parse(e.result_json);d(n,t.run_id,t.node_id,"question.answered",{question_id:e.request_id,answer:r.responses??{}})}i(D,"appendQuestionAnswered");function A(n,e=o()){return e.prepare(`SELECT h.request_id FROM human_requests h JOIN nodes n ON n.node_id = h.requester_node_id
2
+ WHERE n.run_id = ? AND h.kind = 'page' AND h.state = 'open' AND h.settleable = 1
3
+ ORDER BY h.created_at, h.request_id`).all(n).map(t=>t.request_id)}i(A,"openQuestionIds");function N(n){return n.state!=="settled"?"open":n.outcome==="answered"?"answered":"canceled"}i(N,"questionStatus");function m(n){if(n.result_json===null)return null;const e=JSON.parse(n.result_json);return n.outcome==="answered"?e.responses??{}:e}i(m,"questionResult");function S(n,e){const t=N(n);return{...a(n,e),run_id:e.run_id,node_id:e.node_id,status:t,...t==="answered"?{answer:m(n)}:{}}}i(S,"questionObject");function k(n){const e=c(n);if(e===null)return null;const t=s(e);return t===null?null:{request:e,run:t}}i(k,"getQuestion");function h(n){const[e,t]="run_id"in n?["n.run_id = ?",n.run_id]:"node_id"in n?["n.node_id = ?",n.node_id]:["n.grantee = ?",n.grantee];return o().prepare(`SELECT h.request_id FROM human_requests h JOIN nodes n ON n.node_id = h.requester_node_id
4
+ WHERE ${e} AND n.run_id IS NOT NULL AND h.kind = 'page' AND h.state = 'open' AND h.settleable = 1`).all(t).map(r=>r.request_id)}i(h,"openQuestionIdsFor");async function L(n,e){const t=h(n);if(!t.length)return 0;const{cancelHumanTicket:r}=await import("../../daemon/human/finish.js");let u=0;for(const l of t)(await r(l,{reason:e,actor:"crtrd"})).outcome==="settled"&&(u+=1);return u}i(L,"cancelOpenQuestions");export{D as appendQuestionAnswered,x as appendWaitingOnUser,L as cancelOpenQuestions,k as getQuestion,A as openQuestionIds,h as openQuestionIdsFor,S as questionObject,m as questionResult,s as questionRun,N as questionStatus};
@@ -0,0 +1,33 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import { type StorageClient, type StorageConfig } from './client.js';
3
+ /** The fetch step of one `run.start` or `run.message` is bounded to 110 s in
4
+ * total (the hosting router waits 120 s for its headers). */
5
+ export declare const ATTACHMENT_FETCH_BUDGET_MS = 110000;
6
+ /** One fetched upload; `url` is the storage URL the text named (for refusals). */
7
+ export interface AttachmentUse {
8
+ upload_id: string;
9
+ path: string;
10
+ url: string;
11
+ }
12
+ export interface ResolvedAttachments {
13
+ /** The text with each storage URL replaced by its runtime path. */
14
+ text: string;
15
+ uses: AttachmentUse[];
16
+ /** Remove every file (and directory) this call created. Idempotent. */
17
+ cleanup: () => void;
18
+ }
19
+ export interface ResolveOptions {
20
+ config?: () => StorageConfig | null;
21
+ client?: () => StorageClient;
22
+ budgetMs?: number;
23
+ }
24
+ /** Re-check, inside the accepting write, that every used upload is still this
25
+ * grantee's and not pending delete (the due-work tick or an app removal may
26
+ * have released it while its bytes were fetched). */
27
+ export declare function assertUploadsUsable(grantee: string, uses: readonly AttachmentUse[], db: DatabaseSync): void;
28
+ /** Fetch every upload a storage URL in `text` names into
29
+ * `appSpace(grantee).nodes/<rootId>/attachments/` and replace exactly each
30
+ * URL's span with the file's absolute runtime path. Without configured
31
+ * storage the text passes through unchanged. On any failure every file this
32
+ * call wrote is removed before the error propagates. */
33
+ export declare function resolveStorageUrls(grantee: string, rootId: string, text: string, options?: ResolveOptions): Promise<ResolvedAttachments>;
@@ -0,0 +1 @@
1
+ var N=Object.defineProperty;var i=(e,n)=>N(e,"name",{value:n,configurable:!0});import{constants as Z,createWriteStream as j}from"node:fs";import{extname as q,join as E}from"node:path";import{Transform as G}from"node:stream";import{pipeline as X}from"node:stream/promises";import{appSpace as Y}from"../layout.js";import{RunError as v}from"../runs/operations.js";import{createFileBeneath as J,existsBeneath as z,openBeneath as K,removeTreeBeneath as O,setModeBeneath as P,unlinkBeneath as Q,withDirBeneath as V}from"../spaces/open-beneath.js";import{ensureAppSpace as ee}from"../spaces/space.js";import{storageClient as te,storageConfig as oe,StorageRefused as ne}from"./client.js";import{getUpload as k}from"./tables.js";const re=11e4,p=i((e,n)=>new v(400,"invalid_request",n,void 0,{url:e}),"refused"),R=i(e=>new v(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable");function x(e,n){return/^[^\s<>"'`)\]]*/.exec(e.slice(n))[0].replace(/[.,;:!?]+$/,"")}i(x,"shownUrl");function ae(e,n,r,c,d){const l=`${n}/`,_=[];let h=0;for(let u=e.indexOf(l,h);u!==-1;u=e.indexOf(l,h)){const t=x(e,u),f=/^([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)\//.exec(e.slice(u+l.length));if(!f)throw p(t,`storage URL ${t} does not name an upload`);if(f[1]!==r)throw p(t,`storage URL ${t} names another runtime`);const s=k(f[2],d);if(!s||s.grantee!==c)throw p(t,`storage URL ${t} names an unknown upload`);if(s.delete_pending_since)throw p(t,`storage URL ${t} names a deleted upload`);const $=u+l.length+f[0].length,m=encodeURIComponent(s.name);if(!e.startsWith(m,$))throw p(t,`storage URL ${t} does not match the upload's name`);_.push({start:u,end:$+m.length,upload:s}),h=$+m.length}return _}i(ae,"matchStorageUrls");function _e(e,n,r){for(const c of n){const d=k(c.upload_id,r);if(!d||d.grantee!==e||d.delete_pending_since)throw p(c.url,`storage URL ${c.url} names an upload deleted while it was fetched`)}}i(_e,"assertUploadsUsable");function se(e,n){if(n===1)return e;const r=q(e);return r&&r!==e?`${e.slice(0,-r.length)}-${n}${r}`:`${e}-${n}`}i(se,"candidate");async function $e(e,n,r,c={}){const d={text:r,uses:[],cleanup:i(()=>{},"cleanup")},l=(c.config??oe)();if(!l||!r.includes(`${l.base_url}/`))return d;const _=(c.client??te)(),h=ae(r,l.base_url,_.runtimeId,e);if(!h.length)return d;const u=await ee(e),t=Y(e).nodes,f=E(t,n),s=E(f,"attachments"),$={uid:process.getuid?.()??0,gid:u.gid},m=!z(t,f),I=!m&&!z(t,s),C=[];let D=!1;const M=i(()=>{if(!D){D=!0;for(const o of C)try{Q(t,o)}catch{}try{m?O(t,f):I&&O(t,s)}catch{}}},"cleanup"),U=AbortSignal.timeout(c.budgetMs??re),b=new Map;try{V(t,s,()=>{},!0);for(const{upload:o,start:B}of h){if(b.has(o.upload_id))continue;const g=x(r,B);let L;try{L=await _.fetchUpload(o.upload_id,U)}catch(a){throw a instanceof ne?p(g,a.status===409?`storage URL ${g} names an upload that was never finished`:`storage URL ${g} names an unknown upload`):U.aborted?R("attachments could not be fetched within 110 s"):a}let w="";for(let a=1;;a++){w=E(s,se(o.name,a));try{J(t,w,Buffer.alloc(0),432);break}catch(A){if(A.code!=="EEXIST")throw L.body.destroy(),A}}C.push(w);let T=0;const W=new G({transform(a,A,H){T+=a.length,H(null,a)}}),F=K(t,w,Z.O_WRONLY);try{await X(L.body,W,j("",{fd:F,autoClose:!0}),{signal:U})}catch(a){throw U.aborted?R("attachments could not be fetched within 110 s"):a instanceof v?a:R(`storage stopped sending ${o.name}: ${a instanceof Error?a.message:String(a)}`)}if(T!==o.size)throw R(`storage sent ${T} of ${o.size} bytes of ${o.name}`);P(t,w,432,$),b.set(o.upload_id,{path:w,url:g})}}catch(o){throw M(),o}let y="",S=0;for(const o of h)y+=r.slice(S,o.start)+b.get(o.upload.upload_id).path,S=o.end;return y+=r.slice(S),{text:y,uses:[...b].map(([o,{path:B,url:g}])=>({upload_id:o,path:B,url:g})),cleanup:M}}i($e,"resolveStorageUrls");export{re as ATTACHMENT_FETCH_BUDGET_MS,_e as assertUploadsUsable,$e as resolveStorageUrls};
@@ -0,0 +1,67 @@
1
+ import { Readable } from 'node:stream';
2
+ import { type DirectoryToken } from '../grants/sync.js';
3
+ /** The size limit of one uploaded or shared file: 100 MiB. */
4
+ export declare const UPLOAD_MAX_BYTES = 104857600;
5
+ /** Storage answered 404 (unknown, or another runtime's object) or 409 (not uploaded). */
6
+ export declare class StorageRefused extends Error {
7
+ readonly status: 404 | 409;
8
+ readonly code: string;
9
+ constructor(status: 404 | 409, code: string, message: string);
10
+ }
11
+ export interface StorageConfig {
12
+ service_url: string;
13
+ base_url: string;
14
+ }
15
+ export interface CreatedUpload {
16
+ upload_id: string;
17
+ url: string;
18
+ upload_link: string;
19
+ expires_at: string;
20
+ }
21
+ export interface CreatedShare {
22
+ share_id: string;
23
+ url: string;
24
+ upload_link: string;
25
+ expires_at: string | null;
26
+ }
27
+ export interface SignedLink {
28
+ url: string;
29
+ expires_at: string;
30
+ }
31
+ export interface StorageClient {
32
+ readonly config: StorageConfig;
33
+ /** This runtime's id, the second segment of every storage URL it owns. */
34
+ readonly runtimeId: string;
35
+ createUpload(input: {
36
+ name: string;
37
+ media_type: string;
38
+ size: number;
39
+ }): Promise<CreatedUpload>;
40
+ /** The upload's bytes; `size` is storage's `Content-Length`. */
41
+ fetchUpload(uploadId: string, signal?: AbortSignal): Promise<{
42
+ body: Readable;
43
+ size: number | null;
44
+ media_type: string | null;
45
+ }>;
46
+ signDownload(uploadId: string): Promise<SignedLink>;
47
+ deleteUpload(uploadId: string): Promise<void>;
48
+ createShare(input: {
49
+ name: string;
50
+ media_type: string;
51
+ size: number;
52
+ expires_at?: string;
53
+ }): Promise<CreatedShare>;
54
+ putShareBytes(uploadLink: string, file: string, size: number, mediaType: string): Promise<void>;
55
+ deleteShare(shareId: string): Promise<void>;
56
+ }
57
+ /** The configured storage, or null when this runtime has none. */
58
+ export declare function storageConfig(): StorageConfig | null;
59
+ /** The storage client for the configured runtime. Refuses with
60
+ * `storage_unavailable` when no storage is configured. */
61
+ export declare function storageClient(): StorageClient;
62
+ /** Test seam: reset the cached client (and its token). */
63
+ export declare function resetStorageClient(): void;
64
+ export declare function createStorageClient(config: StorageConfig, mint: () => Promise<DirectoryToken>, runtime: string): StorageClient;
65
+ /** Storage's name rule (plan Overview): 1–255 bytes UTF-8, no `/`, `\`, NUL or
66
+ * control characters, not `.` or `..`. Returns a reason, or null when valid. */
67
+ export declare function invalidStorageName(name: string): string | null;
@@ -0,0 +1,3 @@
1
+ var v=Object.defineProperty;var s=(t,u)=>v(t,"name",{value:u,configurable:!0});import{createReadStream as x,statSync as k}from"node:fs";import{Readable as _}from"node:stream";import{readConfig as b}from"../config.js";import{RunError as m}from"../runs/operations.js";import{mintDirectoryToken as E,runtimeId as T}from"../grants/sync.js";const j=104857600;class w extends Error{static{s(this,"StorageRefused")}status;code;constructor(u,d,c){super(c),this.status=u,this.code=d}}const i=s(t=>new m(503,"storage_unavailable",t,void 0,void 0,void 0,!0),"unavailable");function C(){const t=b("user").runtime?.storage;return!t?.service_url||!t.base_url?null:{service_url:t.service_url.replace(/\/$/,""),base_url:t.base_url.replace(/\/$/,"")}}s(C,"storageConfig");let h;function B(){const t=C(),u=b("user").runtime?.issuer;if(!t||!u)throw i("file storage is not configured on this runtime");const d=`${u}
2
+ ${t.service_url}
3
+ ${t.base_url}`;return h?.key!==d&&(h={key:d,client:A(t,()=>E(u,t.service_url),T())}),h.client}s(B,"storageClient");function z(){h=void 0}s(z,"resetStorageClient");function A(t,u,d){let c,g;const S=s(async()=>{if(c&&c.expires_at-6e4>Date.now())return c.access_token;g??=u().finally(()=>{g=void 0});try{c=await g}catch(r){throw i(`storage token could not be minted: ${r instanceof Error?r.message:String(r)}`)}return c.access_token},"bearer"),l=s(async(r,e,n={})=>{const f=[AbortSignal.timeout(n.timeoutMs??1e4),...n.signal?[n.signal]:[]];let o;try{o=await fetch(`${t.service_url}${e}`,{method:r,signal:AbortSignal.any(f),headers:{Authorization:`Bearer ${await S()}`,...n.body===void 0?{}:{"Content-Type":"application/json"}},...n.body===void 0?{}:{body:JSON.stringify(n.body)}})}catch(a){throw a instanceof m?a:i(`storage could not be reached: ${a instanceof Error?a.message:String(a)}`)}if(o.status===401&&(c=void 0),o.status===404||o.status===409){const a=await o.json().catch(()=>({})),$=a.error?.code??a.code??(o.status===404?"not_found":"not_uploaded");throw new w(o.status,$,a.error?.message??a.message??`storage answered ${o.status}`)}if(!o.ok)throw await o.body?.cancel().catch(()=>{}),i(`storage answered ${o.status} to ${r} ${e.split("?")[0]}`);return o},"call"),y=s(async r=>{try{return await r.json()}catch{throw i("storage answered with an invalid body")}},"json"),p=s(r=>encodeURIComponent(r),"id");return{config:t,runtimeId:d,async createUpload(r){const e=await y(await l("POST","/v1/uploads",{body:r}));if(typeof e.upload_id!="string"||typeof e.url!="string"||typeof e.upload_link!="string"||typeof e.expires_at!="string")throw i("storage answered with an invalid upload");return{upload_id:e.upload_id,url:e.url,upload_link:e.upload_link,expires_at:e.expires_at}},async fetchUpload(r,e){const n=await l("GET",`/v1/uploads/${p(r)}/content`,{...e?{signal:e}:{},timeoutMs:11e4});if(!n.body)throw i("storage answered with no body");const f=n.headers.get("content-length");return{body:_.fromWeb(n.body),size:f===null?null:Number(f),media_type:n.headers.get("content-type")}},async signDownload(r){const e=await y(await l("POST",`/v1/uploads/${p(r)}/download-link`));if(typeof e.url!="string"||typeof e.expires_at!="string")throw i("storage answered with an invalid link");return{url:e.url,expires_at:e.expires_at}},async deleteUpload(r){try{await l("DELETE",`/v1/uploads/${p(r)}`)}catch(e){if(!(e instanceof w&&e.status===404))throw e}},async createShare(r){const e=await y(await l("POST","/v1/shares",{body:r}));if(typeof e.share_id!="string"||typeof e.url!="string"||typeof e.upload_link!="string")throw i("storage answered with an invalid share");return{share_id:e.share_id,url:e.url,upload_link:e.upload_link,expires_at:e.expires_at??null}},async putShareBytes(r,e,n,f){if(k(e).size!==n)throw new Error("shared file changed size while it was being copied");let o;try{o=await fetch(r,{method:"PUT",signal:AbortSignal.timeout(11e4),headers:{"Content-Type":f,"Content-Length":String(n)},body:_.toWeb(x(e)),duplex:"half"})}catch(a){throw i(`storage could not be reached: ${a instanceof Error?a.message:String(a)}`)}if(await o.body?.cancel().catch(()=>{}),!o.ok)throw i(`storage answered ${o.status} to the share upload`)},async deleteShare(r){try{await l("DELETE",`/v1/shares/${p(r)}`)}catch(e){if(!(e instanceof w&&e.status===404))throw e}}}}s(A,"createStorageClient");function I(t){return!t||Buffer.byteLength(t,"utf8")>255?"name must be 1-255 bytes":t==="."||t===".."?"name must not be . or ..":/[/\\\u0000-\u001f\u007f]/.test(t)?"name must not contain /, \\, or control characters":null}s(I,"invalidStorageName");export{w as StorageRefused,j as UPLOAD_MAX_BYTES,A as createStorageClient,I as invalidStorageName,z as resetStorageClient,B as storageClient,C as storageConfig};
@@ -0,0 +1,23 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { type FileCaller } from '../spaces/permissions.js';
3
+ export declare function contentTypeFor(path: string): string;
4
+ /** An open regular file the caller may read. The caller closes `fd`. */
5
+ export interface CallerFile {
6
+ fd: number;
7
+ path: string;
8
+ size: number;
9
+ }
10
+ /** Open `raw` for `caller` beneath the root its permission names: absent or
11
+ * withheld → `not_found`; unpermitted → `scope_missing`; a symlink on the way →
12
+ * `invalid_request` `param: path`; not a regular file → `not_found`. */
13
+ export declare function openCallerFile(caller: FileCaller, raw: string | null | undefined): CallerFile;
14
+ /** A single `bytes=` range of a `size`-byte file: `null` = serve all; throws a
15
+ * 416 for a malformed or unsatisfiable range. Several ranges are served whole. */
16
+ export declare function parseRange(header: string | undefined, size: number): {
17
+ start: number;
18
+ end: number;
19
+ } | null;
20
+ /** `file.download`: the file's raw bytes. Errors before the head is sent throw
21
+ * (the listener answers the JSON envelope; a 416 carries `Content-Range`); an
22
+ * error once bytes flow destroys the socket so no JSON is ever appended. */
23
+ export declare function serveDownload(req: IncomingMessage, res: ServerResponse, caller: FileCaller, raw: string | null): Promise<void>;