@north-light/crouter 0.3.320 → 0.3.321

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 (62) hide show
  1. package/dist/api/client.d.ts +2 -1
  2. package/dist/api/client.js +1 -1
  3. package/dist/api/dto/broker-ops.d.ts +0 -1
  4. package/dist/api/dto/node-outcomes.d.ts +6 -0
  5. package/dist/api/dto/nodes.d.ts +4 -3
  6. package/dist/api/dto/review-comments.d.ts +8 -0
  7. package/dist/api/routes.d.ts +1 -0
  8. package/dist/api/routes.js +1 -1
  9. package/dist/clients/attach/viewer.js +582 -582
  10. package/dist/clients/inbox/review/comments-client.d.ts +8 -1
  11. package/dist/clients/inbox/review/comments-client.js +1 -1
  12. package/dist/clients/inbox/review/companion-pane.d.ts +17 -0
  13. package/dist/clients/inbox/review/companion-pane.js +1 -1
  14. package/dist/clients/inbox/review/document-surface.d.ts +10 -0
  15. package/dist/clients/inbox/review/document-surface.js +2 -2
  16. package/dist/clients/inbox/review/frame.js +1 -1
  17. package/dist/clients/inbox/review/keys.d.ts +2 -0
  18. package/dist/clients/inbox/review/keys.js +1 -1
  19. package/dist/commands/human/prompts.js +1 -1
  20. package/dist/core/canvas/browse/app.js +3 -3
  21. package/dist/core/canvas/canvas.d.ts +3 -3
  22. package/dist/core/canvas/canvas.js +17 -14
  23. package/dist/core/canvas/migrations.js +34 -27
  24. package/dist/core/canvas/node-sql-migration.d.ts +1 -0
  25. package/dist/core/canvas/node-sql-migration.js +28 -2
  26. package/dist/core/canvas/paths.d.ts +4 -0
  27. package/dist/core/canvas/paths.js +1 -1
  28. package/dist/core/canvas/recovery.d.ts +1 -0
  29. package/dist/core/canvas/recovery.js +1 -1
  30. package/dist/core/canvas/worktrees.d.ts +1 -0
  31. package/dist/core/canvas/worktrees.js +1 -1
  32. package/dist/core/human/requests.d.ts +1 -0
  33. package/dist/core/human/requests.js +17 -13
  34. package/dist/core/review/fork.d.ts +8 -0
  35. package/dist/core/review/fork.js +5 -0
  36. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  37. package/dist/core/runtime/broker/extension-abort.js +1 -1
  38. package/dist/core/runtime/broker.js +1 -1
  39. package/dist/core/runtime/spawn.d.ts +5 -1
  40. package/dist/core/runtime/spawn.js +2 -2
  41. package/dist/core/runtime/stop-guard.d.ts +1 -3
  42. package/dist/core/runtime/stop-guard.js +2 -2
  43. package/dist/core/runtime/stop-signals.d.ts +0 -1
  44. package/dist/core/runtime/stop-signals.js +1 -1
  45. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  46. package/dist/daemon/api/handlers/health.js +14 -1
  47. package/dist/daemon/api/handlers/inbox.js +1 -1
  48. package/dist/daemon/api/handlers/review-comments.js +1 -1
  49. package/dist/daemon/api/map.d.ts +4 -2
  50. package/dist/daemon/api/map.js +2 -2
  51. package/dist/daemon/companion-retire.d.ts +3 -1
  52. package/dist/daemon/companion-retire.js +1 -1
  53. package/dist/daemon/crtrd.js +7 -7
  54. package/dist/daemon/human/finish.d.ts +4 -1
  55. package/dist/daemon/human/finish.js +7 -7
  56. package/dist/daemon/human/settle.d.ts +8 -6
  57. package/dist/daemon/human/settle.js +1 -1
  58. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  59. package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
  60. package/dist/pi-extensions/canvas-stophook.js +1 -1
  61. package/package.json +1 -1
  62. package/runtime.lock.json +5 -5
@@ -1,7 +1,7 @@
1
- var c=Object.defineProperty;var n=(t,r)=>c(t,"name",{value:r,configurable:!0});import{hasActiveLiveSubscription as p,hasLiveMessageWait as f,hasPendingCronWake as d,getNode as m,contextDir as h}from"../canvas/index.js";import{activeBackgroundBashJobs as g}from"../bash-jobs.js";import{formatCard as o,formatStructuredOutputReprompt as v,STALL_REPROMPT as w}from"../../shared/generated-context.js";import{readOutputRequest as S}from"./structured-output.js";import{STALL_REPROMPT as A}from"../../shared/generated-context.js";function R(t){return o("stop-guard",{},v(JSON.stringify(t,null,2)))}n(R,"formatValidStructuredOutputReprompt");function y(t){return o("stop-guard",{},`Structured-output request file is invalid and cannot be used: ${t}
1
+ var c=Object.defineProperty;var n=(t,r)=>c(t,"name",{value:r,configurable:!0});import{hasActiveLiveSubscription as p,hasLiveMessageWait as f,hasPendingCronWake as m,getNode as d,contextDir as h}from"../canvas/index.js";import{activeBackgroundBashJobs as g}from"../bash-jobs.js";import{hasOpenReplyBearingRequestByRequester as v}from"../human/requests.js";import{formatCard as o,formatStructuredOutputReprompt as w,STALL_REPROMPT as R}from"../../shared/generated-context.js";import{readOutputRequest as S}from"./structured-output.js";import{STALL_REPROMPT as T}from"../../shared/generated-context.js";function y(t){return o("stop-guard",{},w(JSON.stringify(t,null,2)))}n(y,"formatValidStructuredOutputReprompt");function O(t){return o("stop-guard",{},`Structured-output request file is invalid and cannot be used: ${t}
2
2
 
3
3
  You have two options:
4
4
  1. Remove the invalid file (the output-schema.json in your node directory has been corrupted)
5
5
  2. Fix the corruption if you know the original request schema
6
6
 
7
- After resolving the file, retry with \`crtr push result\` (or \`crtr push result --decline "<reason>" --code <token>\` when the schema cannot be honestly satisfied). If this is unexpected, escalate to the user using \`crtr human send\`.`)}n(y,"formatInvalidStructuredOutputReprompt");function l(t,r){return d(t)?"scheduled":p(t)||f(t)||r?"awaiting":null}n(l,"wakeCapableWait");function W(t,r,i=g(h(t)).length>0){if(r.pushedFinal)return{action:"allow",reason:"finished"};if(r.requestedHumanReply)return{action:"allow",reason:"escalated"};const a=S(t);if(a.state==="valid"){const s=l(t,i);return s!==null?{action:"allow",reason:s}:{action:"reprompt",reason:"stalled",message:R(a.request.schema)}}if(a.state==="invalid")return{action:"reprompt",reason:"stalled",message:y(a.error)};const e=m(t);if(e!==null&&(e.final_report!=null||e.status==="done"||e.status==="dead"||e.status==="canceled"))return{action:"allow",reason:"finished"};if(e!==null&&e.lifecycle==="resident")return{action:"allow",reason:"dormant"};const u=l(t,i);return u!==null?{action:"allow",reason:u}:{action:"reprompt",reason:"stalled",message:o("stop-guard",{},w)}}n(W,"evaluateStop");export{A as STALL_REPROMPT,W as evaluateStop};
7
+ After resolving the file, retry with \`crtr push result\` (or \`crtr push result --decline "<reason>" --code <token>\` when the schema cannot be honestly satisfied). If this is unexpected, escalate to the user using \`crtr human send\`.`)}n(O,"formatInvalidStructuredOutputReprompt");function l(t,r){return m(t)?"scheduled":p(t)||f(t)||v(t)||r?"awaiting":null}n(l,"wakeCapableWait");function k(t,r,i=g(h(t)).length>0){if(r.pushedFinal)return{action:"allow",reason:"finished"};const a=S(t);if(a.state==="valid"){const u=l(t,i);return u!==null?{action:"allow",reason:u}:{action:"reprompt",reason:"stalled",message:y(a.request.schema)}}if(a.state==="invalid")return{action:"reprompt",reason:"stalled",message:O(a.error)};const e=d(t);if(e!==null&&(e.final_report!=null||e.status==="done"||e.status==="dead"||e.status==="canceled"))return{action:"allow",reason:"finished"};if(e!==null&&e.lifecycle==="resident")return{action:"allow",reason:"dormant"};const s=l(t,i);return s!==null?{action:"allow",reason:s}:{action:"reprompt",reason:"stalled",message:o("stop-guard",{},R)}}n(k,"evaluateStop");export{T as STALL_REPROMPT,k as evaluateStop};
@@ -1,6 +1,5 @@
1
1
  export interface StopSignals {
2
2
  pushedFinal: boolean;
3
- requestedHumanReply: boolean;
4
3
  }
5
4
  export type StopSignal = keyof StopSignals;
6
5
  /** Record a successful command outcome for this broker process. The stophook
@@ -1 +1 @@
1
- var p=Object.defineProperty;var e=(r,n)=>p(r,"name",{value:n,configurable:!0});import{existsSync as l,mkdirSync as S,readFileSync as m,rmSync as s,writeFileSync as g}from"node:fs";import{join as y}from"node:path";import{jobDir as c}from"../canvas/paths.js";const u=["pushedFinal","requestedHumanReply"];function o(r,n){return y(c(r),`.${n}`)}e(o,"signalPath");function f(){return process.env.CRTR_BROKER_PID??String(process.pid)}e(f,"brokerIdentity");function x(r,n){S(c(r),{recursive:!0}),g(o(r,n),f())}e(x,"markStopSignal");function F(r){const n={pushedFinal:!1,requestedHumanReply:!1};for(const i of u){const t=o(r,i);if(!l(t))continue;const a=m(t,"utf8").trim();s(t,{force:!0}),a===f()&&(n[i]=!0)}return n}e(F,"consumeStopSignals");function b(r){for(const n of u)s(o(r,n),{force:!0})}e(b,"clearStopSignals");export{b as clearStopSignals,F as consumeStopSignals,x as markStopSignal};
1
+ var p=Object.defineProperty;var t=(r,n)=>p(r,"name",{value:n,configurable:!0});import{existsSync as S,mkdirSync as l,readFileSync as m,rmSync as c,writeFileSync as g}from"node:fs";import{join as y}from"node:path";import{jobDir as s}from"../canvas/paths.js";const f=["pushedFinal"];function i(r,n){return y(s(r),`.${n}`)}t(i,"signalPath");function u(){return process.env.CRTR_BROKER_PID??String(process.pid)}t(u,"brokerIdentity");function F(r,n){l(s(r),{recursive:!0}),g(i(r,n),u())}t(F,"markStopSignal");function R(r){const n={pushedFinal:!1};for(const e of f){const o=i(r,e);if(!S(o))continue;const a=m(o,"utf8").trim();c(o,{force:!0}),a===u()&&(n[e]=!0)}return n}t(R,"consumeStopSignals");function b(r){for(const n of f)c(i(r,n),{force:!0})}t(b,"clearStopSignals");export{b as clearStopSignals,R as consumeStopSignals,F as markStopSignal};
@@ -1 +1 @@
1
- var A=Object.defineProperty;var o=(e,t)=>A(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as N,findNodeBySessionFile as P,getNode as k,isWarmSpare as R,listNodeIdentities as q,recordSettledTurn as T,setPresence as _,subscriptionsOf as $,updateNode as g}from"../../../core/canvas/canvas.js";import{recordExecutionPid as C}from"../../../core/canvas/executions.js";import{bindSession as j,readLiveSession as I,transferSession as E}from"../../../core/canvas/sessions.js";import{isSafeNodeId as H}from"../../../core/canvas/paths.js";import{isPidAlive as M}from"../../../core/canvas/pid.js";import{editorLabel as B}from"../../../core/canvas/labels.js";import{assembleNodeSubject as L}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as a}from"../../../core/errors.js";import{hasUnseenWakeMail as O}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as G}from"../../../core/runtime/kickoff.js";import{transition as y}from"../../../core/runtime/lifecycle.js";import{focusOf as b,tearDownNode as S}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as J}from"../../../core/runtime/broker/client-registry.js";import{evaluateStop as W}from"../../../core/runtime/stop-guard.js";import{clearFault as p,recordFault as D}from"../../../core/canvas/recovery.js";import{updateModelRecipe as U}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as V}from"../../review/finish.js";import{emitEvent as Y}from"../../../core/events/emit.js";import{consumePendingPark as z,recordPendingParkActivity as K}from"../../park-pending.js";import{shouldParkAfterSummary as Q}from"../../park-activity.js";import{requireCurrentExecution as m}from"./broker-recovery.js";function f(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw a(`${t} requires a JSON body`);return e}o(f,"objectBody");function X(e){const t=f(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw a("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw a("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw a("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw a("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw a("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw a("reviewBoundaryIds must be an array of strings");return t}o(X,"parseSessionBoundBody");function Z(e){const t=f(e,"broker settle");if(typeof t.stopReason!="string")throw a("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal","requestedHumanReply"])if(typeof t[n]!="boolean")throw a(`${n} must be a boolean`);return t}o(Z,"parseSettleBody");function ee(e){const t=f(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw a("outcome must be completed or failed");return t}o(ee,"parseParkCompleteBody");function te(e){const t=f(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw a("spec must be a non-empty string");if(t.pinnedOverride!==void 0&&typeof t.pinnedOverride!="boolean")throw a("pinnedOverride must be a boolean when present");if(typeof t.userSelected!="boolean")throw a("userSelected must be a boolean");return t}o(te,"parseModelCommitBody");function h(e){const t=k(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}o(h,"requireNode");function w(e){return{node_id:e.node_id,name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}o(w,"extensionNode");function ne(e){const t=h(e),n=[],r=new Set([e]);let i=t.parent??null;for(;i!==null&&i!==""&&!r.has(i);){r.add(i);const c=k(i);if(c===null)break;n.unshift(w(c)),i=c.parent??null}const s=$(e).map(c=>k(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,x)=>c.status===x.status?0:c.status==="active"?-1:x.status==="active"?1:0).map(w),u=typeof t.fork_source_file=="string"?P(t.fork_source_file):null,d=L(e);if(d===null)throw v(`unknown node: ${e}`,{received:e});return{node:w(t),warm_spare:R(e),ancestors:n,children:s,fork_source:u===null?null:w(u),subject:d,report_nodes:q()}}o(ne,"extensionState");function F(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}o(F,"samePersona");function ie(e){const t=f(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw a("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw a("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(r=>typeof n[r]!="string"))throw a("recap expected must contain name, description, title, icon, and kind strings");return t}o(ie,"parseGeneratedNameBody");function re(e){const t=f(e,"broker persona-ack"),n=o(r=>{const i=t[r];if(typeof i!="object"||i===null||Array.isArray(i)||typeof i.kind!="string"||i.mode!=="base"&&i.mode!=="orchestrator"||i.lifecycle!=="terminal"&&i.lifecycle!=="resident")throw a(`${r} must be a persona state`);return i},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}o(re,"parsePersonaAckBody");function oe(e){const t=e.params.id,n=X(e.body),r=n.sessionFile===null?null:N(n.sessionFile);return{status:200,body:l(()=>{const s=h(t);if(C(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const u=s.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))return{action:"shutdown"};if(n.reason==="new"&&s.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&s.fork_from!=null&&s.pi_session_id==null&&r===null)return{action:"shutdown"};const d=r===null?null:P(r);if(d!==null&&d.node_id!==t){if(M(d.pi_pid))return D(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${r}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const c=I(d.node_id);if(c===null||E({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})!=="transferred")return{action:"shutdown"}}else if(j(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(G(t),s.intent==="refresh"&&y(t,"revive")),{action:"none"}})}}o(oe,"handleSessionBound");function se(e,t){const n=k(e);if(n===null){if(t.pushedFinal)return{action:"shutdown"};if(t.requestedHumanReply)return{action:"stay_dormant"};throw v(`unknown node: ${e}`,{received:e})}if(T(e,new Date().toISOString()),t.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(y(e,"finish"),p(e),b(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(t.stopReason!=="stop"&&t.stopReason!=="length")return p(e,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const r={pushedFinal:t.pushedFinal,requestedHumanReply:t.requestedHumanReply};if(r.pushedFinal||n.status==="done")return p(e),b(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(r.requestedHumanReply)return p(e),{action:"stay_dormant"};if(n.intent==="refresh")return p(e),{action:"shutdown"};const i=W(e,r,t.backgroundJobsRunning);return p(e),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?O(e)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:b(e)!==null||J(e)||O(e)?{action:"stay_dormant"}:(y(e,"release"),{action:"shutdown"})}o(se,"settleBroker");function ae(e){const t=e.params.id,n=Z(e.body);m(t,n.expected_execution_id);const r=l(()=>se(t,n));return r.action!=="reprompt"&&V(t),{status:200,body:r}}o(ae,"handleSettle");function de(e){const t=e.params.id,n=ee(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=z(t);if(i===void 0)return{action:"stay_dormant"};const s=h(t);return Q(t,s,i)?(p(t),y(t,"park"),b(t)!==null&&S(t),_(t,{pane:null,tmux_session:null,window:null}),Y({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...H(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}o(de,"handleParkComplete");function ue(e){const t=e.params.id;return m(t,f(e.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:K(t)?"recorded":"none"}))}}o(ue,"handleParkActivity");function ce(e){const t=e.params.id,n=te(e.body);return m(t,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>U(h(t),n.spec,n.pinnedOverride,n.userSelected)).model_override}}}o(ce,"handleModelCommit");function le(e){return{status:200,body:ne(e.params.id)}}o(le,"handleExtensionState");function pe(e){const t=e.params.id,n=ie(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:B(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const s=n.expected;if(i.name!==s.name||(i.description??"")!==s.description||(i.title??"")!==s.title||(i.icon??"")!==s.icon||i.kind!==s.kind)return{applied:!1};const u=g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:B(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}o(pe,"handleGeneratedName");function fe(e){const t=e.params.id,n=re(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t),s={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},u=i.persona_ack,d=u===void 0?s:{kind:u.kind??i.kind,mode:u.mode,lifecycle:u.lifecycle};return!F(s,n.to)||!F(d,n.from)?{applied:!1}:(g(t,{persona_ack:n.to}),{applied:!0})})}}o(fe,"handlePersonaAck");const Ie=[{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:oe},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:ae},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:de},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:ue},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:ce},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:le},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:fe}];export{Ie as brokerOperationRoutes};
1
+ var A=Object.defineProperty;var r=(e,t)=>A(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as N,findNodeBySessionFile as P,getNode as k,isWarmSpare as R,listNodeIdentities as T,recordSettledTurn as $,setPresence as _,subscriptionsOf as C,updateNode as g}from"../../../core/canvas/canvas.js";import{recordExecutionPid as I}from"../../../core/canvas/executions.js";import{bindSession as j,readLiveSession as q,transferSession as E}from"../../../core/canvas/sessions.js";import{isSafeNodeId as M}from"../../../core/canvas/paths.js";import{isPidAlive as L}from"../../../core/canvas/pid.js";import{editorLabel as B}from"../../../core/canvas/labels.js";import{assembleNodeSubject as G}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as a}from"../../../core/errors.js";import{hasUnseenWakeMail as O}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as J}from"../../../core/runtime/kickoff.js";import{transition as b}from"../../../core/runtime/lifecycle.js";import{focusOf as w,tearDownNode as S}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../../../core/runtime/broker/client-registry.js";import{evaluateStop as D}from"../../../core/runtime/stop-guard.js";import{clearFault as f,recordFault as U}from"../../../core/canvas/recovery.js";import{updateModelRecipe as V}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as Y}from"../../review/finish.js";import{emitEvent as z}from"../../../core/events/emit.js";import{consumePendingPark as H,recordPendingParkActivity as K}from"../../park-pending.js";import{shouldParkAfterSummary as Q}from"../../park-activity.js";import{requireCurrentExecution as m}from"./broker-recovery.js";function p(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw a(`${t} requires a JSON body`);return e}r(p,"objectBody");function X(e){const t=p(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw a("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw a("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw a("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw a("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw a("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw a("reviewBoundaryIds must be an array of strings");return t}r(X,"parseSessionBoundBody");function Z(e){const t=p(e,"broker settle");if(typeof t.stopReason!="string")throw a("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof t[n]!="boolean")throw a(`${n} must be a boolean`);return t}r(Z,"parseSettleBody");function ee(e){const t=p(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw a("outcome must be completed or failed");return t}r(ee,"parseParkCompleteBody");function te(e){const t=p(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw a("spec must be a non-empty string");if(t.pinnedOverride!==void 0&&typeof t.pinnedOverride!="boolean")throw a("pinnedOverride must be a boolean when present");if(typeof t.userSelected!="boolean")throw a("userSelected must be a boolean");return t}r(te,"parseModelCommitBody");function h(e){const t=k(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}r(h,"requireNode");function y(e){return{node_id:e.node_id,name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}r(y,"extensionNode");function ne(e){const t=h(e),n=[],o=new Set([e]);let i=t.parent??null;for(;i!==null&&i!==""&&!o.has(i);){o.add(i);const c=k(i);if(c===null)break;n.unshift(y(c)),i=c.parent??null}const s=C(e).map(c=>k(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,x)=>c.status===x.status?0:c.status==="active"?-1:x.status==="active"?1:0).map(y),u=typeof t.fork_source_file=="string"?P(t.fork_source_file):null,d=G(e);if(d===null)throw v(`unknown node: ${e}`,{received:e});return{node:y(t),warm_spare:R(e),ancestors:n,children:s,fork_source:u===null?null:y(u),subject:d,report_nodes:T()}}r(ne,"extensionState");function F(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}r(F,"samePersona");function ie(e){const t=p(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw a("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw a("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(o=>typeof n[o]!="string"))throw a("recap expected must contain name, description, title, icon, and kind strings");return t}r(ie,"parseGeneratedNameBody");function oe(e){const t=p(e,"broker persona-ack"),n=r(o=>{const i=t[o];if(typeof i!="object"||i===null||Array.isArray(i)||typeof i.kind!="string"||i.mode!=="base"&&i.mode!=="orchestrator"||i.lifecycle!=="terminal"&&i.lifecycle!=="resident")throw a(`${o} must be a persona state`);return i},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}r(oe,"parsePersonaAckBody");function re(e){const t=e.params.id,n=X(e.body),o=n.sessionFile===null?null:N(n.sessionFile);return{status:200,body:l(()=>{const s=h(t);if(I(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const u=s.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))return{action:"shutdown"};if(n.reason==="new"&&s.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&s.fork_from!=null&&s.pi_session_id==null&&o===null)return{action:"shutdown"};const d=o===null?null:P(o);if(d!==null&&d.node_id!==t){if(L(d.pi_pid))return U(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${o}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const c=q(d.node_id);if(c===null||E({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})!=="transferred")return{action:"shutdown"}}else if(j(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(J(t),s.intent==="refresh"&&b(t,"revive")),{action:"none"}})}}r(re,"handleSessionBound");function se(e,t){const n=k(e);if(n===null){if(t.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${e}`,{received:e})}if($(e,new Date().toISOString()),t.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(b(e,"finish"),f(e),w(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(t.stopReason!=="stop"&&t.stopReason!=="length")return f(e,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const o={pushedFinal:t.pushedFinal};if(o.pushedFinal||n.status==="done")return f(e),w(e)!==null&&S(e),_(e,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return f(e),{action:"shutdown"};const i=D(e,o,t.backgroundJobsRunning);return f(e),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?O(e)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:w(e)!==null||W(e)||O(e)?{action:"stay_dormant"}:(b(e,"release"),{action:"shutdown"})}r(se,"settleBroker");function ae(e){const t=e.params.id,n=Z(e.body);m(t,n.expected_execution_id);const o=l(()=>se(t,n));return o.action!=="reprompt"&&Y(t),{status:200,body:o}}r(ae,"handleSettle");function de(e){const t=e.params.id,n=ee(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=H(t);if(i===void 0)return{action:"stay_dormant"};const s=h(t);return Q(t,s,i)?(f(t),b(t,"park"),w(t)!==null&&S(t),_(t,{pane:null,tmux_session:null,window:null}),z({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...M(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}r(de,"handleParkComplete");function ue(e){const t=e.params.id;return m(t,p(e.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:K(t)?"recorded":"none"}))}}r(ue,"handleParkActivity");function ce(e){const t=e.params.id,n=te(e.body);return m(t,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>V(h(t),n.spec,n.pinnedOverride,n.userSelected)).model_override}}}r(ce,"handleModelCommit");function le(e){return{status:200,body:ne(e.params.id)}}r(le,"handleExtensionState");function pe(e){const t=e.params.id,n=ie(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:B(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const s=n.expected;if(i.name!==s.name||(i.description??"")!==s.description||(i.title??"")!==s.title||(i.icon??"")!==s.icon||i.kind!==s.kind)return{applied:!1};const u=g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:B(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}r(pe,"handleGeneratedName");function fe(e){const t=e.params.id,n=oe(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const i=h(t),s={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},u=i.persona_ack,d=u===void 0?s:{kind:u.kind??i.kind,mode:u.mode,lifecycle:u.lifecycle};return!F(s,n.to)||!F(d,n.from)?{applied:!1}:(g(t,{persona_ack:n.to}),{applied:!0})})}}r(fe,"handlePersonaAck");const qe=[{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:re},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:ae},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:de},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:ue},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:ce},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:le},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:fe}];export{qe as brokerOperationRoutes};
@@ -1 +1,14 @@
1
- var u=Object.defineProperty;var s=(o,t)=>u(o,"name",{value:t,configurable:!0});import{listNodes as c}from"../../../core/canvas/canvas.js";import{apiSocketPath as i}from"../../../core/canvas/paths.js";import{currentVersion as l}from"../../../core/self-update.js";import{API_VERSION as p}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as d}from"../../supervise-cadence.js";import{envCrtrdTcp as m}from"../../../shared/env.js";import{isPidAlive as _}from"../../../core/canvas/pid.js";import{readLiveTurn as h}from"../../../core/canvas/recovery.js";import{boundDaemonControl as r}from"../../control.js";const f=d;function a(){try{return c()}catch{return null}}s(a,"canvasRows");function b(o){const t={};for(const e of o)t[e.status]=(t[e.status]??0)+1;return t}s(b,"nodeCounts");function k(){const o=a()!==null,t=r()?.startupBlock()??null,e={ok:o&&t===null,daemon_up:!0,store_accessible:o,brokers_reconciled:t===null,startup_phase:t?.phase??"ready",...t===null?{}:{startup_blocked:t.message}};return{status:e.ok?200:503,body:e}}s(k,"handleHealthz");function v(){const o=a();if(o===null)throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};const t=o.filter(n=>n.kind!=="human"&&h(n.node_id)?.busy===!0&&_(n.pi_pid)).length,e=m();return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:f,node_counts:b(o),busy_node_count:t,listeners:{socket_path:i(),tcp:e!==void 0&&e!==""?e:null},runtime_version:l(),api_version:p,startup_phase:r()?.startupBlock()?.phase??"ready"}}}s(v,"handleStatus");const g=[{method:"GET",pattern:"/healthz",handler:s(o=>k(),"handler")},{method:"GET",pattern:"/v1/status",handler:s(o=>v(),"handler")}];export{g as healthRoutes};
1
+ var u=Object.defineProperty;var e=(t,o)=>u(t,"name",{value:o,configurable:!0});import{openDb as r}from"../../../core/canvas/db.js";import{apiSocketPath as c}from"../../../core/canvas/paths.js";import{currentVersion as i}from"../../../core/self-update.js";import{API_VERSION as p}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as d}from"../../supervise-cadence.js";import{envCrtrdTcp as l}from"../../../shared/env.js";import{isPidAlive as _}from"../../../core/canvas/pid.js";import{boundDaemonControl as s}from"../../control.js";const m=d;function a(){try{return r().prepare("SELECT 1 FROM nodes LIMIT 1").get(),!0}catch{return!1}}e(a,"canvasAccessible");function h(){const t={},o=r().prepare(`
2
+ SELECT status, COUNT(*) AS count
3
+ FROM node_rows
4
+ WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
5
+ GROUP BY status
6
+ `).all();for(const n of o)t[n.status]=n.count;return t}e(h,"nodeCounts");function E(){return r().prepare(`
7
+ SELECT pi_pid
8
+ FROM node_rows
9
+ WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
10
+ AND kind != 'human'
11
+ AND pi_pid IS NOT NULL
12
+ AND turn_open_at IS NOT NULL
13
+ AND turn_closed_at IS NULL
14
+ `).all().filter(o=>_(o.pi_pid)).length}e(E,"busyNodeCount");function f(){const t=a(),o=s()?.startupBlock()??null,n={ok:t&&o===null,daemon_up:!0,store_accessible:t,brokers_reconciled:o===null,startup_phase:o?.phase??"ready",...o===null?{}:{startup_blocked:o.message}};return{status:n.ok?200:503,body:n}}e(f,"handleHealthz");function N(){if(!a())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};const t=l();return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:m,node_counts:h(),busy_node_count:E(),listeners:{socket_path:c(),tcp:t!==void 0&&t!==""?t:null},runtime_version:i(),api_version:p,startup_phase:s()?.startupBlock()?.phase??"ready"}}}e(N,"handleStatus");const k=[{method:"GET",pattern:"/healthz",handler:e(t=>f(),"handler")},{method:"GET",pattern:"/v1/status",handler:e(t=>N(),"handler")}];export{k as healthRoutes};
@@ -1 +1 @@
1
- var _=Object.defineProperty;var o=(e,t)=>_(e,"name",{value:t,configurable:!0});import{ApiError as n}from"../../../api/index.js";import{inboxPageProjection as b}from"./inbox-page.js";import{getRequestByInboxTicket as w}from"../../../core/human/requests.js";import{parsePage as g}from"../../../core/human/page.js";import{scanInbox as m,scanPageHistory as v}from"../../../core/human/scan.js";import{readPageTicket as u,readTicketResult as p,selectedPageDir as y,validatePageTicketResponses as q,writePageProgress as T}from"../../../core/human/tickets.js";import{describePageAnswer as I}from"../../../core/human/answer.js";import{cancelHumanTicket as x,resolvePageTicket as A}from"../../human/finish.js";const P="Canceled from the inbox.",E=1e3,R=/^[a-f0-9]{64}$/;function d(e){const t=w(e);return t===null?null:{ticketId:t.request_id,dir:t.request_dir,kind:t.kind}}o(d,"resolveTicket");function c(e){const t=e.ticket_id;if(t===void 0||!R.test(t))throw new n(400,"invalid_request","invalid ticket id");return t}o(c,"requireTicketId");function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(l,"isPlainObject");function h(e,t){for(const i of Object.keys(e))if(!t.includes(i))throw new n(400,"invalid_request",`unexpected field: ${i}`)}o(h,"requireNoExtraKeys");function O(e){if(!l(e))throw new n(400,"invalid_request","respond body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}o(O,"validateRespondRequest");function S(e){if(!l(e))throw new n(400,"invalid_request","progress body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}o(S,"validateProgressRequest");function C(e){if(e===void 0)return{};if(!l(e))throw new n(400,"invalid_request","cancel body must be an object");if(h(e,["reason"]),e.reason===void 0)return{};const t=e.reason;if(typeof t!="string")throw new n(400,"invalid_request","`reason` must be a string");if(t.trim()===""||t.length>E)throw new n(400,"invalid_request","`reason` must be nonempty after trim and at most 1000 characters");return{reason:t}}o(C,"validateCancelRequest");const D=[/^slot ".*?" /,/^response names unknown or non-response-bearing slot id/,/^final page response is missing response-bearing slot id/];function k(e){return e instanceof Error&&D.some(t=>t.test(e.message))}o(k,"isSlotValidationError");function f(e){const t={request_id:e.id,request_dir:e.dir,ticket_id:e.inboxTicketId,kind:"page",title:e.title,placement:e.placement,dialect:e.dialect,steps:e.steps,emitted_at:e.emittedAt,source:e.source,slot_kinds:e.slotKinds,inbox:e.inbox,awaits_response:e.awaitsResponse,state:e.state};return e.subtitle!==""&&(t.subtitle=e.subtitle),e.answerDigest!==void 0&&(t.answer_digest=e.answerDigest),e.recommendedOptions.length>0&&(t.recommended_options=e.recommendedOptions.map(i=>({slot_id:i.slotId,option_id:i.optionId,label:i.label}))),e.fastAction!==void 0&&(t.fast_action={kind:e.fastAction.kind,responses:e.fastAction.responses}),t}o(f,"pageSummaryToDTO");function N(){return{status:200,body:{tickets:m().map(t=>{if(t.kind==="page")return f(t);if(t.kind==="review")return{request_id:t.id,request_dir:t.dir,ticket_id:t.inboxTicketId,kind:"review",title:t.title,subtitle:t.subtitle,blocked_since:t.blockedSince,source:t.source};throw new Error(`unknown ticket kind: ${t.kind}`)}).sort((t,i)=>{const s=o(a=>a.kind==="page"?a.emitted_at:a.blocked_since,"pageTime"),r=Date.parse(s(i))-Date.parse(s(t));return r!==0?r:t.ticket_id.localeCompare(i.ticket_id)})}}}o(N,"handleList");function j(e){const t=e.query.get("node_id");if(t==="")throw new n(400,"invalid_request","node_id must be nonempty when present");return{status:200,body:{tickets:v(t??void 0).map(f)}}}o(j,"handleHistory");function G(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have no page read operation");const s=w(t);if(s===null||s.kind!=="page")throw new n(404,"ticket_not_found","no matching ticket");try{return{status:200,body:b(s)}}catch{throw new n(500,"internal","the ticket could not be read")}}o(G,"handleGetPage");async function L(e){const t=c(e.params),i=O(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets submit through their own path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const r=p(s.dir);if(r!==null&&r.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");if(r?.kind==="canceled")throw new n(409,"ticket_canceled","canceled tickets cannot be answered");try{q(s.dir,i.responses)}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","validation failed")}try{const a=await A(s.ticketId,i.responses);if(a.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");return{status:200,body:a}}catch(a){throw a instanceof n?a:k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","the ticket could not be finalized")}}o(L,"handleRespond");function H(e){const t=c(e.params),i=S(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets do not support progress autosave");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const r=p(s.dir);if(r!==null&&r.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");try{return T(s.dir,i.responses),{status:200,body:{}}}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","progress could not be saved")}}o(H,"handleProgress");async function K(e){const t=c(e.params),i=C(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have their own cancel path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");try{const r=await x(s.ticketId,{reason:i.reason??P,actor:"human",disposition:"dismissed"});if(r.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");return{status:200,body:r}}catch(r){throw r instanceof n?r:new n(500,"internal","the ticket could not be canceled")}}o(K,"handleCancel");function $(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets fetch responses through their own path");const s=p(i.dir);if(s===null)throw new n(404,"ticket_pending","ticket has no response yet");if(s.kind==="canceled")throw new n(404,"ticket_canceled","canceled tickets have no response");if(s.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");try{const r=g(y(i.dir));return{status:200,body:{...s,answer:I(r,s.responses,{completedAt:s.completedAt})}}}catch{throw new n(500,"internal","the ticket answer could not be read")}}o($,"handleGetResponse");const W=[{method:"GET",pattern:"/v1/human/inbox",handler:N},{method:"GET",pattern:"/v1/human/inbox/history",handler:j},{method:"GET",pattern:"/v1/human/inbox/:ticket_id",handler:G},{method:"GET",pattern:"/v1/human/inbox/:ticket_id/response",handler:$},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/respond",handler:L},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/progress",handler:H},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/cancel",handler:K}];export{W as inboxRoutes,c as requireTicketId,d as resolveTicket};
1
+ var _=Object.defineProperty;var r=(e,t)=>_(e,"name",{value:t,configurable:!0});import{ApiError as n}from"../../../api/index.js";import{inboxPageProjection as b}from"./inbox-page.js";import{getRequestByInboxTicket as w}from"../../../core/human/requests.js";import{parsePage as m}from"../../../core/human/page.js";import{scanInbox as g,scanPageHistory as v}from"../../../core/human/scan.js";import{readPageTicket as u,readTicketResult as p,selectedPageDir as y,validatePageTicketResponses as q,writePageProgress as T}from"../../../core/human/tickets.js";import{describePageAnswer as I}from"../../../core/human/answer.js";import{cancelHumanTicket as x,resolvePageTicket as A}from"../../human/finish.js";const P="Canceled from the inbox.",E=1e3,R=/^[a-f0-9]{64}$/;function d(e){const t=w(e);return t===null?null:{ticketId:t.request_id,dir:t.request_dir,kind:t.kind}}r(d,"resolveTicket");function c(e){const t=e.ticket_id;if(t===void 0||!R.test(t))throw new n(400,"invalid_request","invalid ticket id");return t}r(c,"requireTicketId");function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}r(l,"isPlainObject");function h(e,t){for(const i of Object.keys(e))if(!t.includes(i))throw new n(400,"invalid_request",`unexpected field: ${i}`)}r(h,"requireNoExtraKeys");function O(e){if(!l(e))throw new n(400,"invalid_request","respond body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}r(O,"validateRespondRequest");function S(e){if(!l(e))throw new n(400,"invalid_request","progress body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}r(S,"validateProgressRequest");function C(e){if(e===void 0)return{};if(!l(e))throw new n(400,"invalid_request","cancel body must be an object");if(h(e,["reason"]),e.reason===void 0)return{};const t=e.reason;if(typeof t!="string")throw new n(400,"invalid_request","`reason` must be a string");if(t.trim()===""||t.length>E)throw new n(400,"invalid_request","`reason` must be nonempty after trim and at most 1000 characters");return{reason:t}}r(C,"validateCancelRequest");const D=[/^slot ".*?" /,/^response names unknown or non-response-bearing slot id/,/^final page response is missing response-bearing slot id/];function k(e){return e instanceof Error&&D.some(t=>t.test(e.message))}r(k,"isSlotValidationError");function f(e){const t={request_id:e.id,request_dir:e.dir,ticket_id:e.inboxTicketId,kind:"page",title:e.title,placement:e.placement,dialect:e.dialect,steps:e.steps,emitted_at:e.emittedAt,source:e.source,slot_kinds:e.slotKinds,inbox:e.inbox,awaits_response:e.awaitsResponse,state:e.state};return e.subtitle!==""&&(t.subtitle=e.subtitle),e.answerDigest!==void 0&&(t.answer_digest=e.answerDigest),e.recommendedOptions.length>0&&(t.recommended_options=e.recommendedOptions.map(i=>({slot_id:i.slotId,option_id:i.optionId,label:i.label}))),e.fastAction!==void 0&&(t.fast_action={kind:e.fastAction.kind,responses:e.fastAction.responses}),t}r(f,"pageSummaryToDTO");function N(){return{status:200,body:{tickets:g().map(t=>{if(t.kind==="page")return f(t);if(t.kind==="review")return{request_id:t.id,request_dir:t.dir,ticket_id:t.inboxTicketId,kind:"review",title:t.title,subtitle:t.subtitle,blocked_since:t.blockedSince,source:t.source};throw new Error(`unknown ticket kind: ${t.kind}`)}).sort((t,i)=>{const s=r(a=>a.kind==="page"?a.emitted_at:a.blocked_since,"pageTime"),o=Date.parse(s(i))-Date.parse(s(t));return o!==0?o:t.ticket_id.localeCompare(i.ticket_id)})}}}r(N,"handleList");function j(e){const t=e.query.get("node_id");if(t==="")throw new n(400,"invalid_request","node_id must be nonempty when present");return{status:200,body:{tickets:v(t??void 0).map(f)}}}r(j,"handleHistory");function G(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have no page read operation");const s=w(t);if(s===null||s.kind!=="page")throw new n(404,"ticket_not_found","no matching ticket");try{return{status:200,body:b(s)}}catch{throw new n(500,"internal","the ticket could not be read")}}r(G,"handleGetPage");async function L(e){const t=c(e.params),i=O(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets submit through their own path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const o=p(s.dir);if(o!==null&&o.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");if(o?.kind==="canceled")throw new n(409,"ticket_canceled","canceled tickets cannot be answered");try{q(s.dir,i.responses)}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","validation failed")}try{const a=await A(s.ticketId,i.responses);if(a.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");return{status:200,body:a}}catch(a){throw a instanceof n?a:k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","the ticket could not be finalized")}}r(L,"handleRespond");function H(e){const t=c(e.params),i=S(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets do not support progress autosave");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const o=p(s.dir);if(o!==null&&o.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");try{return T(s.dir,i.responses),{status:200,body:{}}}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","progress could not be saved")}}r(H,"handleProgress");async function K(e){const t=c(e.params),i=C(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have their own cancel path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");try{const o=await x(s.ticketId,{reason:i.reason??P,actor:"human",disposition:"dismissed"});if(o.outcome==="already_settled"||o.result.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");return{status:200,body:o.result}}catch(o){throw o instanceof n?o:new n(500,"internal","the ticket could not be canceled")}}r(K,"handleCancel");function $(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets fetch responses through their own path");const s=p(i.dir);if(s===null)throw new n(404,"ticket_pending","ticket has no response yet");if(s.kind==="canceled")throw new n(404,"ticket_canceled","canceled tickets have no response");if(s.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");try{const o=m(y(i.dir));return{status:200,body:{...s,answer:I(o,s.responses,{completedAt:s.completedAt})}}}catch{throw new n(500,"internal","the ticket answer could not be read")}}r($,"handleGetResponse");const W=[{method:"GET",pattern:"/v1/human/inbox",handler:N},{method:"GET",pattern:"/v1/human/inbox/history",handler:j},{method:"GET",pattern:"/v1/human/inbox/:ticket_id",handler:G},{method:"GET",pattern:"/v1/human/inbox/:ticket_id/response",handler:$},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/respond",handler:L},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/progress",handler:H},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/cancel",handler:K}];export{W as inboxRoutes,c as requireTicketId,d as resolveTicket};
@@ -1 +1 @@
1
- var W=Object.defineProperty;var d=(n,t)=>W(n,"name",{value:t,configurable:!0});import{randomUUID as q}from"node:crypto";import{getNode as z}from"../../../core/canvas/canvas.js";import{isSafeNodeId as S}from"../../../core/canvas/paths.js";import{createComment as J,deleteComment as X,editComment as Y,getComment as A,listCommentEvents as Z,listComments as O,listReviewEvents as ee,reopenComment as ne,resolveComment as te}from"../../../core/review/comments.js";import{withCanvasWrite as C}from"../../../core/canvas/db.js";import{captureAnchorText as ie,requireCurrentDocumentLocked as oe}from"../../../core/review/document.js";import{applyRangeBatch as re}from"../../../core/review/remap.js";import{getReviewByCompanion as de,requireVisibleReview as _}from"../../../core/review/store.js";import{ReviewOperationError as p}from"../../../core/review/types.js";import{notifyComment as se}from"../../review/comment-notify.js";import{toReviewCommentDTO as v,toReviewCommentEventDTO as T}from"../map.js";import{invalidRequest as ce,isRecord as $,objectBody as R,requireParam as x,requiredString as I}from"./validate.js";const D=/^[a-f0-9]{32}$/,P=/^[a-f0-9]{64}$/,ue=new Set(["open","resolved","deleted","all"]),ae=new Set(["wake","quiet"]);function m(n){ce("review comment request",n)}d(m,"invalidRequest");function me(n,t,e){const i=n[t];if(i!==void 0){if(typeof i!="string"||!P.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",received:i});return}return i}}d(me,"optionalSha256");function j(n,t,e){const i=n[t];if(typeof i!="string"||!P.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",...i===void 0?{}:{received:i}});return}return i}d(j,"requiredSha256");function N(n,t){const e=n.deliver;if(e!==void 0){if(typeof e!="string"||!ae.has(e)){t.push({field:"deliver",problem:"must be wake or quiet",received:e});return}return e}}d(N,"optionalDeliver");function le(n,t){const e=n.if_revision;if(e!==void 0){if(!Number.isSafeInteger(e)||e<0){t.push({field:"if_revision",problem:"must be a non-negative safe integer",received:e});return}return e}}d(le,"optionalRevision");function L(n,t){const e=n.actor_node_id;return e==null?{kind:"human",node_id:null}:typeof e!="string"||!S(e)?(t.push({field:"actor_node_id",problem:"must be a safe node id or null",received:e}),null):{kind:"node",node_id:e}}d(L,"actorFrom");function M(n,t,e){z(n)===null&&e.push({field:t,problem:"must name an existing node",received:n})}d(M,"requireKnownNode");function B(n,t){n.node_id!==null&&M(n.node_id,"actor_node_id",t)}d(B,"requireKnownActor");function G(n,t,e){if(!$(n)){e.push({field:t,problem:"must be an anchor object",received:n});return}const i=["line","end_line","col_start","col_end","quote"];for(const o of Object.keys(n))i.includes(o)||e.push({field:`${t}.${o}`,problem:"is not allowed",received:n[o]});const r=n.line,s=n.end_line;typeof r!="number"&&e.push({field:`${t}.line`,problem:"must be a number",...r===void 0?{}:{received:r}}),typeof s!="number"&&e.push({field:`${t}.end_line`,problem:"must be a number",...s===void 0?{}:{received:s}});for(const o of["col_start","col_end"]){const c=n[o];c!==void 0&&typeof c!="number"&&e.push({field:`${t}.${o}`,problem:"must be a number",received:c})}if(n.quote!==void 0&&typeof n.quote!="string"&&e.push({field:`${t}.quote`,problem:"must be a string",received:n.quote}),!(typeof r!="number"||typeof s!="number"))return{line:r,end_line:s,...typeof n.col_start=="number"?{col_start:n.col_start}:{},...typeof n.col_end=="number"?{col_end:n.col_end}:{},...typeof n.quote=="string"?{quote:n.quote}:{}}}d(G,"anchorFrom");function w(n,t){return x(n,"review_id","must be a safe review id",S,t)}d(w,"requireReviewId");function F(n,t){return x(n,"comment_id","must be a 32-character lowercase hexadecimal id",e=>D.test(e),t)}d(F,"requireCommentId");function b(n){const t=_(n);if(t.state!=="open")throw new p("review_terminal","review already has a terminal outcome",{state:t.state,requested:"comment",review:t});return t}d(b,"requireOpenReview");function H(n){const t=n===null?null:de(n);if(t===null||t.state!=="open")throw new p("review_required","an open review is required when no review id is supplied",{actor_node_id:n});return t}d(H,"requireCompanionReview");function fe(n){return{comment:v(n),events:Z(n.comment_id).map(T)}}d(fe,"toDetail");function he(n,t){return{attempted:!0,target_node_id:n.companion_node_id,status:"failed",woke:!1,error:t instanceof Error?t.message:String(t)}}d(he,"deliveryFailure");async function U(n){if(!n.changed)return{comment:v(n.comment),changed:!1};let t;try{t=await se({review:n.review,comment:n.comment,verb:n.verb,actor_node_id:n.actor.node_id,deliver:n.deliver,operation_id:n.operationId})}catch(e){t=he(n.review,e)}return{comment:v(n.comment),changed:!0,delivery:t}}d(U,"mutationResult");function _e(n,t){const e=[],i=R(n.body,["text","anchor","doc_hash","actor_node_id","deliver"],e),r=t==="review"?(()=>{const a=w(n,e);return a===void 0?void 0:{kind:"review",review_id:a}})():{kind:"self"},s=I(i,"text",e),o=G(i.anchor,"anchor",e),c=me(i,"doc_hash",e),u=L(i,e),f=N(i,e);return u!==null&&B(u,e),(e.length>0||r===void 0||s===void 0||o===void 0||u===null)&&m(e),{selector:r,text:s,anchor:o,...c===void 0?{}:{doc_hash:c},actor:u,...f===void 0?{}:{deliver:f}}}d(_e,"parseCreate");function pe(n,t){const e=[],i=R(n.body,t?["text","actor_node_id","deliver","if_revision"]:["actor_node_id","deliver","if_revision"],e),r=F(n,e),s=t?I(i,"text",e):void 0,o=L(i,e),c=N(i,e),u=le(i,e);return o!==null&&B(o,e),(e.length>0||r===void 0||o===null||t&&s===void 0)&&m(e),{comment_id:r,...s===void 0?{}:{text:s},actor:o,...c===void 0?{}:{deliver:c},...u===void 0?{}:{if_revision:u}}}d(pe,"parseAction");function ve(n){const t=[],e=R(n.body,["from_doc_hash","to_doc_hash","entries"],t),i=w(n,t),r=j(e,"from_doc_hash",t),s=j(e,"to_doc_hash",t),o=e.entries,c=[];return Array.isArray(o)?o.forEach((u,f)=>{const a=`entries[${f}]`;if(!$(u)){t.push({field:a,problem:"must be an object",received:u});return}for(const g of Object.keys(u))["comment_id","anchor","detached"].includes(g)||t.push({field:`${a}.${g}`,problem:"is not allowed",received:u[g]});const l=u.comment_id;if(typeof l!="string"||!D.test(l)){t.push({field:`${a}.comment_id`,problem:"must be a 32-character lowercase hexadecimal id",received:l});return}const K=u.anchor!==void 0,h=u.detached;h!==void 0&&h!==!0&&t.push({field:`${a}.detached`,problem:"must be true when present",received:h});const k=h===!0;if(K===k){t.push({field:a,problem:"must provide exactly one of anchor or detached: true"});return}if(k){c.push({comment_id:l,detached:!0});return}const E=G(u.anchor,`${a}.anchor`,t);E!==void 0&&c.push({comment_id:l,anchor:E})}):t.push({field:"entries",problem:"must be an array",received:o}),(t.length>0||i===void 0||r===void 0||s===void 0||!Array.isArray(o))&&m(t),{review_id:i,request:{from_doc_hash:r,to_doc_hash:s,entries:c}}}d(ve,"parseRangeBatch");function we(n,t,e){for(const[o,c]of n.query)o!=="status"&&(o!=="actor_node_id"||t!=="self")&&e.push({field:o,problem:"is not allowed",received:c});const i=n.query.getAll("status");(i.length>1||i.length===1&&!ue.has(i[0]))&&e.push({field:"status",problem:"must be open, resolved, deleted, or all",received:i.length>1?i:i[0]});const r=n.query.getAll("actor_node_id");let s=null;if(r.length>1)e.push({field:"actor_node_id",problem:"must appear at most once",received:r});else if(r.length===1){const o=r[0];S(o)?(s=o,M(o,"actor_node_id",e)):e.push({field:"actor_node_id",problem:"must be a safe node id",received:o})}return{...i.length===0?{}:{status:i[0]},actor_node_id:s}}d(we,"parseListQuery");function be(n,t){const e={};for(const[i,r]of n.query)i!=="since_seq"&&i!=="limit"&&t.push({field:i,problem:"is not allowed",received:r});for(const i of["since_seq","limit"]){const r=n.query.getAll(i);if(r.length>1){t.push({field:i,problem:"must appear at most once",received:r});continue}if(r.length===0)continue;const s=r[0],o=Number(s);if(!Number.isSafeInteger(o)||o<0||String(o)!==s){t.push({field:i,problem:"must be a non-negative safe integer",received:s});continue}e[i]=o}return e.limit!==void 0&&e.limit<1&&t.push({field:"limit",problem:"must be at least 1",received:e.limit}),e}d(be,"parseEventQuery");async function V(n,t){const e=_e(n,t),i=q(),r=C(s=>{const o=e.selector.kind==="review"?b(e.selector.review_id):b(H(e.actor.node_id).review_id),c=oe(s,o.review_id,e.doc_hash??o.anchor_base_sha256),u=J({review_id:o.review_id,text:e.text,anchor:e.anchor,line_text:ie(c.lines,e.anchor),doc_hash:c.sha256,actor:e.actor,operation_id:i});return{review:o,mutation:u}});return{status:200,body:await U({review:r.review,...r.mutation,verb:"create",actor:e.actor,deliver:e.deliver,operationId:i})}}d(V,"handleCreate");function Q(n,t){const e=[],i=t==="review"?(()=>{const c=w(n,e);return c===void 0?void 0:{kind:"review",review_id:c}})():{kind:"self"},r=we(n,t,e);(e.length>0||i===void 0)&&m(e);const s=i.kind==="review"?_(i.review_id):H(r.actor_node_id);return{status:200,body:{review_id:s.review_id,comments:O(s.review_id,r).map(v)}}}d(Q,"handleList");function ye(n){const t=[],e=w(n,t),i=be(n,t);(t.length>0||e===void 0)&&m(t);const r=_(e),s=ee(r.review_id,i);return{status:200,body:{review_id:r.review_id,events:s.events.map(T),next_since_seq:s.events.length===0?null:s.next_since_seq}}}d(ye,"handleEvents");function ge(n){const{review_id:t,request:e}=ve(n),i=q(),r=C(()=>{const o=b(t),c=O(o.review_id).length,u=re({review_id:o.review_id,...e,actor:{kind:"human",node_id:null},operation_id:i});return{review:o,nondeleted:c,applied:u}});return{status:200,body:{review_id:r.review.review_id,anchor_base_sha256:r.applied.anchor_base_sha256,updated:r.applied.updated,detached:r.applied.detached,unchanged:r.nondeleted-r.applied.updated}}}d(ge,"handleRanges");function qe(n){const t=[],e=F(n,t);(t.length>0||e===void 0)&&m(t);const i=A(e);if(i===null)throw new p("unknown_comment","comment was not found",{received:e});return _(i.review_id),{status:200,body:fe(i)}}d(qe,"handleDetail");async function y(n,t){const e=pe(n,t==="edit"),i=q(),r=C(()=>{const s=A(e.comment_id);if(s===null)throw new p("unknown_comment","comment was not found",{received:e.comment_id});const o=b(s.review_id),c=t==="edit"?Y(e.comment_id,{text:e.text,actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="resolve"?te(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="reopen"?ne(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):X(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision});return{review:o,mutation:c}});return{status:200,body:await U({review:r.review,...r.mutation,verb:t,actor:e.actor,deliver:e.deliver,operationId:i})}}d(y,"handleAction");const je=[{method:"POST",pattern:"/v1/human/reviews/self/comments",handler:d(n=>V(n,"self"),"handler")},{method:"GET",pattern:"/v1/human/reviews/self/comments",handler:d(n=>Q(n,"self"),"handler")},{method:"POST",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>V(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>Q(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comment-events",handler:ye},{method:"POST",pattern:"/v1/human/reviews/:review_id/comment-ranges",handler:ge},{method:"GET",pattern:"/v1/human/comments/:comment_id",handler:qe},{method:"POST",pattern:"/v1/human/comments/:comment_id/edit",handler:d(n=>y(n,"edit"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/resolve",handler:d(n=>y(n,"resolve"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/reopen",handler:d(n=>y(n,"reopen"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/delete",handler:d(n=>y(n,"delete"),"handler")}];export{je as reviewCommentRoutes};
1
+ var z=Object.defineProperty;var d=(n,t)=>z(n,"name",{value:t,configurable:!0});import{randomUUID as q}from"node:crypto";import{getNode as T}from"../../../core/canvas/canvas.js";import{isSafeNodeId as S}from"../../../core/canvas/paths.js";import{createComment as J,deleteComment as X,editComment as Y,getComment as A,listCommentEvents as Z,listComments as $,listReviewEvents as ee,reopenComment as ne,resolveComment as te}from"../../../core/review/comments.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{captureAnchorText as ie,requireCurrentDocumentLocked as oe}from"../../../core/review/document.js";import{forkReviewComment as re}from"../../../core/review/fork.js";import{applyRangeBatch as de}from"../../../core/review/remap.js";import{getReviewByCompanion as se,requireVisibleReview as f}from"../../../core/review/store.js";import{ReviewOperationError as v}from"../../../core/review/types.js";import{notifyComment as ce}from"../../review/comment-notify.js";import{toReviewCommentDTO as p,toReviewCommentEventDTO as x}from"../map.js";import{invalidRequest as ue,isRecord as I,objectBody as R,requireParam as D,requiredString as P}from"./validate.js";const j=/^[a-f0-9]{32}$/,L=/^[a-f0-9]{64}$/,ae=new Set(["open","resolved","deleted","all"]),me=new Set(["wake","quiet"]);function m(n){ue("review comment request",n)}d(m,"invalidRequest");function le(n,t,e){const i=n[t];if(i!==void 0){if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",received:i});return}return i}}d(le,"optionalSha256");function M(n,t,e){const i=n[t];if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",...i===void 0?{}:{received:i}});return}return i}d(M,"requiredSha256");function B(n,t){const e=n.deliver;if(e!==void 0){if(typeof e!="string"||!me.has(e)){t.push({field:"deliver",problem:"must be wake or quiet",received:e});return}return e}}d(B,"optionalDeliver");function fe(n,t){const e=n.if_revision;if(e!==void 0){if(!Number.isSafeInteger(e)||e<0){t.push({field:"if_revision",problem:"must be a non-negative safe integer",received:e});return}return e}}d(fe,"optionalRevision");function F(n,t){const e=n.actor_node_id;return e==null?{kind:"human",node_id:null}:typeof e!="string"||!S(e)?(t.push({field:"actor_node_id",problem:"must be a safe node id or null",received:e}),null):{kind:"node",node_id:e}}d(F,"actorFrom");function G(n,t,e){T(n)===null&&e.push({field:t,problem:"must name an existing node",received:n})}d(G,"requireKnownNode");function N(n,t){n.node_id!==null&&G(n.node_id,"actor_node_id",t)}d(N,"requireKnownActor");function H(n,t,e){if(!I(n)){e.push({field:t,problem:"must be an anchor object",received:n});return}const i=["line","end_line","col_start","col_end","quote"];for(const r of Object.keys(n))i.includes(r)||e.push({field:`${t}.${r}`,problem:"is not allowed",received:n[r]});const o=n.line,s=n.end_line;typeof o!="number"&&e.push({field:`${t}.line`,problem:"must be a number",...o===void 0?{}:{received:o}}),typeof s!="number"&&e.push({field:`${t}.end_line`,problem:"must be a number",...s===void 0?{}:{received:s}});for(const r of["col_start","col_end"]){const c=n[r];c!==void 0&&typeof c!="number"&&e.push({field:`${t}.${r}`,problem:"must be a number",received:c})}if(n.quote!==void 0&&typeof n.quote!="string"&&e.push({field:`${t}.quote`,problem:"must be a string",received:n.quote}),!(typeof o!="number"||typeof s!="number"))return{line:o,end_line:s,...typeof n.col_start=="number"?{col_start:n.col_start}:{},...typeof n.col_end=="number"?{col_end:n.col_end}:{},...typeof n.quote=="string"?{quote:n.quote}:{}}}d(H,"anchorFrom");function w(n,t){return D(n,"review_id","must be a safe review id",S,t)}d(w,"requireReviewId");function C(n,t){return D(n,"comment_id","must be a 32-character lowercase hexadecimal id",e=>j.test(e),t)}d(C,"requireCommentId");function b(n){const t=f(n);if(t.state!=="open")throw new v("review_terminal","review already has a terminal outcome",{state:t.state,requested:"comment",review:t});return t}d(b,"requireOpenReview");function U(n){const t=n===null?void 0:T(n)?.review_binding?.review_id,e=n===null?null:se(n)??(t===void 0?null:f(t));if(e===null||e.state!=="open")throw new v("review_required","an open review is required when no review id is supplied",{actor_node_id:n});return e}d(U,"requireCompanionReview");function he(n){return{comment:p(n),events:Z(n.comment_id).map(x)}}d(he,"toDetail");function _e(n,t){return{attempted:!0,target_node_id:n.companion_node_id,status:"failed",woke:!1,error:t instanceof Error?t.message:String(t)}}d(_e,"deliveryFailure");async function V(n){if(!n.changed)return{comment:p(n.comment),changed:!1};let t;try{t=await ce({review:n.review,comment:n.comment,verb:n.verb,actor_node_id:n.actor.node_id,deliver:n.deliver,operation_id:n.operationId})}catch(e){t=_e(n.review,e)}return{comment:p(n.comment),changed:!0,delivery:t}}d(V,"mutationResult");function ve(n,t){const e=[],i=R(n.body,["text","anchor","doc_hash","actor_node_id","deliver"],e),o=t==="review"?(()=>{const a=w(n,e);return a===void 0?void 0:{kind:"review",review_id:a}})():{kind:"self"},s=P(i,"text",e),r=H(i.anchor,"anchor",e),c=le(i,"doc_hash",e),u=F(i,e),h=B(i,e);return u!==null&&N(u,e),(e.length>0||o===void 0||s===void 0||r===void 0||u===null)&&m(e),{selector:o,text:s,anchor:r,...c===void 0?{}:{doc_hash:c},actor:u,...h===void 0?{}:{deliver:h}}}d(ve,"parseCreate");function pe(n,t){const e=[],i=R(n.body,t?["text","actor_node_id","deliver","if_revision"]:["actor_node_id","deliver","if_revision"],e),o=C(n,e),s=t?P(i,"text",e):void 0,r=F(i,e),c=B(i,e),u=fe(i,e);return r!==null&&N(r,e),(e.length>0||o===void 0||r===null||t&&s===void 0)&&m(e),{comment_id:o,...s===void 0?{}:{text:s},actor:r,...c===void 0?{}:{deliver:c},...u===void 0?{}:{if_revision:u}}}d(pe,"parseAction");function we(n){const t=[],e=R(n.body,["from_doc_hash","to_doc_hash","entries"],t),i=w(n,t),o=M(e,"from_doc_hash",t),s=M(e,"to_doc_hash",t),r=e.entries,c=[];return Array.isArray(r)?r.forEach((u,h)=>{const a=`entries[${h}]`;if(!I(u)){t.push({field:a,problem:"must be an object",received:u});return}for(const g of Object.keys(u))["comment_id","anchor","detached"].includes(g)||t.push({field:`${a}.${g}`,problem:"is not allowed",received:u[g]});const l=u.comment_id;if(typeof l!="string"||!j.test(l)){t.push({field:`${a}.comment_id`,problem:"must be a 32-character lowercase hexadecimal id",received:l});return}const W=u.anchor!==void 0,_=u.detached;_!==void 0&&_!==!0&&t.push({field:`${a}.detached`,problem:"must be true when present",received:_});const E=_===!0;if(W===E){t.push({field:a,problem:"must provide exactly one of anchor or detached: true"});return}if(E){c.push({comment_id:l,detached:!0});return}const O=H(u.anchor,`${a}.anchor`,t);O!==void 0&&c.push({comment_id:l,anchor:O})}):t.push({field:"entries",problem:"must be an array",received:r}),(t.length>0||i===void 0||o===void 0||s===void 0||!Array.isArray(r))&&m(t),{review_id:i,request:{from_doc_hash:o,to_doc_hash:s,entries:c}}}d(we,"parseRangeBatch");function be(n,t,e){for(const[r,c]of n.query)r!=="status"&&(r!=="actor_node_id"||t!=="self")&&e.push({field:r,problem:"is not allowed",received:c});const i=n.query.getAll("status");(i.length>1||i.length===1&&!ae.has(i[0]))&&e.push({field:"status",problem:"must be open, resolved, deleted, or all",received:i.length>1?i:i[0]});const o=n.query.getAll("actor_node_id");let s=null;if(o.length>1)e.push({field:"actor_node_id",problem:"must appear at most once",received:o});else if(o.length===1){const r=o[0];S(r)?(s=r,G(r,"actor_node_id",e)):e.push({field:"actor_node_id",problem:"must be a safe node id",received:r})}return{...i.length===0?{}:{status:i[0]},actor_node_id:s}}d(be,"parseListQuery");function ye(n,t){const e={};for(const[i,o]of n.query)i!=="since_seq"&&i!=="limit"&&t.push({field:i,problem:"is not allowed",received:o});for(const i of["since_seq","limit"]){const o=n.query.getAll(i);if(o.length>1){t.push({field:i,problem:"must appear at most once",received:o});continue}if(o.length===0)continue;const s=o[0],r=Number(s);if(!Number.isSafeInteger(r)||r<0||String(r)!==s){t.push({field:i,problem:"must be a non-negative safe integer",received:s});continue}e[i]=r}return e.limit!==void 0&&e.limit<1&&t.push({field:"limit",problem:"must be at least 1",received:e.limit}),e}d(ye,"parseEventQuery");async function Q(n,t){const e=ve(n,t),i=q(),o=k(s=>{const r=e.selector.kind==="review"?b(e.selector.review_id):b(U(e.actor.node_id).review_id),c=oe(s,r.review_id,e.doc_hash??r.anchor_base_sha256),u=J({review_id:r.review_id,text:e.text,anchor:e.anchor,line_text:ie(c.lines,e.anchor),doc_hash:c.sha256,actor:e.actor,operation_id:i});return{review:r,mutation:u}});return{status:200,body:await V({review:o.review,...o.mutation,verb:"create",actor:e.actor,deliver:e.deliver,operationId:i})}}d(Q,"handleCreate");function K(n,t){const e=[],i=t==="review"?(()=>{const c=w(n,e);return c===void 0?void 0:{kind:"review",review_id:c}})():{kind:"self"},o=be(n,t,e);(e.length>0||i===void 0)&&m(e);const s=i.kind==="review"?f(i.review_id):U(o.actor_node_id);return{status:200,body:{review_id:s.review_id,comments:$(s.review_id,o).map(p)}}}d(K,"handleList");function ge(n){const t=[],e=w(n,t),i=ye(n,t);(t.length>0||e===void 0)&&m(t);const o=f(e),s=ee(o.review_id,i);return{status:200,body:{review_id:o.review_id,events:s.events.map(x),next_since_seq:s.events.length===0?null:s.next_since_seq}}}d(ge,"handleEvents");function qe(n){const{review_id:t,request:e}=we(n),i=q(),o=k(()=>{const r=b(t),c=$(r.review_id).length,u=de({review_id:r.review_id,...e,actor:{kind:"human",node_id:null},operation_id:i});return{review:r,nondeleted:c,applied:u}});return{status:200,body:{review_id:o.review.review_id,anchor_base_sha256:o.applied.anchor_base_sha256,updated:o.applied.updated,detached:o.applied.detached,unchanged:o.nondeleted-o.applied.updated}}}d(qe,"handleRanges");function Se(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=A(e);if(i===null)throw new v("unknown_comment","comment was not found",{received:e});return f(i.review_id),{status:200,body:he(i)}}d(Se,"handleDetail");async function y(n,t){const e=pe(n,t==="edit"),i=q(),o=k(()=>{const s=A(e.comment_id);if(s===null)throw new v("unknown_comment","comment was not found",{received:e.comment_id});const r=b(s.review_id),c=t==="edit"?Y(e.comment_id,{text:e.text,actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="resolve"?te(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="reopen"?ne(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):X(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision});return{review:r,mutation:c}});return{status:200,body:await V({review:o.review,...o.mutation,verb:t,actor:e.actor,deliver:e.deliver,operationId:i})}}d(y,"handleAction");async function ke(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=await re(e);return{status:200,body:{comment_id:e,node_id:i.node_id,cwd:i.cwd}}}d(ke,"handleFork");const Be=[{method:"POST",pattern:"/v1/human/reviews/self/comments",handler:d(n=>Q(n,"self"),"handler")},{method:"GET",pattern:"/v1/human/reviews/self/comments",handler:d(n=>K(n,"self"),"handler")},{method:"POST",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>Q(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>K(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comment-events",handler:ge},{method:"POST",pattern:"/v1/human/reviews/:review_id/comment-ranges",handler:qe},{method:"GET",pattern:"/v1/human/comments/:comment_id",handler:Se},{method:"POST",pattern:"/v1/human/comments/:comment_id/edit",handler:d(n=>y(n,"edit"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/resolve",handler:d(n=>y(n,"resolve"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/reopen",handler:d(n=>y(n,"reopen"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/delete",handler:d(n=>y(n,"delete"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/fork",handler:ke}];export{Be as reviewCommentRoutes};
@@ -7,12 +7,14 @@ import type { CloseNodeResult } from '../../core/runtime/close.js';
7
7
  import { type PushResult } from '../../core/feed/feed.js';
8
8
  import type { PageFeedback, PageFeedbackComment } from '../../core/human/feedback.js';
9
9
  import type { OnDiskMigrationRunResult } from '../../migrations/runner.js';
10
- import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
10
+ import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodeOutcomeSummaryDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
11
11
  export declare function toMigrateStateDTO(result: OnDiskMigrationRunResult, options: {
12
12
  resumed: boolean;
13
13
  resumeError?: string;
14
14
  }): MigrateStateDTO;
15
- /** Project a latched outcome, or null while this node remains unsettled. */
15
+ /** Project the list-row outcome, or null while this node remains unsettled. */
16
+ export declare function toNodeOutcomeSummaryDTO(node: NodeRuntime): NodeOutcomeSummaryDTO | null;
17
+ /** Project the full outcome, or null while this node remains unsettled. */
16
18
  export declare function toNodeOutcomeDTO(node: Pick<NodeMeta, 'node_id' | 'final_report'> & NodeRuntime): NodeOutcomeDTO | null;
17
19
  /** The outcome-delivery fields exposed by the API. The delivery store supplies this projection directly. */
18
20
  export interface OutcomeDeliveryDTOInput {
@@ -1,2 +1,2 @@
1
- var h=Object.defineProperty;var o=(e,t)=>h(e,"name",{value:t,configurable:!0});import{existsSync as v,readFileSync as g}from"node:fs";import{join as b}from"node:path";import{outputResultPath as k}from"../../core/runtime/structured-output.js";import{ReviewOperationError as u}from"../../core/review/types.js";import{cronSinkDisplay as x}from"../../core/canvas/crons.js";import{isProfilePaused as l,sanitizeProfileMetadata as y}from"../../core/profiles/manifest.js";import{contextDir as O,nodeDir as D,nodeMetaPath as T,reportsDir as c,transcriptPath as R,viewSocketPath as S}from"../../core/canvas/paths.js";import{FinalizationError as A}from"../../core/feed/feed.js";import{NodeIdConflictError as E}from"../../core/runtime/nodes.js";import{readContextTokens as N}from"../../core/canvas/telemetry.js";import{CrtrError as s}from"../../core/errors.js";import{WorktreeError as z}from"../../core/worktree.js";import{ApiError as C}from"../../api/errors.js";import{ExitCode as d}from"../../types.js";function ae(e,t){const{discovery:i,snapshots:r}=e;return{profiles:e.profiles,stores:i.stores.length,changed:e.changed,applied:e.applied,skipped:e.skipped,blockers:e.blockers.map(n=>({kind:n.kind,message:n.message,...n.storeRoot===void 0?{}:{store:n.storeRoot},...n.targetId===void 0?{}:{target:n.targetId},...n.path===void 0?{}:{path:n.path},...n.name===void 0?{}:{name:n.name},...n.paths===void 0?{}:{paths:n.paths}})),discovery_roots:i.roots.map(n=>({reason:n.reason,root:n.root,boundary:n.boundary,...n.detail===void 0?{}:{detail:n.detail}})),discovered_stores:i.stores.map(n=>({store:n.key,scope:n.descriptor.scope,namespace:n.descriptor.namespace,mount_status:n.descriptor.mountStatus,writable:n.writable,reasons:[...new Set(n.discovery.map(a=>a.reason))],targets:n.targets,docs:r.get(n.key)?.docs.length??0})),discovered_targets:i.targets.map(n=>({id:n.id,kind:n.kind,origin:n.origin,cwd:n.target.cwd,profile_id:n.target.profileId,node_id:n.target.nodeId,stores:n.storeKeys})),repository_namespaces:e.repositories.map(n=>({repository_root:n.repositoryRoot,repository_key:n.repositoryKey,declaration_path:n.declarationPath,namespace:n.namespace,source:n.source,action:n.action})),store_prefixes:e.storePrefixes.map(n=>({store_root:n.storeRoot,owner_dir:n.ownerDir,repository_root:n.repositoryRoot,owner_relative_path:n.ownerRelativePath,old_prefix:n.oldPrefix,old_rule:n.oldRule,effective_prefix:n.effectivePrefix,nested_declaration_action:n.nestedDeclarationAction,front_door_action:n.frontDoorAction})),renames:e.renames.map(n=>({store_root:n.storeRoot,path:n.path,from:n.from,to:n.to})),references:e.references.map(n=>({store_root:n.storeRoot,path:n.path,kind:n.kind,from:n.from,to:n.to})),dryRun:e.dryRun,blocked:e.blocked,corpus_phase:e.corpusPhase,wrote:{profile_manifests:e.wrote.profileManifests,documents:e.wrote.documents,corpus_consumers:e.wrote.corpusConsumers,corpus_identities:e.wrote.corpusIdentities},resumed:t.resumed,...t.resumeError===void 0?{}:{resume_error:t.resumeError}}}o(ae,"toMigrateStateDTO");function P(e){const t=k(e);try{return v(t)?JSON.parse(g(t,"utf8")):null}catch{return null}}o(P,"readStructuredResult");function p(e){if(e.outcome_at===null||e.outcome_at===void 0||e.outcome_kind===null||e.outcome_kind===void 0||e.outcome_reason===null||e.outcome_reason===void 0)return null;let t=null;if(e.outcome_detail_json!==null&&e.outcome_detail_json!==void 0)try{t=JSON.parse(e.outcome_detail_json)}catch{t=null}const i=e.final_report??null,r={node_id:e.node_id,revision:e.outcome_revision??1,settled_at:e.outcome_at,final_report:i,final_report_path:i===null?null:`${c(e.node_id)}/${i}`,structured_result:e.outcome_kind==="result"?P(e.node_id):null,detail:t};return e.outcome_kind==="result"?{...r,kind:"result",reason:e.outcome_reason,declined:null}:e.outcome_reason==="declined"?{...r,kind:"failure",reason:"declined",declined:t?.declined??null}:{...r,kind:"failure",reason:e.outcome_reason,declined:null}}o(p,"toNodeOutcomeDTO");function se(e){const t=e.lastFailure;return{node_id:e.nodeId,state:e.state,action:e.actionName,attempt:e.attempt,next_attempt_at:e.nextAttemptAt===0?null:new Date(e.nextAttemptAt).toISOString(),accepted_at:e.acceptedAt===null?null:new Date(e.acceptedAt).toISOString(),permanent_failed_at:e.permanentFailedAt===null?null:new Date(e.permanentFailedAt).toISOString(),last_failure:t===null?null:{kind:t.kind,...t.exitCode===void 0?{}:{exit_code:t.exitCode},...t.signal===void 0?{}:{signal:t.signal},...t.message===void 0?{}:{message:t.message}},created_at:new Date(e.createdAt).toISOString(),updated_at:new Date(e.updatedAt).toISOString()}}o(se,"toOutcomeDeliveryDTO");function _e(e){return{node_id:e.node_id,name:e.name,description:e.description,cycles:e.cycles,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind,profile_id:e.profile_id,profile_paused:l(e.profile_id),parent:e.parent,created:e.created,intent:e.intent,waiting_for:e.waiting_for,frozen_at:e.frozen_at??null,terminal_reason:e.terminal_reason??null,pi_pid:e.pi_pid,pi_pid_identity:e.pi_pid_identity,window:e.window,tmux_session:e.tmux_session,pane:e.pane,final_report:e.final_report??null,finalized_at:e.finalized_at??null,deadline_at:e.deadline_at??null,outcome:p(e),fault:e.fault&&e.fault.link!=="broker\u2194crtrd"?{...e.fault,link:e.fault.link}:null,streaming:e.streaming??!1}}o(_e,"toNodeSummaryDTO");function j(e,t){return{parent:e.parent??null,spawned_by:e.spawned_by??null,subscribes_to:t.subscribesTo.map(i=>i.node_id),subscribers:t.subscribers.map(i=>i.node_id),children:[...t.children]}}o(j,"toNodeEdgesDTO");function I(e){return{node_dir:D(e),context_dir:O(e),reports_dir:c(e),meta_path:T(e),transcript_path:R(e),view_socket:S(e)}}o(I,"toNodePathsDTO");function q(e){const t={state:e.state,path:e.path,branch:e.branch,repo_root:e.repo_root,base_ref:e.base_ref,base_sha:e.base_sha,created:e.created};return e.cleanup!==void 0&&(t.cleanup=e.cleanup),e.closed!==void 0&&(t.closed=e.closed),e.abandoned!==void 0&&(t.abandoned={...e.abandoned}),t}o(q,"toNodeWorktreeDTO");function ue(e,t){const i={node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,profile_paused:l(e.profile_id),parent:e.parent??null,created:e.created,intent:e.intent??null,waiting_for:e.waiting_for??null,frozen_at:e.frozen_at??null,terminal_reason:e.terminal_reason??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,deadline_at:e.deadline_at??null,outcome:p(e),fault:e.fault&&e.fault.link!=="broker\u2194crtrd"?{...e.fault,link:e.fault.link}:null,streaming:e.streaming??!1,creator:e.creator??null,edges:j(e,t),paths:I(e.node_id)};return e.description!==void 0&&(i.description=e.description),e.title!==void 0&&(i.title=e.title),e.icon!==void 0&&(i.icon=e.icon),e.cycles!==void 0&&(i.cycles=e.cycles),i.context_tokens=N(e.node_id),e.pi_session_id!==void 0&&(i.pi_session_id=e.pi_session_id??null),i.model_override=e.model_override??null,e.pi_session_file!==void 0&&(i.pi_session_file=e.pi_session_file??null),e.review_binding!==void 0&&(i.review_binding=e.review_binding===null?null:{...e.review_binding.kind===void 0?{}:{kind:e.review_binding.kind},review_id:e.review_binding.review_id,origin_node_id:e.review_binding.origin_node_id,branch_file:e.review_binding.branch_file,target_file:e.review_binding.target_file}),e.managed_worktree!=null&&(i.worktree=q(e.managed_worktree)),i}o(ue,"toNodeDetailDTO");function le(e,t,i){return{node_id:e,revived:t.launch!==void 0,resumed:t.resumed,status:i,outcome:t.outcome}}o(le,"toReviveResultDTO");function ce(e){return{root:e.root,closed:[...e.closed],spared:[...e.spared]}}o(ce,"toCloseResultDTO");function pe(e,t,i){const r={report_path:e.reportPath,notified:[...e.deliveredTo]};return t!==void 0&&(r.transitioned=t),i!==void 0&&(r.worktree_auto_dropped=!0,r.worktree_auto_dropped_path=i),r}o(pe,"toReportResultDTO");function fe(e){return{node_id:e.node_id,active:e.active,created:e.created}}o(fe,"toSubscriptionDTO");function F(e){if(e===null||e==="")return[];try{const t=JSON.parse(e);return typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.keys(t):[]}catch{return[]}}o(F,"envKeys");function me(e,t){return{cron_id:e.cron_id,name:e.name,created_by:e.created_by,command:e.command,fire_at:e.fire_at,recur:e.recur,tz:e.tz,expires_at:e.expires_at,anchor_node:e.anchor_node,cancel_on_wake:e.cancel_on_wake,cwd:e.cwd,profile:e.profile,scope:e.scope,env_keys:F(e.env_json),run_timeout_s:e.run_timeout_s,overlap:e.overlap,on_output:e.on_output,sink:x(e.sink),tier:e.tier,state:e.state,held:e.held,run_state:e.run_state,last_run:t==null?null:{finished:t.finished,exit_code:t.exit_code,delivered:t.delivered},created:e.created,updated:e.updated}}o(me,"toCronDTO");function he(e){return{run_id:e.run_id,started:e.started,finished:e.finished,duration_ms:e.duration_ms,exit_code:e.exit_code,stdout_head:e.stdout_head,stderr_head:e.stderr_head,delivered:e.delivered}}o(he,"toCronRunDTO");function ve(e){return{id:e.profileId,name:e.manifest.name,projects:e.manifest.projects.map(t=>({...t})),home:e.manifest.home,paused_at:e.manifest.paused_at,default_kind:e.manifest.default_kind??"general",metadata:y(e.manifest.metadata),default_dir:null}}o(ve,"toProfileDTO");function f(e,t={}){const i={review_id:e.review_id,origin_kind:e.origin_kind,origin_node_id:e.origin_node_id,review_dir:e.review_dir,companion_node_id:e.companion_node_id,file:e.file,state:e.state,created:e.created,source_missing:e.source_missing,anchor_base_sha256:e.anchor_base_sha256};return e.opened_at!==null&&(i.opened_at=e.opened_at),e.submit_requested_at!==null&&(i.submit_requested_at=e.submit_requested_at),e.approved_at!==null&&(i.approved_at=e.approved_at),e.changed!==null&&(i.changed=e.changed),e.comments_total!==null&&(i.comments_total=e.comments_total),e.comments_unresolved!==null&&(i.comments_unresolved=e.comments_unresolved),e.canceled_at!==null&&(i.canceled_at=e.canceled_at),e.cancel_reason!==null&&(i.cancel_reason=e.cancel_reason),e.cancel_actor!==null&&(i.cancel_actor=e.cancel_actor),t.result_path!==void 0&&(i.result_path=t.result_path),e.delivery_error!==null&&(i.delivery_error=e.delivery_error),e.projection_error!==null&&(i.projection_error=e.projection_error),i}o(f,"toReviewDTO");function ge(e){return{comment_id:e.comment_id,review_id:e.review_id,status:e.status,revision:e.revision,text:e.text,anchor:{...e.anchor},anchor_state:e.anchor_state,anchor_line_text:e.anchor_line_text,anchor_doc_hash:e.anchor_doc_hash,author:{kind:e.author.kind,...e.author.node_id===null?{}:{node_id:e.author.node_id}},updated_by:{kind:e.updated_by.kind,...e.updated_by.node_id===null?{}:{node_id:e.updated_by.node_id}},created_at:e.created_at,updated_at:e.updated_at,...e.resolved_at===null?{}:{resolved_at:e.resolved_at},...e.deleted_at===null?{}:{deleted_at:e.deleted_at},created_seq:e.created_seq}}o(ge,"toReviewCommentDTO");function M(e){return{id:e.id,quote:e.quote,...e.context===void 0?{}:{context:e.context},note:e.note,status:e.status,created_at:e.createdAt,...e.resolvedAt===void 0?{}:{resolved_at:e.resolvedAt}}}o(M,"toPageFeedbackCommentDTO");function be(e){return{companion_node_id:e.companionNodeId??null,open_count:e.comments.filter(t=>t.status==="open").length,comments:e.comments.map(M)}}o(be,"toPageFeedbackDTO");function ke(e){return{seq:e.seq,review_id:e.review_id,comment_id:e.comment_id,kind:e.kind,state_change:e.state_change===1,revision_after:e.revision_after,actor:{kind:e.actor.kind,...e.actor.node_id===null?{}:{node_id:e.actor.node_id}},at:e.at,operation_id:e.operation_id,...e.payload===void 0?{}:{payload:e.payload}}}o(ke,"toReviewCommentEventDTO");function xe(e){return{file:e.file,submitted:e.submitted,approved:e.approved,comments:e.comments.map(i=>({...i})),submittedAt:e.submittedAt,savedAt:e.savedAt,reviewId:e.review_id,changed:e.changed,baselineSha256:e.baseline_sha256,approvedSha256:e.approved_sha256,companionNodeId:e.companion_node_id,commentsTotal:e.comments_total,commentsUnresolved:e.comments_unresolved}}o(xe,"toFeedbackResultDTO");const U=!0,G=Object.freeze({review_origin_missing:{status:400,code:"review_origin_unavailable"},review_origin_unforkable:{status:400,code:"review_origin_unavailable"},review_origin_unstable:{status:409,code:"review_origin_unstable"},review_branch_unavailable:{status:409,code:"review_branch_unavailable"},branch_lost:{status:409,code:"review_branch_unavailable"},review_companion_unbound:{status:409,code:"review_companion_unbound"},review_bridge_unsubscribed:{status:409,code:"review_bridge_unavailable"},review_target_unreviewable:{status:400,code:"review_file_unreadable"},source_unreadable:{status:409,code:"review_source_unreadable"},delivery_unroutable:{status:409,code:"review_delivery_unroutable"},unknown_review:{status:404,code:"unknown_review"},review_terminal:{status:409,code:"review_terminal_conflict"},review_required:{status:400,code:"review_required"},stale_document:{status:409,code:"stale_document"},unknown_comment:{status:404,code:"unknown_comment"},comment_deleted:{status:409,code:"comment_deleted"},invalid_anchor:{status:400,code:"invalid_anchor"},anchor_out_of_range:{status:400,code:"anchor_out_of_range"},text_too_long:{status:400,code:"text_too_long"},comment_limit_reached:{status:409,code:"comment_limit_reached"},stale_comment:{status:409,code:"stale_comment"},range_batch_incomplete:{status:409,code:"range_batch_incomplete"},range_batch_stale:{status:409,code:"range_batch_stale"}});function K(e){const t=m(e);if(typeof t=="object"&&t!==null&&typeof t.status=="number"&&typeof t.code=="string")return{status:t.status,code:t.code};if(t instanceof A)return t.code==="unknown_node"?{status:404,code:"node_not_found"}:t.code==="already_finalized"?{status:409,code:"already_finalized"}:{status:409,code:"finalization_forbidden"};if(t instanceof E)return{status:409,code:"node_id_exists"};if(t instanceof u)return G[t.code];if(t instanceof s)return{status:W(t.exitCode),code:t.code};if(t instanceof Error){const i=t.message;if(/unknown node/i.test(i))return{status:404,code:"node_not_found"};if(/finalization latch/i.test(i))return{status:409,code:"already_finalized"};if(/illegal lifecycle transition/i.test(i))return{status:409,code:"illegal_transition"}}return{status:500,code:"internal"}}o(K,"errorToStatus");function m(e){if(!(e instanceof z))return e;const t=e.code==="unknown_node"?d.NOT_FOUND:d.GENERAL,i={error:e.code,message:e.message,next:e.next};return e.detail!==void 0&&(i.received=e.detail),new s(e.code,e.message,t,i)}o(m,"normalizeThrow");function w(e){if(e.code!=="review_terminal")return e.detail;const{review:t,...i}=e.detail;return{...i,review:L(t)}}o(w,"reviewErrorDetails");function L(e){return e.state!=="approved"?f(e):f(e,{result_path:b(e.review_dir,"result.json")})}o(L,"terminalConflictReviewDTO");function W(e){switch(e){case d.NOT_FOUND:return 404;case d.USAGE:return 400;case d.AMBIGUOUS:return 400;case d.NETWORK:return 503;case d.GENERAL:return 400;default:return 500}}o(W,"statusForExitCode");function $(e){const i=(e instanceof Error?e.message:String(e)).split(`
2
- `,1)[0].trim();return i===""?"internal error":i.length>500?`${i.slice(0,497)}\u2026`:i}o($,"boundedCause");function ye(e){const t=m(e),{status:i,code:r}=K(t);if(i>=500)return{status:i,body:{error:{code:r,message:$(t)}}};const n=t instanceof Error?t.message:String(t),a=t instanceof u?w(t):(t instanceof s||t instanceof C)&&t.details!==void 0?t.details:void 0,_={error:{code:r,message:n}};return a!==void 0&&(_.error.details=a),{status:i,body:_}}o(ye,"toErrorBody");export{G as REVIEW_ERROR_MAP,K as errorToStatus,ce as toCloseResultDTO,me as toCronDTO,he as toCronRunDTO,ye as toErrorBody,xe as toFeedbackResultDTO,ae as toMigrateStateDTO,ue as toNodeDetailDTO,j as toNodeEdgesDTO,p as toNodeOutcomeDTO,I as toNodePathsDTO,_e as toNodeSummaryDTO,q as toNodeWorktreeDTO,se as toOutcomeDeliveryDTO,M as toPageFeedbackCommentDTO,be as toPageFeedbackDTO,ve as toProfileDTO,pe as toReportResultDTO,ge as toReviewCommentDTO,ke as toReviewCommentEventDTO,f as toReviewDTO,le as toReviveResultDTO,fe as toSubscriptionDTO};
1
+ var m=Object.defineProperty;var o=(e,t)=>m(e,"name",{value:t,configurable:!0});import{existsSync as h,readFileSync as v}from"node:fs";import{join as g}from"node:path";import{outputResultPath as b}from"../../core/runtime/structured-output.js";import{ReviewOperationError as u}from"../../core/review/types.js";import{cronSinkDisplay as k}from"../../core/canvas/crons.js";import{isProfilePaused as l,sanitizeProfileMetadata as x}from"../../core/profiles/manifest.js";import{contextDir as y,nodeDir as O,nodeMetaPath as D,reportsDir as c,transcriptPath as T,viewSocketPath as S}from"../../core/canvas/paths.js";import{FinalizationError as R}from"../../core/feed/feed.js";import{NodeIdConflictError as A}from"../../core/runtime/nodes.js";import{readContextTokens as E}from"../../core/canvas/telemetry.js";import{CrtrError as s}from"../../core/errors.js";import{WorktreeError as N}from"../../core/worktree.js";import{ApiError as z}from"../../api/errors.js";import{ExitCode as d}from"../../types.js";function se(e,t){const{discovery:i,snapshots:r}=e;return{profiles:e.profiles,stores:i.stores.length,changed:e.changed,applied:e.applied,skipped:e.skipped,blockers:e.blockers.map(n=>({kind:n.kind,message:n.message,...n.storeRoot===void 0?{}:{store:n.storeRoot},...n.targetId===void 0?{}:{target:n.targetId},...n.path===void 0?{}:{path:n.path},...n.name===void 0?{}:{name:n.name},...n.paths===void 0?{}:{paths:n.paths}})),discovery_roots:i.roots.map(n=>({reason:n.reason,root:n.root,boundary:n.boundary,...n.detail===void 0?{}:{detail:n.detail}})),discovered_stores:i.stores.map(n=>({store:n.key,scope:n.descriptor.scope,namespace:n.descriptor.namespace,mount_status:n.descriptor.mountStatus,writable:n.writable,reasons:[...new Set(n.discovery.map(a=>a.reason))],targets:n.targets,docs:r.get(n.key)?.docs.length??0})),discovered_targets:i.targets.map(n=>({id:n.id,kind:n.kind,origin:n.origin,cwd:n.target.cwd,profile_id:n.target.profileId,node_id:n.target.nodeId,stores:n.storeKeys})),repository_namespaces:e.repositories.map(n=>({repository_root:n.repositoryRoot,repository_key:n.repositoryKey,declaration_path:n.declarationPath,namespace:n.namespace,source:n.source,action:n.action})),store_prefixes:e.storePrefixes.map(n=>({store_root:n.storeRoot,owner_dir:n.ownerDir,repository_root:n.repositoryRoot,owner_relative_path:n.ownerRelativePath,old_prefix:n.oldPrefix,old_rule:n.oldRule,effective_prefix:n.effectivePrefix,nested_declaration_action:n.nestedDeclarationAction,front_door_action:n.frontDoorAction})),renames:e.renames.map(n=>({store_root:n.storeRoot,path:n.path,from:n.from,to:n.to})),references:e.references.map(n=>({store_root:n.storeRoot,path:n.path,kind:n.kind,from:n.from,to:n.to})),dryRun:e.dryRun,blocked:e.blocked,corpus_phase:e.corpusPhase,wrote:{profile_manifests:e.wrote.profileManifests,documents:e.wrote.documents,corpus_consumers:e.wrote.corpusConsumers,corpus_identities:e.wrote.corpusIdentities},resumed:t.resumed,...t.resumeError===void 0?{}:{resume_error:t.resumeError}}}o(se,"toMigrateStateDTO");function C(e){const t=b(e);try{return h(t)?JSON.parse(v(t,"utf8")):null}catch{return null}}o(C,"readStructuredResult");function P(e){return e.outcome_at===null||e.outcome_at===void 0||e.outcome_kind===null||e.outcome_kind===void 0||e.outcome_reason===null||e.outcome_reason===void 0?null:{kind:e.outcome_kind,reason:e.outcome_reason,settled_at:e.outcome_at}}o(P,"toNodeOutcomeSummaryDTO");function j(e){if(e.outcome_at===null||e.outcome_at===void 0||e.outcome_kind===null||e.outcome_kind===void 0||e.outcome_reason===null||e.outcome_reason===void 0)return null;let t=null;if(e.outcome_detail_json!==null&&e.outcome_detail_json!==void 0)try{t=JSON.parse(e.outcome_detail_json)}catch{t=null}const i=e.final_report??null,r={node_id:e.node_id,revision:e.outcome_revision??1,settled_at:e.outcome_at,final_report:i,final_report_path:i===null?null:`${c(e.node_id)}/${i}`,structured_result:e.outcome_kind==="result"?C(e.node_id):null,detail:t};return e.outcome_kind==="result"?{...r,kind:"result",reason:e.outcome_reason,declined:null}:e.outcome_reason==="declined"?{...r,kind:"failure",reason:"declined",declined:t?.declined??null}:{...r,kind:"failure",reason:e.outcome_reason,declined:null}}o(j,"toNodeOutcomeDTO");function _e(e){const t=e.lastFailure;return{node_id:e.nodeId,state:e.state,action:e.actionName,attempt:e.attempt,next_attempt_at:e.nextAttemptAt===0?null:new Date(e.nextAttemptAt).toISOString(),accepted_at:e.acceptedAt===null?null:new Date(e.acceptedAt).toISOString(),permanent_failed_at:e.permanentFailedAt===null?null:new Date(e.permanentFailedAt).toISOString(),last_failure:t===null?null:{kind:t.kind,...t.exitCode===void 0?{}:{exit_code:t.exitCode},...t.signal===void 0?{}:{signal:t.signal},...t.message===void 0?{}:{message:t.message}},created_at:new Date(e.createdAt).toISOString(),updated_at:new Date(e.updatedAt).toISOString()}}o(_e,"toOutcomeDeliveryDTO");function ue(e){return{node_id:e.node_id,name:e.name,description:e.description,cycles:e.cycles,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind,profile_id:e.profile_id,profile_paused:l(e.profile_id),parent:e.parent,created:e.created,intent:e.intent,waiting_for:e.waiting_for,frozen_at:e.frozen_at??null,terminal_reason:e.terminal_reason??null,pi_pid:e.pi_pid,pi_pid_identity:e.pi_pid_identity,window:e.window,tmux_session:e.tmux_session,pane:e.pane,final_report:e.final_report??null,finalized_at:e.finalized_at??null,deadline_at:e.deadline_at??null,outcome:P(e),fault:e.fault&&e.fault.link!=="broker\u2194crtrd"?{...e.fault,link:e.fault.link}:null,streaming:e.streaming??!1}}o(ue,"toNodeSummaryDTO");function I(e,t){return{parent:e.parent??null,spawned_by:e.spawned_by??null,subscribes_to:t.subscribesTo.map(i=>i.node_id),subscribers:t.subscribers.map(i=>i.node_id),children:[...t.children]}}o(I,"toNodeEdgesDTO");function q(e){return{node_dir:O(e),context_dir:y(e),reports_dir:c(e),meta_path:D(e),transcript_path:T(e),view_socket:S(e)}}o(q,"toNodePathsDTO");function F(e){const t={state:e.state,path:e.path,branch:e.branch,repo_root:e.repo_root,base_ref:e.base_ref,base_sha:e.base_sha,created:e.created};return e.cleanup!==void 0&&(t.cleanup=e.cleanup),e.closed!==void 0&&(t.closed=e.closed),e.abandoned!==void 0&&(t.abandoned={...e.abandoned}),t}o(F,"toNodeWorktreeDTO");function le(e,t){const i={node_id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,host_kind:e.host_kind??null,profile_id:e.profile_id??null,profile_paused:l(e.profile_id),parent:e.parent??null,created:e.created,intent:e.intent??null,waiting_for:e.waiting_for??null,frozen_at:e.frozen_at??null,terminal_reason:e.terminal_reason??null,pi_pid:e.pi_pid??null,pi_pid_identity:e.pi_pid_identity??null,window:e.window??null,tmux_session:e.tmux_session??null,pane:e.pane??null,final_report:e.final_report??null,finalized_at:e.finalized_at??null,deadline_at:e.deadline_at??null,outcome:j(e),fault:e.fault&&e.fault.link!=="broker\u2194crtrd"?{...e.fault,link:e.fault.link}:null,streaming:e.streaming??!1,creator:e.creator??null,edges:I(e,t),paths:q(e.node_id)};return e.description!==void 0&&(i.description=e.description),e.title!==void 0&&(i.title=e.title),e.icon!==void 0&&(i.icon=e.icon),e.cycles!==void 0&&(i.cycles=e.cycles),i.context_tokens=E(e.node_id),e.pi_session_id!==void 0&&(i.pi_session_id=e.pi_session_id??null),i.model_override=e.model_override??null,e.pi_session_file!==void 0&&(i.pi_session_file=e.pi_session_file??null),e.review_binding!==void 0&&(i.review_binding=e.review_binding===null?null:{...e.review_binding.kind===void 0?{}:{kind:e.review_binding.kind},review_id:e.review_binding.review_id,origin_node_id:e.review_binding.origin_node_id,branch_file:e.review_binding.branch_file,target_file:e.review_binding.target_file}),e.managed_worktree!=null&&(i.worktree=F(e.managed_worktree)),i}o(le,"toNodeDetailDTO");function ce(e,t,i){return{node_id:e,revived:t.launch!==void 0,resumed:t.resumed,status:i,outcome:t.outcome}}o(ce,"toReviveResultDTO");function pe(e){return{root:e.root,closed:[...e.closed],spared:[...e.spared]}}o(pe,"toCloseResultDTO");function fe(e,t,i){const r={report_path:e.reportPath,notified:[...e.deliveredTo]};return t!==void 0&&(r.transitioned=t),i!==void 0&&(r.worktree_auto_dropped=!0,r.worktree_auto_dropped_path=i),r}o(fe,"toReportResultDTO");function me(e){return{node_id:e.node_id,active:e.active,created:e.created}}o(me,"toSubscriptionDTO");function M(e){if(e===null||e==="")return[];try{const t=JSON.parse(e);return typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.keys(t):[]}catch{return[]}}o(M,"envKeys");function he(e,t){return{cron_id:e.cron_id,name:e.name,created_by:e.created_by,command:e.command,fire_at:e.fire_at,recur:e.recur,tz:e.tz,expires_at:e.expires_at,anchor_node:e.anchor_node,cancel_on_wake:e.cancel_on_wake,cwd:e.cwd,profile:e.profile,scope:e.scope,env_keys:M(e.env_json),run_timeout_s:e.run_timeout_s,overlap:e.overlap,on_output:e.on_output,sink:k(e.sink),tier:e.tier,state:e.state,held:e.held,run_state:e.run_state,last_run:t==null?null:{finished:t.finished,exit_code:t.exit_code,delivered:t.delivered},created:e.created,updated:e.updated}}o(he,"toCronDTO");function ve(e){return{run_id:e.run_id,started:e.started,finished:e.finished,duration_ms:e.duration_ms,exit_code:e.exit_code,stdout_head:e.stdout_head,stderr_head:e.stderr_head,delivered:e.delivered}}o(ve,"toCronRunDTO");function ge(e){return{id:e.profileId,name:e.manifest.name,projects:e.manifest.projects.map(t=>({...t})),home:e.manifest.home,paused_at:e.manifest.paused_at,default_kind:e.manifest.default_kind??"general",metadata:x(e.manifest.metadata),default_dir:null}}o(ge,"toProfileDTO");function p(e,t={}){const i={review_id:e.review_id,origin_kind:e.origin_kind,origin_node_id:e.origin_node_id,review_dir:e.review_dir,companion_node_id:e.companion_node_id,file:e.file,state:e.state,created:e.created,source_missing:e.source_missing,anchor_base_sha256:e.anchor_base_sha256};return e.opened_at!==null&&(i.opened_at=e.opened_at),e.submit_requested_at!==null&&(i.submit_requested_at=e.submit_requested_at),e.approved_at!==null&&(i.approved_at=e.approved_at),e.changed!==null&&(i.changed=e.changed),e.comments_total!==null&&(i.comments_total=e.comments_total),e.comments_unresolved!==null&&(i.comments_unresolved=e.comments_unresolved),e.canceled_at!==null&&(i.canceled_at=e.canceled_at),e.cancel_reason!==null&&(i.cancel_reason=e.cancel_reason),e.cancel_actor!==null&&(i.cancel_actor=e.cancel_actor),t.result_path!==void 0&&(i.result_path=t.result_path),e.delivery_error!==null&&(i.delivery_error=e.delivery_error),e.projection_error!==null&&(i.projection_error=e.projection_error),i}o(p,"toReviewDTO");function be(e){return{comment_id:e.comment_id,review_id:e.review_id,status:e.status,revision:e.revision,text:e.text,anchor:{...e.anchor},anchor_state:e.anchor_state,anchor_line_text:e.anchor_line_text,anchor_doc_hash:e.anchor_doc_hash,author:{kind:e.author.kind,...e.author.node_id===null?{}:{node_id:e.author.node_id}},updated_by:{kind:e.updated_by.kind,...e.updated_by.node_id===null?{}:{node_id:e.updated_by.node_id}},created_at:e.created_at,updated_at:e.updated_at,...e.resolved_at===null?{}:{resolved_at:e.resolved_at},...e.deleted_at===null?{}:{deleted_at:e.deleted_at},created_seq:e.created_seq}}o(be,"toReviewCommentDTO");function U(e){return{id:e.id,quote:e.quote,...e.context===void 0?{}:{context:e.context},note:e.note,status:e.status,created_at:e.createdAt,...e.resolvedAt===void 0?{}:{resolved_at:e.resolvedAt}}}o(U,"toPageFeedbackCommentDTO");function ke(e){return{companion_node_id:e.companionNodeId??null,open_count:e.comments.filter(t=>t.status==="open").length,comments:e.comments.map(U)}}o(ke,"toPageFeedbackDTO");function xe(e){return{seq:e.seq,review_id:e.review_id,comment_id:e.comment_id,kind:e.kind,state_change:e.state_change===1,revision_after:e.revision_after,actor:{kind:e.actor.kind,...e.actor.node_id===null?{}:{node_id:e.actor.node_id}},at:e.at,operation_id:e.operation_id,...e.payload===void 0?{}:{payload:e.payload}}}o(xe,"toReviewCommentEventDTO");function ye(e){return{file:e.file,submitted:e.submitted,approved:e.approved,comments:e.comments.map(i=>({...i})),submittedAt:e.submittedAt,savedAt:e.savedAt,reviewId:e.review_id,changed:e.changed,baselineSha256:e.baseline_sha256,approvedSha256:e.approved_sha256,companionNodeId:e.companion_node_id,commentsTotal:e.comments_total,commentsUnresolved:e.comments_unresolved}}o(ye,"toFeedbackResultDTO");const G=!0,K=Object.freeze({review_origin_missing:{status:400,code:"review_origin_unavailable"},review_origin_unforkable:{status:400,code:"review_origin_unavailable"},review_origin_unstable:{status:409,code:"review_origin_unstable"},review_branch_unavailable:{status:409,code:"review_branch_unavailable"},branch_lost:{status:409,code:"review_branch_unavailable"},review_companion_unbound:{status:409,code:"review_companion_unbound"},review_bridge_unsubscribed:{status:409,code:"review_bridge_unavailable"},review_target_unreviewable:{status:400,code:"review_file_unreadable"},source_unreadable:{status:409,code:"review_source_unreadable"},delivery_unroutable:{status:409,code:"review_delivery_unroutable"},unknown_review:{status:404,code:"unknown_review"},review_terminal:{status:409,code:"review_terminal_conflict"},review_required:{status:400,code:"review_required"},stale_document:{status:409,code:"stale_document"},unknown_comment:{status:404,code:"unknown_comment"},comment_deleted:{status:409,code:"comment_deleted"},invalid_anchor:{status:400,code:"invalid_anchor"},anchor_out_of_range:{status:400,code:"anchor_out_of_range"},text_too_long:{status:400,code:"text_too_long"},comment_limit_reached:{status:409,code:"comment_limit_reached"},stale_comment:{status:409,code:"stale_comment"},range_batch_incomplete:{status:409,code:"range_batch_incomplete"},range_batch_stale:{status:409,code:"range_batch_stale"}});function w(e){const t=f(e);if(typeof t=="object"&&t!==null&&typeof t.status=="number"&&typeof t.code=="string")return{status:t.status,code:t.code};if(t instanceof R)return t.code==="unknown_node"?{status:404,code:"node_not_found"}:t.code==="already_finalized"?{status:409,code:"already_finalized"}:{status:409,code:"finalization_forbidden"};if(t instanceof A)return{status:409,code:"node_id_exists"};if(t instanceof u)return K[t.code];if(t instanceof s)return{status:$(t.exitCode),code:t.code};if(t instanceof Error){const i=t.message;if(/unknown node/i.test(i))return{status:404,code:"node_not_found"};if(/finalization latch/i.test(i))return{status:409,code:"already_finalized"};if(/illegal lifecycle transition/i.test(i))return{status:409,code:"illegal_transition"}}return{status:500,code:"internal"}}o(w,"errorToStatus");function f(e){if(!(e instanceof N))return e;const t=e.code==="unknown_node"?d.NOT_FOUND:d.GENERAL,i={error:e.code,message:e.message,next:e.next};return e.detail!==void 0&&(i.received=e.detail),new s(e.code,e.message,t,i)}o(f,"normalizeThrow");function L(e){if(e.code!=="review_terminal")return e.detail;const{review:t,...i}=e.detail;return{...i,review:W(t)}}o(L,"reviewErrorDetails");function W(e){return e.state!=="approved"?p(e):p(e,{result_path:g(e.review_dir,"result.json")})}o(W,"terminalConflictReviewDTO");function $(e){switch(e){case d.NOT_FOUND:return 404;case d.USAGE:return 400;case d.AMBIGUOUS:return 400;case d.NETWORK:return 503;case d.GENERAL:return 400;default:return 500}}o($,"statusForExitCode");function B(e){const i=(e instanceof Error?e.message:String(e)).split(`
2
+ `,1)[0].trim();return i===""?"internal error":i.length>500?`${i.slice(0,497)}\u2026`:i}o(B,"boundedCause");function Oe(e){const t=f(e),{status:i,code:r}=w(t);if(i>=500)return{status:i,body:{error:{code:r,message:B(t)}}};const n=t instanceof Error?t.message:String(t),a=t instanceof u?L(t):(t instanceof s||t instanceof z)&&t.details!==void 0?t.details:void 0,_={error:{code:r,message:n}};return a!==void 0&&(_.error.details=a),{status:i,body:_}}o(Oe,"toErrorBody");export{K as REVIEW_ERROR_MAP,w as errorToStatus,pe as toCloseResultDTO,he as toCronDTO,ve as toCronRunDTO,Oe as toErrorBody,ye as toFeedbackResultDTO,se as toMigrateStateDTO,le as toNodeDetailDTO,I as toNodeEdgesDTO,j as toNodeOutcomeDTO,P as toNodeOutcomeSummaryDTO,q as toNodePathsDTO,ue as toNodeSummaryDTO,F as toNodeWorktreeDTO,_e as toOutcomeDeliveryDTO,U as toPageFeedbackCommentDTO,ke as toPageFeedbackDTO,ge as toProfileDTO,fe as toReportResultDTO,be as toReviewCommentDTO,xe as toReviewCommentEventDTO,p as toReviewDTO,ce as toReviveResultDTO,me as toSubscriptionDTO};
@@ -1,2 +1,4 @@
1
- /** Retire a companion only through the terminal transition legal for its current status. */
1
+ /** Retire a companion only through the terminal transition legal for its current status.
2
+ * A review companion may have forks working single comments beside it; they hold
3
+ * the same review binding and go terminal with the review that owns them. */
2
4
  export declare function retireCompanion(nodeId: string, outcome: 'approved' | 'canceled'): Promise<'retired' | 'already' | 'missing'>;
@@ -1 +1 @@
1
- var s=Object.defineProperty;var n=(t,e)=>s(t,"name",{value:e,configurable:!0});import{getNode as c}from"../core/canvas/canvas.js";import{FinalizationError as l,pushFinal as u}from"../core/feed/feed.js";import{transition as f}from"../core/runtime/lifecycle.js";import{requestBrokerTeardown as o}from"../core/runtime/host.js";async function v(t,e){const r=c(t);if(r===null)return"missing";if(r.status==="canceled"||e==="canceled"&&r.status==="done")return"already";if(e==="approved"&&(r.status==="active"||r.status==="idle"||r.status==="done")){let i="retired";try{await u(t,"The companion conversation is complete.")}catch(a){if(!(a instanceof l)||a.code!=="already_finalized")throw a;i="already"}return o(t),i}return f(t,"cancel",{reason:"retired"}),(r.status==="active"||r.status==="idle")&&o(t),"retired"}n(v,"retireCompanion");export{v as retireCompanion};
1
+ var d=Object.defineProperty;var o=(i,r)=>d(i,"name",{value:r,configurable:!0});import{childrenOf as f,getNode as s}from"../core/canvas/canvas.js";import{FinalizationError as l,pushFinal as u}from"../core/feed/feed.js";import{transition as p}from"../core/runtime/lifecycle.js";import{requestBrokerTeardown as c}from"../core/runtime/host.js";async function m(i,r){const e=s(i);if(e===null)return"missing";const a=e.review_binding?.review_id;if(a!==void 0)for(const t of f(i))s(t)?.review_binding?.review_id===a&&await m(t,r);if(e.status==="canceled"||r==="canceled"&&e.status==="done")return"already";if(r==="approved"&&(e.status==="active"||e.status==="idle"||e.status==="done")){let t="retired";try{await u(i,"The companion conversation is complete.")}catch(n){if(!(n instanceof l)||n.code!=="already_finalized")throw n;t="already"}return c(i),t}return p(i,"cancel",{reason:"retired"}),(e.status==="active"||e.status==="idle")&&c(i),"retired"}o(m,"retireCompanion");export{m as retireCompanion};
@@ -1,8 +1,8 @@
1
- var ie=Object.defineProperty;var o=(t,i)=>ie(t,"name",{value:i,configurable:!0});import{writeFileSync as oe,readFileSync as ae,rmSync as se,mkdirSync as ce}from"node:fs";import{dirname as de}from"node:path";import{randomBytes as le}from"node:crypto";import{crtrHome as me}from"../core/canvas/paths.js";import{listNodeMemoryTargets as B,listNodes as j}from"../core/canvas/index.js";import{createApiServer as pe}from"./api/server.js";import{reconcileUndeliveredTickets as fe}from"./human/sweep.js";import{resetHandedOffDeliveries as ue}from"../core/canvas/deliveries.js";import{sweepReviews as he}from"./review/sweep.js";import{pidfilePath as I}from"./pidfile.js";import{rendererWarning as ge}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as ve}from"./supervise-cadence.js";import{BrokerSupervisionReconciler as we}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as ye}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Se}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as ke}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as be}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as _e}from"./reconcilers/delivery-lane.js";import{migrateLegacyExecutionIdentities as Ee}from"../core/canvas/executions.js";import{PendingReviewSubmitReconciler as Pe}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as Re}from"./reconcilers/storage-maintenance.js";import{BashDeadlineReconciler as De}from"./reconcilers/bash-deadline.js";import{captureLivenessSnapshot as z,capturePidCommand as Ie,captureTeardownSnapshot as H,isPidAlive as Te,isAnyPidAlive as W,killProcessTreePids as K}from"../core/canvas/pid.js";import{bindFleet as Me,boundFleet as xe}from"../core/runtime/fleet.js";import{bindDaemonControl as Le,clearDaemonControl as Ae}from"./control.js";import{execDaemon as Ce,spawnDaemon as $e}from"./manage.js";import{reconcileAndMigrateBoot as Oe}from"../core/canvas/boot.js";import{resolveInstallId as Fe}from"../core/canvas/install-id.js";import{setInstallId as Ge}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ne,releaseDaemonOwnership as U}from"../core/canvas/daemon-owner.js";import{migrate as Be,openDb as je}from"../core/canvas/db.js";import{prewarmRecentRecipes as ze,reapStaleSpares as He}from"../core/runtime/warm-pool.js";import{DaemonFleet as We}from"./fleet.js";import{BOOT_MIGRATIONS as Ke}from"./boot-migrations.js";import{emitEvent as u}from"../core/events/emit.js";import{operationIdContext as g}from"../core/events/operation-id.js";import{bindDaemonEventSource as Ue}from"../core/events/source.js";import{activateOnDiskMigrations as Ve,MigrationBlockedError as qe,runForcedOnDiskMigrations as Qe}from"../migrations/activation.js";import{profilesRoot as Je,withProfileManifestLock as Xe}from"../core/profiles/manifest.js";import{runProfileManifestMigrations as Ye}from"../migrations/profile-manifests.js";import{convertLegacyProviderStore as Ze,convertLegacyScopedStore as er}from"../core/scoped-state/migrate.js";import{userScopeRoot as rr}from"../core/scope.js";import{piAgentDir as tr}from"../core/runtime/package-health.js";function T(t,i){return t.includes(` --canvas-home ${i} `)}o(T,"brokerCommandDeclaresCanvasHome");function M(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}o(M,"brokerCommandEpoch");const nr=5e3,V=150;async function ir(t){const i=z();if(i===null)throw u({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const s=me(),c=[];for(const[a,p]of i.processes){const d=p.command;if(p.zombie||!d.includes("broker-cli.js")||!T(d,s)||M(d)===t)continue;const S=d.trim().split(/\s+/).at(-1)??"";S===""||S.endsWith("broker-cli.js")||c.push({pid:a,nodeId:S})}let f=0;const n=[];for(const a of c){const p=Ie(a.pid);if(p===null||!p.includes("broker-cli.js")||!T(p,s)||M(p)===t||p.trim().split(/\s+/).at(-1)!==a.nodeId)continue;const d=H(a.pid,null);if(!d.reused){try{process.kill(a.pid,"SIGTERM")}catch{continue}f++,n.push({pid:a.pid,snap:d})}}const v=Date.now()+nr;for(;Date.now()<v&&n.some(a=>W(a.snap.tree.length>0?a.snap.tree:[a.pid]));)await new Promise(a=>setTimeout(a,V));let h=0;for(const a of n){const p=a.snap.tree.length>0?a.snap.tree:[a.pid];W(p)&&(K(p,"SIGKILL",a.snap.identities),h++)}h>0&&await new Promise(a=>setTimeout(a,V));const w=z();if(w===null)throw u({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const y=[];for(const[a,p]of w.processes){const d=p.command;p.zombie||!d.includes("broker-cli.js")||T(d,s)&&M(d)!==t&&y.push(a)}if(y.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${y.join(", ")}`);u({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:c.length,sigtermed:f,sigkilled:h}})}o(ir,"reapPriorEpochBrokers");const or=5e3;async function ar(t){const i=Array.from(t.entries());if(i.length===0)return;const s=i.map(([,n])=>({pid:n.pid,snap:H(n.pid,null),exited:n.handle.exited}));for(const n of s)if(!n.snap.reused)try{process.kill(n.pid,"SIGTERM")}catch{}const c=new Promise(n=>{setTimeout(n,or).unref()});await Promise.allSettled(s.map(n=>Promise.race([n.exited.then(()=>{}),c])));const f=[];for(const n of s)Te(n.pid)&&(K(n.snap.tree.length>0?n.snap.tree:[n.pid],"SIGKILL",n.snap.identities),f.push(n));await Promise.all(f.map(n=>n.exited)),u({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:s.length,sigkilled:f.length}})}o(ar,"teardownFleet");function sr(){ce(de(I()),{recursive:!0}),oe(I(),String(process.pid),"utf8")}o(sr,"writePidfile");function q(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}o(q,"isMissingPathError");function cr(t){const i=I();let s;try{s=ae(i,"utf8")}catch(c){if(q(c))return;throw c}if(s.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{se(i)}catch(c){if(q(c))return;throw c}}o(cr,"removeOwnedPidfileMirror");const dr={acceptsDetachedWork:o(()=>!0,"acceptsDetachedWork"),registerDetached:o(t=>{t.catch(()=>{})},"registerDetached")},x=new we,lr=new ye,mr=new Se,pr=new ke,fr=new be,ur=new _e,hr=new Pe,gr=new Re,vr=new De;async function wr(t=Date.now(),i=dr){const s=xe(),c=await x.runFleetPreamble(s);let f,n;try{f=j({status:["active","idle"]}).filter(h=>h.kind!=="human"),n=j({status:["done","canceled","dead"],withRecordedPidOrFrozen:!0}).filter(h=>h.kind!=="human")}catch(h){u({level:"error",event:"canvas.node_list.failed",error:h});return}await x.run(t,{rows:f,fleet:s,lifecycle:i}),lr.run(t,{rows:f});const v=await mr.run(t,{rows:[...f,...n],fleet:s});pr.run(t),fr.run(t,{lifecycle:i}),ur.run(t,{lifecycle:i}),hr.run(t,{lifecycle:i}),gr.run(t,{lifecycle:i,fleet:s}),await vr.run(t,{rows:f}),x.warnIfSaturated({fleet:s,lifecycle:i,thresholds:c,frozen:v})}o(wr,"superviseTick");async function yr(t={}){const i=Ne(le(16).toString("hex"));if(!i.claimed){if(i.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${i.incumbentPid??"?"})
2
- `);else{const e=[i.incumbentPid!==void 0?`pid ${i.incumbentPid}`:void 0,i.verdict!==void 0?`verdict ${i.verdict}`:void 0].filter(l=>l!==void 0),r=e.length>0?` (${e.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${i.reason}${r}
3
- `)}return async()=>{}}const s=i.claim;try{await ir(s.token),Ye(Je(),{dryRun:!1,withLock:Xe}),er({kind:"user",root:rr()}),await Ze(tr()),Be(je())}catch(e){try{const{released:r}=U(s);if(!r)throw new Error("daemon ownership claim was not released")}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}let c=!0,f,n=Promise.resolve(),v=!1,h,w;const y=new Set;let a=!1,p=!1,d,S,L=!1,m={phase:"initializing",message:"daemon startup is initializing its on-disk memory migration and normal services are unavailable",blockerPaths:[]},_="initial startup activation",Q=null;function J(){return m.phase==="ready"?null:{phase:m.phase,message:m.message,blockerPaths:m.blockerPaths}}o(J,"startupBlock");function A(e){y.add(e),e.finally(()=>{y.delete(e)}).catch(()=>{})}o(A,"registerDetached");const X={acceptsDetachedWork:o(()=>c,"acceptsDetachedWork"),registerDetached:A};async function Y(){try{c=!1,h!==void 0&&(clearInterval(h),h=void 0);let e;do e=n,await e;while(e!==n);for(;y.size>0;)await Promise.allSettled([...y]);if(w!==void 0&&(await ar(w),w.dispose()),S!==void 0&&!L&&(L=!0,await S.close()),a||(cr(process.pid),a=!0),a&&!p){const{released:r}=U(s);if(!r)throw new Error("daemon ownership claim was not released");p=!0}}finally{Ae(),process.off("SIGINT",O),process.off("SIGTERM",F),process.off("exit",G)}}o(Y,"cleanupAttempt");const P=1e3;let C=!1;function Z(){return C?{graceMs:P}:(C=!0,g.fresh(()=>{u({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:P}})}),setTimeout(()=>{ee()},P),{graceMs:P})}o(Z,"requestHandover");async function ee(){try{await k()}catch(e){const r=e instanceof Error?e.stack??e.message:String(e);process.stderr.write(`[crtrd] handover cleanup failed:
1
+ var ne=Object.defineProperty;var o=(t,i)=>ne(t,"name",{value:i,configurable:!0});import{writeFileSync as ie,readFileSync as oe,rmSync as ae,mkdirSync as se}from"node:fs";import{dirname as ce}from"node:path";import{randomBytes as le}from"node:crypto";import{crtrHome as de}from"../core/canvas/paths.js";import{listNodeMemoryTargets as B,listNodesForSupervision as me}from"../core/canvas/index.js";import{createApiServer as pe}from"./api/server.js";import{reconcileUndeliveredTickets as fe}from"./human/sweep.js";import{resetHandedOffDeliveries as ue}from"../core/canvas/deliveries.js";import{sweepReviews as he}from"./review/sweep.js";import{pidfilePath as R}from"./pidfile.js";import{rendererWarning as ge}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as ve}from"./supervise-cadence.js";import{BrokerSupervisionReconciler as we}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as ye}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Se}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as ke}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as be}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as _e}from"./reconcilers/delivery-lane.js";import{migrateLegacyExecutionIdentities as Ee}from"../core/canvas/executions.js";import{PendingReviewSubmitReconciler as Pe}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as De}from"./reconcilers/storage-maintenance.js";import{BashDeadlineReconciler as Ie}from"./reconcilers/bash-deadline.js";import{captureLivenessSnapshot as j,capturePidCommand as Re,captureTeardownSnapshot as z,isPidAlive as Te,isAnyPidAlive as H,killProcessTreePids as W}from"../core/canvas/pid.js";import{bindFleet as Me,boundFleet as xe}from"../core/runtime/fleet.js";import{bindDaemonControl as Le,clearDaemonControl as Ae}from"./control.js";import{execDaemon as Ce,spawnDaemon as $e}from"./manage.js";import{reconcileAndMigrateBoot as Oe}from"../core/canvas/boot.js";import{resolveInstallId as Fe}from"../core/canvas/install-id.js";import{setInstallId as Ge}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ne,releaseDaemonOwnership as K}from"../core/canvas/daemon-owner.js";import{migrate as Be,openDb as je}from"../core/canvas/db.js";import{prewarmRecentRecipes as ze,reapStaleSpares as He}from"../core/runtime/warm-pool.js";import{DaemonFleet as We}from"./fleet.js";import{BOOT_MIGRATIONS as Ke}from"./boot-migrations.js";import{emitEvent as u}from"../core/events/emit.js";import{operationIdContext as v}from"../core/events/operation-id.js";import{bindDaemonEventSource as Ue}from"../core/events/source.js";import{activateOnDiskMigrations as Ve,MigrationBlockedError as qe,runForcedOnDiskMigrations as Qe}from"../migrations/activation.js";import{profilesRoot as Je,withProfileManifestLock as Xe}from"../core/profiles/manifest.js";import{runProfileManifestMigrations as Ye}from"../migrations/profile-manifests.js";import{convertLegacyProviderStore as Ze,convertLegacyScopedStore as er}from"../core/scoped-state/migrate.js";import{userScopeRoot as rr}from"../core/scope.js";import{piAgentDir as tr}from"../core/runtime/package-health.js";function T(t,i){return t.includes(` --canvas-home ${i} `)}o(T,"brokerCommandDeclaresCanvasHome");function M(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}o(M,"brokerCommandEpoch");const nr=5e3,U=150;async function ir(t){const i=j();if(i===null)throw u({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const s=de(),c=[];for(const[a,p]of i.processes){const l=p.command;if(p.zombie||!l.includes("broker-cli.js")||!T(l,s)||M(l)===t)continue;const S=l.trim().split(/\s+/).at(-1)??"";S===""||S.endsWith("broker-cli.js")||c.push({pid:a,nodeId:S})}let f=0;const n=[];for(const a of c){const p=Re(a.pid);if(p===null||!p.includes("broker-cli.js")||!T(p,s)||M(p)===t||p.trim().split(/\s+/).at(-1)!==a.nodeId)continue;const l=z(a.pid,null);if(!l.reused){try{process.kill(a.pid,"SIGTERM")}catch{continue}f++,n.push({pid:a.pid,snap:l})}}const w=Date.now()+nr;for(;Date.now()<w&&n.some(a=>H(a.snap.tree.length>0?a.snap.tree:[a.pid]));)await new Promise(a=>setTimeout(a,U));let g=0;for(const a of n){const p=a.snap.tree.length>0?a.snap.tree:[a.pid];H(p)&&(W(p,"SIGKILL",a.snap.identities),g++)}g>0&&await new Promise(a=>setTimeout(a,U));const h=j();if(h===null)throw u({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const y=[];for(const[a,p]of h.processes){const l=p.command;p.zombie||!l.includes("broker-cli.js")||T(l,s)&&M(l)!==t&&y.push(a)}if(y.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${y.join(", ")}`);u({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:c.length,sigtermed:f,sigkilled:g}})}o(ir,"reapPriorEpochBrokers");const or=5e3;async function ar(t){const i=Array.from(t.entries());if(i.length===0)return;const s=i.map(([,n])=>({pid:n.pid,snap:z(n.pid,null),exited:n.handle.exited}));for(const n of s)if(!n.snap.reused)try{process.kill(n.pid,"SIGTERM")}catch{}const c=new Promise(n=>{setTimeout(n,or).unref()});await Promise.allSettled(s.map(n=>Promise.race([n.exited.then(()=>{}),c])));const f=[];for(const n of s)Te(n.pid)&&(W(n.snap.tree.length>0?n.snap.tree:[n.pid],"SIGKILL",n.snap.identities),f.push(n));await Promise.all(f.map(n=>n.exited)),u({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:s.length,sigkilled:f.length}})}o(ar,"teardownFleet");function sr(){se(ce(R()),{recursive:!0}),ie(R(),String(process.pid),"utf8")}o(sr,"writePidfile");function V(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}o(V,"isMissingPathError");function cr(t){const i=R();let s;try{s=oe(i,"utf8")}catch(c){if(V(c))return;throw c}if(s.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{ae(i)}catch(c){if(V(c))return;throw c}}o(cr,"removeOwnedPidfileMirror");const lr={acceptsDetachedWork:o(()=>!0,"acceptsDetachedWork"),registerDetached:o(t=>{t.catch(()=>{})},"registerDetached")},x=new we,dr=new ye,mr=new Se,pr=new ke,fr=new be,ur=new _e,hr=new Pe,gr=new De,vr=new Ie;async function wr(t=Date.now(),i=lr){const s=xe(),c=await x.runFleetPreamble(s);let f,n;try{const g=me();f=g.filter(h=>h.status==="active"||h.status==="idle"),n=g.filter(h=>h.status==="done"||h.status==="canceled"||h.status==="dead")}catch(g){u({level:"error",event:"canvas.node_list.failed",error:g});return}await x.run(t,{rows:f,fleet:s,lifecycle:i}),dr.run(t,{rows:f});const w=await mr.run(t,{rows:[...f,...n],fleet:s});pr.run(t),fr.run(t,{lifecycle:i}),ur.run(t,{lifecycle:i}),hr.run(t,{lifecycle:i}),gr.run(t,{lifecycle:i,fleet:s}),await vr.run(t,{rows:f}),x.warnIfSaturated({fleet:s,lifecycle:i,thresholds:c,frozen:w})}o(wr,"superviseTick");async function yr(t={}){const i=Ne(le(16).toString("hex"));if(!i.claimed){if(i.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${i.incumbentPid??"?"})
2
+ `);else{const e=[i.incumbentPid!==void 0?`pid ${i.incumbentPid}`:void 0,i.verdict!==void 0?`verdict ${i.verdict}`:void 0].filter(d=>d!==void 0),r=e.length>0?` (${e.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${i.reason}${r}
3
+ `)}return async()=>{}}const s=i.claim;try{await ir(s.token),Ye(Je(),{dryRun:!1,withLock:Xe}),er({kind:"user",root:rr()}),await Ze(tr()),Be(je())}catch(e){try{const{released:r}=K(s);if(!r)throw new Error("daemon ownership claim was not released")}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}let c=!0,f,n=Promise.resolve(),w=!1,g,h;const y=new Set;let a=!1,p=!1,l,S,L=!1,m={phase:"initializing",message:"daemon startup is initializing its on-disk memory migration and normal services are unavailable",blockerPaths:[]},_="initial startup activation",q=null;function Q(){return m.phase==="ready"?null:{phase:m.phase,message:m.message,blockerPaths:m.blockerPaths}}o(Q,"startupBlock");function A(e){y.add(e),e.finally(()=>{y.delete(e)}).catch(()=>{})}o(A,"registerDetached");const J={acceptsDetachedWork:o(()=>c,"acceptsDetachedWork"),registerDetached:A};async function X(){try{c=!1,g!==void 0&&(clearInterval(g),g=void 0);let e;do e=n,await e;while(e!==n);for(;y.size>0;)await Promise.allSettled([...y]);if(h!==void 0&&(await ar(h),h.dispose()),S!==void 0&&!L&&(L=!0,await S.close()),a||(cr(process.pid),a=!0),a&&!p){const{released:r}=K(s);if(!r)throw new Error("daemon ownership claim was not released");p=!0}}finally{Ae(),process.off("SIGINT",O),process.off("SIGTERM",F),process.off("exit",G)}}o(X,"cleanupAttempt");const P=1e3;let C=!1;function Y(){return C?{graceMs:P}:(C=!0,v.fresh(()=>{u({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:P}})}),setTimeout(()=>{Z()},P),{graceMs:P})}o(Y,"requestHandover");async function Z(){try{await k()}catch(e){const r=e instanceof Error?e.stack??e.message:String(e);process.stderr.write(`[crtrd] handover cleanup failed:
4
4
  ${r}
5
- `),process.exit(1)}try{process.pid===1&&await Ce();const e=await $e();g.fresh(()=>{u({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:e.pid??e.existing_pid??null,spawned:e.started}})})}catch(e){g.fresh(()=>{u({level:"error",event:"daemon.handover.successor_failed",error:e})});const r=e instanceof Error?e.message:String(e);process.stderr.write(`[crtrd] handover successor failed to start: ${r}
6
- `),process.exit(1)}process.exit(0)}o(ee,"performHandover");function k(){if(d!==void 0)return d;const e=Y();return d=e,e.then(()=>{d===e&&(d=void 0)},()=>{d===e&&(d=void 0)}),e}o(k,"requestCleanup");async function $(e){try{await k(),process.exit(0)}catch(r){process.exitCode=1;const l=r instanceof Error?r.stack??`${r.name}: ${r.message}`:String(r);process.stderr.write(`[crtrd] ${e} cleanup failed:
7
- ${l}
8
- `),process.exit(1)}}o($,"handleSignal");function O(){$("SIGINT")}o(O,"onSigint");function F(){$("SIGTERM")}o(F,"onSigterm");function G(){k().catch(()=>{})}o(G,"onExit");function R(e){c&&(n=n.then(e).then(()=>{},r=>{g.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:r})})}))}o(R,"enqueue");function N(){!c||v||(v=!0,R(async()=>{if(v=!1,!!c)try{await wr(Date.now(),X)}catch(e){g.fresh(()=>{u({level:"error",event:"daemon.tick.failed",error:e})})}}))}o(N,"enqueueTick");let E=null;async function re(){if(E!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${E instanceof Error?E.message:String(E)}`};if(m.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(m.phase!=="prepared"&&m.phase!=="recovering")throw{status:409,code:"not_prepared",message:m.message};const e=m.phase==="prepared";try{return await D(),m={phase:"ready",message:"",blockerPaths:[]},e?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(r){throw E=r,{status:500,code:"admission_failed",message:`daemon admission failed: ${r instanceof Error?r.message:String(r)}`}}}o(re,"admitStartup");async function te(e){if(_!==null)throw{status:409,code:"migration_in_progress",message:`on-disk migration is already running (${_})`};_="repair";try{const r=await Qe({dryRun:e.dryRun,explicitDirs:e.dirs,nodes:B()});if(e.dryRun||!r.finalVerificationSucceeded||m.phase!=="blocked")return{result:r,resumed:!1};if(t.prepare)return m={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:r,resumed:!1};try{return await D(),m={phase:"ready",message:"",blockerPaths:[]},{result:r,resumed:!0}}catch(l){const b=l instanceof Error?l.message:String(l);return setTimeout(()=>{k().catch(()=>{})},1e3),{result:r,resumed:!1,resumeError:b}}}finally{_=null}}o(te,"repairMigrations");async function ne(){f=t.intervalMs??ve;const e=s.token;w=new We({epoch:e,enqueue:R}),Me(w),m={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},g.fresh(()=>{u({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:f}})});const r=Fe();Ge(r),g.fresh(()=>{u({level:"info",event:"daemon.install_id.resolved",fields:{install_id:r}})}),g.fresh(()=>{let l;try{l=ge()}catch{return}l!==null&&u({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:l.slice(0,2048)}})}),await g.fresh(async()=>{await he(),await fe(),ue(Date.now())}),g.fresh(()=>{const{reconcile:l,migrated:b}=Oe(Ee);l.changed&&u({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:l.cleared.length,same_boot_proven:l.sameBootProven}}),b.length>0&&u({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:b.length}})}),g.fresh(()=>{for(const l of Ke){const b=l.apply();b.changed&&u({level:"info",event:"daemon.boot_migration.applied",fields:{migration:l.id,...b.summary}})}}),R(()=>{He(),ze()}),h=setInterval(N,f),N()}o(ne,"completeStartup");function D(){return Q??=ne().catch(e=>{throw m={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},e})}o(D,"resumeStartup");try{process.on("SIGINT",O),process.on("SIGTERM",F),process.on("exit",G),Ue();const e=s.token;Le({epoch:e,requestHandover:Z,registerDetached:A,startupBlock:J,admitStartup:re,repairMigrations:te}),sr(),S=pe({tcp:t.tcp}),await S.ready;try{await Ve({nodes:B()})}catch(r){if(_=null,r instanceof qe)return m={phase:"blocked",message:r.message,blockerPaths:r.blockerPaths},k;throw r}try{t.prepare?m={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await D(),m={phase:"ready",message:"",blockerPaths:[]})}finally{_=null}return k}catch(e){try{await k()}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}}o(yr,"runDaemon");var lt=yr;export{T as brokerCommandDeclaresCanvasHome,M as brokerCommandEpoch,lt as default,yr as runDaemon,wr as superviseTick};
5
+ `),process.exit(1)}try{process.pid===1&&await Ce();const e=await $e();v.fresh(()=>{u({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:e.pid??e.existing_pid??null,spawned:e.started}})})}catch(e){v.fresh(()=>{u({level:"error",event:"daemon.handover.successor_failed",error:e})});const r=e instanceof Error?e.message:String(e);process.stderr.write(`[crtrd] handover successor failed to start: ${r}
6
+ `),process.exit(1)}process.exit(0)}o(Z,"performHandover");function k(){if(l!==void 0)return l;const e=X();return l=e,e.then(()=>{l===e&&(l=void 0)},()=>{l===e&&(l=void 0)}),e}o(k,"requestCleanup");async function $(e){try{await k(),process.exit(0)}catch(r){process.exitCode=1;const d=r instanceof Error?r.stack??`${r.name}: ${r.message}`:String(r);process.stderr.write(`[crtrd] ${e} cleanup failed:
7
+ ${d}
8
+ `),process.exit(1)}}o($,"handleSignal");function O(){$("SIGINT")}o(O,"onSigint");function F(){$("SIGTERM")}o(F,"onSigterm");function G(){k().catch(()=>{})}o(G,"onExit");function D(e){c&&(n=n.then(e).then(()=>{},r=>{v.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:r})})}))}o(D,"enqueue");function N(){!c||w||(w=!0,D(async()=>{if(w=!1,!!c)try{await wr(Date.now(),J)}catch(e){v.fresh(()=>{u({level:"error",event:"daemon.tick.failed",error:e})})}}))}o(N,"enqueueTick");let E=null;async function ee(){if(E!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${E instanceof Error?E.message:String(E)}`};if(m.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(m.phase!=="prepared"&&m.phase!=="recovering")throw{status:409,code:"not_prepared",message:m.message};const e=m.phase==="prepared";try{return await I(),m={phase:"ready",message:"",blockerPaths:[]},e?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(r){throw E=r,{status:500,code:"admission_failed",message:`daemon admission failed: ${r instanceof Error?r.message:String(r)}`}}}o(ee,"admitStartup");async function re(e){if(_!==null)throw{status:409,code:"migration_in_progress",message:`on-disk migration is already running (${_})`};_="repair";try{const r=await Qe({dryRun:e.dryRun,explicitDirs:e.dirs,nodes:B()});if(e.dryRun||!r.finalVerificationSucceeded||m.phase!=="blocked")return{result:r,resumed:!1};if(t.prepare)return m={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:r,resumed:!1};try{return await I(),m={phase:"ready",message:"",blockerPaths:[]},{result:r,resumed:!0}}catch(d){const b=d instanceof Error?d.message:String(d);return setTimeout(()=>{k().catch(()=>{})},1e3),{result:r,resumed:!1,resumeError:b}}}finally{_=null}}o(re,"repairMigrations");async function te(){f=t.intervalMs??ve;const e=s.token;h=new We({epoch:e,enqueue:D}),Me(h),m={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},v.fresh(()=>{u({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:f}})});const r=Fe();Ge(r),v.fresh(()=>{u({level:"info",event:"daemon.install_id.resolved",fields:{install_id:r}})}),v.fresh(()=>{let d;try{d=ge()}catch{return}d!==null&&u({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:d.slice(0,2048)}})}),await v.fresh(async()=>{await he(),await fe(),ue(Date.now())}),v.fresh(()=>{const{reconcile:d,migrated:b}=Oe(Ee);d.changed&&u({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:d.cleared.length,same_boot_proven:d.sameBootProven}}),b.length>0&&u({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:b.length}})}),v.fresh(()=>{for(const d of Ke){const b=d.apply();b.changed&&u({level:"info",event:"daemon.boot_migration.applied",fields:{migration:d.id,...b.summary}})}}),D(()=>{He(),ze()}),g=setInterval(N,f),N()}o(te,"completeStartup");function I(){return q??=te().catch(e=>{throw m={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},e})}o(I,"resumeStartup");try{process.on("SIGINT",O),process.on("SIGTERM",F),process.on("exit",G),Ue();const e=s.token;Le({epoch:e,requestHandover:Y,registerDetached:A,startupBlock:Q,admitStartup:ee,repairMigrations:re}),sr(),S=pe({tcp:t.tcp}),await S.ready;try{await Ve({nodes:B()})}catch(r){if(_=null,r instanceof qe)return m={phase:"blocked",message:r.message,blockerPaths:r.blockerPaths},k;throw r}try{t.prepare?m={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await I(),m={phase:"ready",message:"",blockerPaths:[]})}finally{_=null}return k}catch(e){try{await k()}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}}o(yr,"runDaemon");var dt=yr;export{T as brokerCommandDeclaresCanvasHome,M as brokerCommandEpoch,dt as default,yr as runDaemon,wr as superviseTick};
@@ -10,7 +10,10 @@ export interface CancelTicketOptions {
10
10
  }
11
11
  /** Settle a page request directly in human_requests; result files and bridge nodes are not part of this path. */
12
12
  export declare function resolvePageTicket(ticketId: string, responses: unknown, opts?: CompletePageOptions): Promise<TicketResult>;
13
- export declare function cancelHumanTicket(ticketId: string, opts: CancelTicketOptions): Promise<TicketResult>;
13
+ export declare function cancelHumanTicket(ticketId: string, opts: CancelTicketOptions): Promise<{
14
+ outcome: 'settled' | 'already_settled';
15
+ result: TicketResult;
16
+ }>;
14
17
  /** Legacy callers use this as a replay hook. Settlement effects are repaired by sweepHumanRequests. */
15
18
  export declare function deliverTerminalResult(ticketId: string): Promise<boolean>;
16
19
  export declare function settleFeedbackCompanion(ticketId: string, outcome: 'approved' | 'canceled'): Promise<void>;
@@ -1,10 +1,10 @@
1
- var y=Object.defineProperty;var o=(t,n)=>y(t,"name",{value:n,configurable:!0});import{getRequest as q,getRequestByInboxTicket as b}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function d(t){const n=q(t)??b(t);if(n===null||n.kind!=="page")throw new Error(`unknown page request: ${t}`);return n}o(d,"requestForTicket");function c(t){try{const n=JSON.parse(t.specification_json);if(typeof n!="object"||n===null)throw new Error("not an object");return n}catch(n){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:n})}}o(c,"manifest");function u(t,n){if(t.action_json!==null)try{const e=JSON.parse(t.action_json);if(e.schema!=="crtr.human-action-binding/v1"||!Array.isArray(e.argv)||typeof e.cwd!="string")throw new Error("invalid binding");return{destinationId:e.name,adapter:{adapter:"subprocess",argv:e.argv,cwd:e.cwd},bodyJson:j({requestId:t.request_id,result:n,binding:e,source:c(t).source??{}})}}catch(e){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:e})}}o(u,"completionAction");function O(t,n=80){const e=t.split(`
2
- `)[0]??"";return e.length>n?`${e.slice(0,n-1)}\u2026`:e}o(O,"firstLine");function E(t){try{return c(t).title}catch{return}}o(E,"pageTitle");function w(t){let n;try{const e=T(t.request_dir);if(e.companionNodeId===void 0)return"";n=[],e.firstCommentedSha256!==void 0&&A(t.request_dir)!==e.firstCommentedSha256&&n.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${e.companionNodeId}) revised it in place. Reread the final page at ${N(t.request_dir)} before interpreting this outcome.`);const r=e.comments.filter(i=>i.status==="open");if(r.length>0){const i=r.map(s=>[...s.quote.split(`
3
- `).map(a=>`> ${a}`),s.note].join(`
4
- `));n.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${e.companionNodeId}) had not dealt with these items:`,...i].join(`
1
+ var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function d(t){const e=y(t)??b(t);if(e===null||e.kind!=="page")throw new Error(`unknown page request: ${t}`);return e}r(d,"requestForTicket");function c(t){try{const e=JSON.parse(t.specification_json);if(typeof e!="object"||e===null)throw new Error("not an object");return e}catch(e){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:e})}}r(c,"manifest");function u(t,e){if(t.action_json!==null)try{const n=JSON.parse(t.action_json);if(n.schema!=="crtr.human-action-binding/v1"||!Array.isArray(n.argv)||typeof n.cwd!="string")throw new Error("invalid binding");return{destinationId:n.name,adapter:{adapter:"subprocess",argv:n.argv,cwd:n.cwd},bodyJson:j({requestId:t.request_id,result:e,binding:n,source:c(t).source??{}})}}catch(n){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:n})}}r(u,"completionAction");function O(t,e=80){const n=t.split(`
2
+ `)[0]??"";return n.length>e?`${n.slice(0,e-1)}\u2026`:n}r(O,"firstLine");function E(t){try{return c(t).title}catch{return}}r(E,"pageTitle");function g(t){let e;try{const n=T(t.request_dir);if(n.companionNodeId===void 0)return"";e=[],n.firstCommentedSha256!==void 0&&A(t.request_dir)!==n.firstCommentedSha256&&e.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${n.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),c(t).dialect)} before interpreting this outcome.`);const o=n.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(a=>[...a.quote.split(`
3
+ `).map(s=>`> ${s}`),a.note].join(`
4
+ `));e.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${n.companionNodeId}) had not dealt with these items:`,...i].join(`
5
5
 
6
- `))}}catch{return""}return n.length===0?"":`
6
+ `))}}catch{return""}return e.length===0?"":`
7
7
 
8
- ${n.join(`
8
+ ${e.join(`
9
9
 
10
- `)}`}o(w,"feedbackAddendum");function g(t,n){const e=k(c(t),n.responses,{completedAt:n.completedAt});return S(e)+w(t)}o(g,"answerBody");function _(t,n,e){const r=E(t),i=r===void 0?`the human interaction ${t.request_id}`:`\u201C${r}\u201D`,s=e!==void 0&&e!==""?e:"no reason was given";return(n?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${r===void 0?`The human interaction ${t.request_id}`:`The page \u201C${r}\u201D`} was canceled \u2014 ${s}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+w(t)}o(_,"cancelBody");function l(t,n,e,r){if(t.requester_node_id!==null)return{label:O(e),disposition:n,body_json:{body:e,result:r}}}o(l,"notification");function m(t){return t.companion_node_id===null?void 0:{retire:o(async(n,e)=>{await f(n,e)},"retire")}}o(m,"retire");async function K(t,n,e={}){const r=d(t),i=c(r),s=$(i,n),a={schema:"crtr.page-response/v1",kind:"page",responses:s,summary:v(i,s),completedAt:e.completedAt??new Date().toISOString(),...e.actor===void 0?{}:{actor:e.actor}},p=await h({request_id:r.request_id,outcome:"answered",result_json:JSON.stringify(a),...l(r,"human-answer",g(r,a),a)===void 0?{}:{notification:l(r,"human-answer",g(r,a),a)},...u(r,a)===void 0?{}:{completion_action:u(r,a)},...m(r)===void 0?{}:{post_commit:m(r)}});if(p.outcome==="already_settled"){if(p.request.result_json===null)throw new Error(`settled page request lacks a result: ${r.request_id}`);return JSON.parse(p.request.result_json)}return a}o(K,"resolvePageTicket");async function L(t,n){const e=d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...n.reason===void 0?{}:{reason:n.reason},...n.actor===void 0?{}:{actor:n.actor},...n.disposition===void 0?{}:{disposition:n.disposition}},s=await h({request_id:e.request_id,outcome:n.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),...l(e,"human-canceled",_(e,n.disposition==="dismissed",n.reason),i)===void 0?{}:{notification:l(e,"human-canceled",_(e,n.disposition==="dismissed",n.reason),i)},...u(e,i)===void 0?{}:{completion_action:u(e,i)},...m(e)===void 0?{}:{post_commit:m(e)}});if(s.outcome==="already_settled"){if(s.request.result_json===null)throw new Error(`settled page request lacks a result: ${e.request_id}`);return JSON.parse(s.request.result_json)}return i}o(L,"cancelHumanTicket");async function M(t){return d(t).state==="settled"}o(M,"deliverTerminalResult");async function Q(t,n){const e=d(t);e.companion_node_id!==null&&await f(e.companion_node_id,n)}o(Q,"settleFeedbackCompanion");export{L as cancelHumanTicket,M as deliverTerminalResult,K as resolvePageTicket,Q as settleFeedbackCompanion};
10
+ `)}`}r(g,"feedbackAddendum");function I(t,e){const n=k(c(t),e.responses,{completedAt:e.completedAt});return S(n)+g(t)}r(I,"answerBody");function J(t,e,n){const o=E(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,a=n!==void 0&&n!==""?n:"no reason was given";return(e?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${a}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+g(t)}r(J,"cancelBody");function w(t,e,n,o){if(t.requester_node_id!==null)return{label:O(n),disposition:e,body_json:{body:n,result:o}}}r(w,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(e,n)=>{await f(e,n)},"retire")}}r(l,"retire");async function M(t,e,n={}){const o=d(t),i=c(o),a=$(i,e),s={schema:"crtr.page-response/v1",kind:"page",responses:a,summary:v(i,a),completedAt:n.completedAt??new Date().toISOString(),...n.actor===void 0?{}:{actor:n.actor}},m=await h({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(s),notification:r(p=>w(p,"human-answer",I(p,s),s),"notification"),...u(o,s)===void 0?{}:{completion_action:u(o,s)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return JSON.parse(m.request.result_json)}return s}r(M,"resolvePageTicket");async function Q(t,e){const n=d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...e.reason===void 0?{}:{reason:e.reason},...e.actor===void 0?{}:{actor:e.actor},...e.disposition===void 0?{}:{disposition:e.disposition}},a=await h({request_id:n.request_id,outcome:e.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(s=>w(s,"human-canceled",J(s,e.disposition==="dismissed",e.reason),i),"notification"),...u(n,i)===void 0?{}:{completion_action:u(n,i)},...l(n)===void 0?{}:{post_commit:l(n)}});if(a.outcome==="already_settled"){if(a.request.result_json===null)throw new Error(`settled page request lacks a result: ${n.request_id}`);return{outcome:"already_settled",result:JSON.parse(a.request.result_json)}}return{outcome:"settled",result:i}}r(Q,"cancelHumanTicket");async function U(t){return d(t).state==="settled"}r(U,"deliverTerminalResult");async function V(t,e){const n=d(t);n.companion_node_id!==null&&await f(n.companion_node_id,e)}r(V,"settleFeedbackCompanion");export{Q as cancelHumanTicket,U as deliverTerminalResult,M as resolvePageTicket,V as settleFeedbackCompanion};
@@ -1,16 +1,17 @@
1
1
  import { type ExternalActionAdapter } from '../../core/feed/messages.js';
2
2
  import { type HumanRequestOutcome, type HumanRequestRecord } from '../../core/human/requests.js';
3
+ interface SettlementNotification {
4
+ label: string;
5
+ disposition: string;
6
+ body_ref?: string;
7
+ body_json?: unknown;
8
+ }
3
9
  export interface SettleHumanRequestInput {
4
10
  request_id: string;
5
11
  outcome: HumanRequestOutcome;
6
12
  result_json: string;
7
13
  settled_at?: string;
8
- notification?: {
9
- label: string;
10
- disposition: string;
11
- body_ref?: string;
12
- body_json?: unknown;
13
- };
14
+ notification?: SettlementNotification | ((request: HumanRequestRecord) => SettlementNotification | undefined);
14
15
  completion_action?: {
15
16
  destinationId: string;
16
17
  adapter: ExternalActionAdapter;
@@ -38,3 +39,4 @@ export declare function projectAndRetire(request: HumanRequestRecord, effects: {
38
39
  project?: (request: HumanRequestRecord) => Promise<void> | void;
39
40
  retire?: (companionNodeId: string, outcome: 'approved' | 'canceled') => Promise<void>;
40
41
  }): Promise<void>;
42
+ export {};