@north-light/crouter 0.3.331 → 0.3.333

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 (128) hide show
  1. package/README.md +2 -2
  2. package/dist/api/command-manifest/manifest.js +1 -1
  3. package/dist/build-root.js +1 -1
  4. package/dist/builtin-memory/crouter-concepts/INDEX.md +13 -0
  5. package/dist/builtin-memory/crouter-concepts/README.md +19 -0
  6. package/dist/builtin-memory/crouter-concepts/lifecycle-and-wakes.md +28 -0
  7. package/dist/builtin-memory/crouter-concepts/memory.md +36 -0
  8. package/dist/builtin-memory/crouter-concepts/nodes-and-the-canvas.md +30 -0
  9. package/dist/builtin-memory/crouter-concepts/profiles-kinds-and-modes.md +33 -0
  10. package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +34 -0
  11. package/dist/builtin-memory/crouter-concepts/why-a-daemon.md +31 -0
  12. package/dist/builtin-memory/crouter-plugin/README.md +10 -13
  13. package/dist/builtin-memory/crouter-plugin/bundles-and-memory.md +2 -4
  14. package/dist/builtin-memory/crouter-plugin/commands.md +4 -7
  15. package/dist/builtin-memory/crouter-plugin/deploying.md +4 -7
  16. package/dist/builtin-memory/crouter-plugin/errors.md +2 -5
  17. package/dist/builtin-memory/crouter-plugin/getting-started.md +3 -6
  18. package/dist/builtin-memory/crouter-plugin/output.md +1 -3
  19. package/dist/builtin-memory/crouter-plugin/parameters.md +3 -4
  20. package/dist/builtin-memory/crouter-sdk/README.md +3 -4
  21. package/dist/builtin-memory/crouter-sdk/bash.md +2 -3
  22. package/dist/builtin-memory/crouter-sdk/client.md +3 -4
  23. package/dist/builtin-memory/crouter-sdk/docker.md +2 -4
  24. package/dist/builtin-memory/crouter-sdk/errors.md +9 -4
  25. package/dist/builtin-memory/crouter-sdk/files.md +2 -3
  26. package/dist/builtin-memory/crouter-sdk/getting-started.md +19 -6
  27. package/dist/builtin-memory/crouter-sdk/memory.md +3 -4
  28. package/dist/builtin-memory/crouter-sdk/migration.md +2 -6
  29. package/dist/builtin-memory/crouter-sdk/nodes.md +3 -3
  30. package/dist/builtin-memory/crouter-sdk/resources.md +2 -4
  31. package/dist/builtin-memory/crouter-sdk/streaming.md +3 -4
  32. package/dist/clients/attach/input/capabilities.js +1 -1
  33. package/dist/clients/attach/overlays/help.js +1 -1
  34. package/dist/clients/attach/slash/dispatch.js +1 -1
  35. package/dist/clients/attach/viewer.js +762 -765
  36. package/dist/commands/sys/branch.js +1 -1
  37. package/dist/commands/sys/connect.js +3 -3
  38. package/dist/commands/sys/setup-core.d.ts +1 -1
  39. package/dist/commands/sys/setup-core.js +4 -4
  40. package/dist/commands/sys/tutorial/branch.d.ts +1 -0
  41. package/dist/commands/sys/tutorial/branch.js +1 -0
  42. package/dist/commands/sys/tutorial/lessons.d.ts +6 -0
  43. package/dist/commands/sys/tutorial/lessons.js +12 -0
  44. package/dist/commands/sys/tutorial/scenario.d.ts +1 -0
  45. package/dist/commands/sys/tutorial/scenario.js +2 -0
  46. package/dist/commands/sys/tutorial/tracks.d.ts +2 -0
  47. package/dist/commands/sys/tutorial/tracks.js +4 -0
  48. package/dist/commands/sys.js +1 -1
  49. package/dist/core/runtime/boot-root.d.ts +7 -0
  50. package/dist/core/runtime/boot-root.js +4 -4
  51. package/dist/core/runtime/first-run-offer.d.ts +11 -0
  52. package/dist/core/runtime/first-run-offer.js +5 -0
  53. package/dist/core/runtime/front-door.js +3 -3
  54. package/dist/core/runtime/spawn.d.ts +3 -1
  55. package/dist/core/runtime/spawn.js +2 -2
  56. package/dist/core/scopes.d.ts +4 -2
  57. package/dist/core/scopes.js +1 -1
  58. package/dist/core/secrets.d.ts +11 -0
  59. package/dist/core/secrets.js +2 -2
  60. package/dist/daemon/api/bridge.d.ts +4 -0
  61. package/dist/daemon/api/bridge.js +2 -2
  62. package/dist/daemon/api/handlers/attach.d.ts +1 -1
  63. package/dist/daemon/api/handlers/attach.js +1 -1
  64. package/dist/daemon/api/handlers/bash.js +1 -1
  65. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  66. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  67. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  68. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  69. package/dist/daemon/api/handlers/canvas.js +4 -4
  70. package/dist/daemon/api/handlers/crons.d.ts +1 -1
  71. package/dist/daemon/api/handlers/crons.js +1 -1
  72. package/dist/daemon/api/handlers/daemon.d.ts +1 -1
  73. package/dist/daemon/api/handlers/daemon.js +1 -1
  74. package/dist/daemon/api/handlers/files.js +1 -1
  75. package/dist/daemon/api/handlers/focus.d.ts +1 -1
  76. package/dist/daemon/api/handlers/focus.js +1 -1
  77. package/dist/daemon/api/handlers/human-requests.js +1 -1
  78. package/dist/daemon/api/handlers/memory.js +1 -1
  79. package/dist/daemon/api/handlers/messages.d.ts +1 -1
  80. package/dist/daemon/api/handlers/messages.js +2 -2
  81. package/dist/daemon/api/handlers/model-config.d.ts +1 -1
  82. package/dist/daemon/api/handlers/model-config.js +1 -1
  83. package/dist/daemon/api/handlers/modelauth.js +1 -1
  84. package/dist/daemon/api/handlers/nodes.js +1 -1
  85. package/dist/daemon/api/handlers/profiles.js +1 -1
  86. package/dist/daemon/api/handlers/reports.js +1 -1
  87. package/dist/daemon/api/handlers/reviews.js +1 -1
  88. package/dist/daemon/api/handlers/worktree.d.ts +1 -1
  89. package/dist/daemon/api/handlers/worktree.js +1 -1
  90. package/dist/daemon/api/router.d.ts +20 -1
  91. package/dist/daemon/api/router.js +1 -1
  92. package/dist/daemon/api/server.js +1 -11
  93. package/dist/types.js +1 -1
  94. package/docs/cli/README.md +16 -0
  95. package/docs/cli/canvas-and-dashboard.md +56 -0
  96. package/docs/cli/first-session.md +55 -0
  97. package/docs/cli/human-inbox.md +34 -0
  98. package/docs/cli/memory-and-preferences.md +50 -0
  99. package/docs/cli/the-viewer.md +79 -0
  100. package/docs/concepts/README.md +17 -0
  101. package/docs/concepts/lifecycle-and-wakes.md +26 -0
  102. package/docs/concepts/memory.md +34 -0
  103. package/docs/concepts/nodes-and-the-canvas.md +28 -0
  104. package/docs/concepts/profiles-kinds-and-modes.md +31 -0
  105. package/docs/concepts/scopes-and-trust.md +32 -0
  106. package/docs/concepts/why-a-daemon.md +29 -0
  107. package/docs/plugin/README.md +5 -0
  108. package/docs/plugin/bundles-and-memory.md +5 -0
  109. package/docs/plugin/commands.md +5 -0
  110. package/docs/plugin/deploying.md +5 -0
  111. package/docs/plugin/errors.md +5 -0
  112. package/docs/plugin/getting-started.md +5 -0
  113. package/docs/plugin/output.md +5 -0
  114. package/docs/plugin/parameters.md +5 -0
  115. package/docs/sdk/README.md +5 -0
  116. package/docs/sdk/bash.md +5 -0
  117. package/docs/sdk/client.md +6 -1
  118. package/docs/sdk/docker.md +5 -0
  119. package/docs/sdk/errors.md +12 -0
  120. package/docs/sdk/files.md +5 -0
  121. package/docs/sdk/getting-started.md +21 -1
  122. package/docs/sdk/memory.md +5 -0
  123. package/docs/sdk/migration.md +5 -0
  124. package/docs/sdk/nodes.md +6 -1
  125. package/docs/sdk/resources.md +5 -0
  126. package/docs/sdk/streaming.md +5 -0
  127. package/package.json +10 -9
  128. package/runtime.lock.json +6734 -670
@@ -1,2 +1,2 @@
1
- var E=Object.defineProperty;var c=(r,e)=>E(r,"name",{value:e,configurable:!0});import{join as J}from"node:path";import{claimNodeMail as W,acknowledgeNodeMail as D}from"../../../core/canvas/deliveries.js";import{nodeMailEntry as L}from"../../../core/feed/inbox.js";import{enqueueNodeMail as q,cancelPendingNodeMail as G}from"../../../core/feed/messages.js";import{reviveNode as F}from"../../../core/runtime/revive.js";import{BrokerUnreachableError as I}from"../../../core/runtime/broker-request.js";import{isBrokerLive as C}from"../../../core/runtime/model-swap.js";import{deliverLive as U,interruptLive as H}from"../../../core/runtime/interactive-deliver.js";import{isProfilePaused as K}from"../../../core/profiles/manifest.js";import{getNode as x,withFreshTerminalGuard as Q}from"../../../core/canvas/canvas.js";import{reportsDir as V}from"../../../core/canvas/paths.js";import{withCanvasWrite as X}from"../../../core/canvas/db.js";import{cancelCronsOnWake as O}from"../../../core/canvas/crons.js";import{assertNotFinalized as N,assertFinalizedForReopen as Y,commitReopenResident as A}from"../../../core/runtime/reopen.js";import{writeOutputSchema as Z}from"../../../core/runtime/structured-output.js";import{appendSituationalContext as j,formatSituationalProse as ee}from"../../../core/runtime/situational-context.js";import{formatDataCard as P}from"../../../shared/generated-context.js";import{hasNoNaturalCycle as te}from"../../../core/runtime/revive-all.js";import{recordPendingParkActivity as re}from"../../park-pending.js";import{wantsExecution as ne}from"../../reconcilers/node-lifecycle/wants-execution.js";import{hasFreshGroundState as oe}from"../../../core/runtime/revive.js";import{notFound as S,usage as a}from"../../../core/errors.js";import{assertScope as ie}from"../../../core/scopes.js";import{InputError as ae}from"../../../core/io.js";import{ApiError as se}from"../../../api/index.js";const de=["critical","urgent","normal","deferred"];function M(r,e){if(typeof r!="object"||r===null||Array.isArray(r))throw a(`${e} must be an object { kind, facts?, body? }`);const i=r,t=i.kind;if(typeof t!="string"||t.trim()==="")throw a(`${e}.kind is required`);if(!t.includes(":"))throw a(`${e}.kind must be namespaced (contain ':'): ${t}`);const s={kind:t},n=i.facts;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n))throw a(`${e}.facts must be an object of string or number values`);const y={};for(const[m,f]of Object.entries(n)){if(typeof f!="string"&&typeof f!="number")throw a(`${e}.facts.${m} must be a string or number`);y[m]=f}s.facts=y}const o=i.body;if(o!==void 0){if(typeof o!="string")throw a(`${e}.body must be a string`);s.body=o}return s}c(M,"parseCardRequest");function T(r,e){try{return P(r.kind,r.facts??{},r.body??"")}catch(i){throw a(`${e}: ${i instanceof Error?i.message:String(i)}`)}}c(T,"renderCard");function ce(r){if(typeof r!="object"||r===null)throw a("a message requires a JSON body { body, tier?, fresh? }");const e=r,i=e.body,t=e.fresh===!0,s=e.tier,n=e.situational_context,o=e.output_schema,y=typeof i=="string"&&i.trim()!=="",m=typeof n=="string"&&n.trim()!=="",f=typeof o=="string"&&o.trim()!=="",g=e.situational_card,h=e.context_cards,b=g===void 0?void 0:M(g,"situational_card");if(h!==void 0&&!Array.isArray(h))throw a("context_cards must be an array of { kind, facts?, body? }");const l=h?.map((v,k)=>M(v,`context_cards[${k}]`));if(b!==void 0&&typeof n=="string"&&n!=="")throw a("situational_card and situational_context are mutually exclusive");const _=b!==void 0||l!==void 0&&l.length>0;if(!t&&!y&&!m&&!f&&!_)throw a("a message requires a non-empty body (or fresh: true, situational_context, a runtime card, or output_schema)");if(t&&l!==void 0&&l.length>0)throw a("context_cards cannot ride a fresh revive (no inbox entry carries them)");if(s!==void 0&&!de.includes(s))throw a(`invalid tier: ${String(s)} (expected critical|urgent|normal|deferred)`);const u={body:typeof i=="string"?i:""};s!==void 0&&(u.tier=s),t&&(u.fresh=!0),e.reopen===!0&&(u.reopen=!0),typeof n=="string"&&(u.situational_context=n),b!==void 0&&(u.situational_card=b),l!==void 0&&(u.context_cards=l),typeof o=="string"&&(u.output_schema=o),typeof e.from=="string"&&(u.from=e.from);const p=e.delivery;if(p!==void 0&&p!=="interactive")throw a(`invalid delivery: ${String(p)} (expected interactive)`);if(p==="interactive"){if(t||u.situational_context!==void 0||u.output_schema!==void 0)throw a("interactive delivery supports a body, runtime cards, and reopen only (no fresh, situational_context, or output_schema)");if(!y)throw a("interactive delivery requires a non-empty body");if(u.tier==="deferred")throw a("interactive delivery cannot be deferred");u.delivery="interactive"}return u}c(ce,"parseSendBody");function ue(r){try{return JSON.parse(r)}catch{throw a("output_schema must be a JSON schema string")}}c(ue,"parseSchema");function fe(r){return r.split(`
2
- `)[0].slice(0,120)}c(fe,"label");function z(r,e){if(e===null)return"";const i=J(V(r),e);return P("reopen-final-report",{path:i},"This node previously completed work. Read this final report before acting on the new instruction.")}c(z,"previousFinalReportCard");function le(r,e){return new ae({error:"deferred_no_natural_cycle",message:`${r} is ${e} with no natural next cycle ahead of it \u2014 a deferred message would never be delivered.`,next:"Use --tier normal, urgent, or critical to wake it now, or --reopen (with a body or --fresh) to re-task it first."})}c(le,"deferredNoNaturalCycle");function me(r){if(!oe(r))throw new se(422,"unprocessable",`node ${r} has no goal/roadmap on disk \u2014 a fresh revive would resume amnesiac.`)}c(me,"assertRecoverableForFresh");async function pe(r){const e=r.params.id,i=x(e);if(i===null)throw S(`unknown node: ${e}`,{received:e});const t=ce(r.body),s=t.tier??"normal",n=K(i.profile_id),o=t.from??null;if(o!==null){const d=x(o);d!==null&&ie(d,"act")}const y=t.body.trim()!=="",m=t.situational_card!==void 0?T(t.situational_card,"situational_card"):t.situational_context!==void 0?ee(t.situational_context.trim()):"",f=m!=="",g=(t.context_cards??[]).map((d,w)=>T(d,`context_cards[${w}]`)),h=t.output_schema!==void 0&&t.output_schema.trim()!==""?ue(t.output_schema):null;if(t.fresh){const d=t.reopen?Y(e):null;t.reopen||N(e),me(e),f&&j(e,m),t.reopen&&A(e,d);const w=await F(e,{resume:!1,capacity:"refuse"});return{status:201,body:{node_id:e,delivered:!1,revived:w.launch!==void 0}}}t.delivery==="interactive"&&!t.reopen&&N(e);let b=!1,l="";if(t.delivery==="interactive"&&t.reopen&&(l=z(e,A(e)),b=!0),t.delivery==="interactive"&&!n&&C(i))try{return f&&j(e,m),await U(e,t.body,{cards:[...l===""?[]:[l],...f?[m]:[],...g],origin:o==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...o===null?{}:{from:o},kind:"message",tier:s}]}}),O(e),{status:201,body:{node_id:e,delivered:!0,revived:!1,delivered_via:"engine"}}}catch(d){if(!(d instanceof I))throw d}const _=c(()=>{t.reopen||N(e),h!==null&&Z(e,"oneoff",h),f&&j(e,m),t.reopen&&!b&&(l=z(e,A(e)));const d=[...l===""?[]:[l],...g],w=d.length>0?{cards:d}:{};if(y||h!==null){const $=y?t.body:"A one-off structured-output request has been granted. Submit a result matching the requested schema with `crtr push result` before you stop; after it is accepted, continue normally.";return q(e,{senderNodeId:o,urgency:s,wake:1,kind:"message",label:fe($),bodyJson:{body:$,...f?{situational:!0}:{},...w}})}return q(e,{senderNodeId:o,urgency:s,wake:1,kind:"message",label:f?"(ambient context updated)":"(context delivered)",bodyJson:{...f?{situational:!0}:{},situationalOnly:!0,...w}})},"deliverImmediate"),p=c(()=>{if(s==="deferred"){const d=Q(e,te,_);if(d.kind==="missing")throw S(`unknown node: ${e}`,{received:e});if(d.kind==="terminal")throw le(e,d.status);return d.result}return _()},"deliver")();p.urgency!=="deferred"&&X(()=>re(e));const v=x(e);if(v===null)throw S(`unknown node: ${e}`,{received:e});i.frozen_at!==null&&O(e);let k=!1,R=!1;if((t.reopen||v.lifecycle==="terminal"||!ne(v))&&p.urgency!=="deferred"&&!n&&!C(v))try{const d=await F(e,{resume:!0,capacity:"freeze"});k=d.launch!==void 0,R=d.outcome==="frozen"}catch{}return{status:201,body:{node_id:e,delivered:!0,revived:k,...R?{not_revived_reason:"capacity_frozen"}:{},delivered_at:p.createdAt,...p.urgency===s?{}:{delivered_tier:p.urgency},...t.delivery==="interactive"?{delivered_via:"inbox"}:{}}}}c(pe,"handleMessage");async function ye(r){const e=r.params.id,i=x(e);if(i===null)throw S(`unknown node: ${e}`,{received:e});const t=G(e,{senderNodeId:"human",kind:"message"});let s=!1;if(C(i))try{s=await H(e)!=="idle"}catch(o){if(!(o instanceof I))throw o}return{status:200,body:{node_id:e,outcome:s?"aborted_turn":t.length>0?"canceled_pending":"idle",aborted_turn:s,canceled_pending:t.length}}}c(ye,"handleInterrupt");function B(r){if(typeof r.body!="object"||r.body===null||Array.isArray(r.body))throw a("mail requires an object body");const e=r.body;if(typeof e.execution_id!="string"||e.execution_id.trim()==="")throw a("execution_id is required");return e}c(B,"mailBody");function he(r){const e=B(r),i=e.channel;if(i!=="wake"&&i!=="passive")throw a("channel must be wake or passive");const t=W(r.params.id,e.execution_id,i);return{status:200,body:{action:t.action,deliveries:t.deliveries.map(n=>({delivery_id:n.deliveryId,attempts:n.attempts,handoff:n.handoff,entry:L(n)}))}}}c(he,"handleMailClaim");function be(r){const e=B(r);if(!Array.isArray(e.deliveries))throw a("deliveries must be an array");const i=e.deliveries.map(n=>{if(typeof n!="object"||n===null||Array.isArray(n))throw a("each delivery must be an object");const o=n;if(typeof o.delivery_id!="string"||o.delivery_id==="")throw a("delivery_id is required");if(!Number.isSafeInteger(o.attempts)||o.attempts<1)throw a("attempts must be a positive integer");if(o.disposition!=="acknowledged"&&o.disposition!=="released")throw a("disposition must be acknowledged or released");return{delivery_id:o.delivery_id,attempts:o.attempts,disposition:o.disposition}}),t=D(r.params.id,e.execution_id,i.map(n=>({deliveryId:n.delivery_id,attempts:n.attempts,disposition:n.disposition})));return{status:200,body:{action:t.action,results:t.results.map(n=>({delivery_id:n.deliveryId,outcome:n.outcome}))}}}c(be,"handleMailAcknowledge");const Ue=[{method:"POST",pattern:"/v1/nodes/:id/mail/claim",handler:he},{method:"POST",pattern:"/v1/nodes/:id/mail/acknowledge",handler:be}],He=[{method:"POST",pattern:"/v1/nodes/:id/messages",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/interrupt",handler:ye}];export{Ue as brokerMailRoutes,He as messageRoutes};
1
+ var E=Object.defineProperty;var c=(r,e)=>E(r,"name",{value:e,configurable:!0});import{join as J}from"node:path";import{claimNodeMail as W,acknowledgeNodeMail as D}from"../../../core/canvas/deliveries.js";import{nodeMailEntry as L}from"../../../core/feed/inbox.js";import{enqueueNodeMail as q,cancelPendingNodeMail as G}from"../../../core/feed/messages.js";import{reviveNode as O}from"../../../core/runtime/revive.js";import{BrokerUnreachableError as F}from"../../../core/runtime/broker-request.js";import{isBrokerLive as C}from"../../../core/runtime/model-swap.js";import{deliverLive as U,interruptLive as H}from"../../../core/runtime/interactive-deliver.js";import{isProfilePaused as K}from"../../../core/profiles/manifest.js";import{getNode as x,withFreshTerminalGuard as Q}from"../../../core/canvas/canvas.js";import{reportsDir as V}from"../../../core/canvas/paths.js";import{withCanvasWrite as X}from"../../../core/canvas/db.js";import{cancelCronsOnWake as I}from"../../../core/canvas/crons.js";import{assertNotFinalized as N,assertFinalizedForReopen as Y,commitReopenResident as A}from"../../../core/runtime/reopen.js";import{writeOutputSchema as Z}from"../../../core/runtime/structured-output.js";import{appendSituationalContext as j,formatSituationalProse as ee}from"../../../core/runtime/situational-context.js";import{formatDataCard as P}from"../../../shared/generated-context.js";import{hasNoNaturalCycle as te}from"../../../core/runtime/revive-all.js";import{recordPendingParkActivity as re}from"../../park-pending.js";import{wantsExecution as ne}from"../../reconcilers/node-lifecycle/wants-execution.js";import{hasFreshGroundState as oe}from"../../../core/runtime/revive.js";import{notFound as S,usage as a}from"../../../core/errors.js";import{assertScope as ie}from"../../../core/scopes.js";import{InputError as ae}from"../../../core/io.js";import{ApiError as se}from"../../../api/index.js";import{ownerOnly as de}from"../router.js";const ce=["critical","urgent","normal","deferred"];function M(r,e){if(typeof r!="object"||r===null||Array.isArray(r))throw a(`${e} must be an object { kind, facts?, body? }`);const i=r,t=i.kind;if(typeof t!="string"||t.trim()==="")throw a(`${e}.kind is required`);if(!t.includes(":"))throw a(`${e}.kind must be namespaced (contain ':'): ${t}`);const s={kind:t},n=i.facts;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n))throw a(`${e}.facts must be an object of string or number values`);const y={};for(const[m,f]of Object.entries(n)){if(typeof f!="string"&&typeof f!="number")throw a(`${e}.facts.${m} must be a string or number`);y[m]=f}s.facts=y}const o=i.body;if(o!==void 0){if(typeof o!="string")throw a(`${e}.body must be a string`);s.body=o}return s}c(M,"parseCardRequest");function T(r,e){try{return P(r.kind,r.facts??{},r.body??"")}catch(i){throw a(`${e}: ${i instanceof Error?i.message:String(i)}`)}}c(T,"renderCard");function ue(r){if(typeof r!="object"||r===null)throw a("a message requires a JSON body { body, tier?, fresh? }");const e=r,i=e.body,t=e.fresh===!0,s=e.tier,n=e.situational_context,o=e.output_schema,y=typeof i=="string"&&i.trim()!=="",m=typeof n=="string"&&n.trim()!=="",f=typeof o=="string"&&o.trim()!=="",g=e.situational_card,h=e.context_cards,b=g===void 0?void 0:M(g,"situational_card");if(h!==void 0&&!Array.isArray(h))throw a("context_cards must be an array of { kind, facts?, body? }");const l=h?.map((v,k)=>M(v,`context_cards[${k}]`));if(b!==void 0&&typeof n=="string"&&n!=="")throw a("situational_card and situational_context are mutually exclusive");const _=b!==void 0||l!==void 0&&l.length>0;if(!t&&!y&&!m&&!f&&!_)throw a("a message requires a non-empty body (or fresh: true, situational_context, a runtime card, or output_schema)");if(t&&l!==void 0&&l.length>0)throw a("context_cards cannot ride a fresh revive (no inbox entry carries them)");if(s!==void 0&&!ce.includes(s))throw a(`invalid tier: ${String(s)} (expected critical|urgent|normal|deferred)`);const u={body:typeof i=="string"?i:""};s!==void 0&&(u.tier=s),t&&(u.fresh=!0),e.reopen===!0&&(u.reopen=!0),typeof n=="string"&&(u.situational_context=n),b!==void 0&&(u.situational_card=b),l!==void 0&&(u.context_cards=l),typeof o=="string"&&(u.output_schema=o),typeof e.from=="string"&&(u.from=e.from);const p=e.delivery;if(p!==void 0&&p!=="interactive")throw a(`invalid delivery: ${String(p)} (expected interactive)`);if(p==="interactive"){if(t||u.situational_context!==void 0||u.output_schema!==void 0)throw a("interactive delivery supports a body, runtime cards, and reopen only (no fresh, situational_context, or output_schema)");if(!y)throw a("interactive delivery requires a non-empty body");if(u.tier==="deferred")throw a("interactive delivery cannot be deferred");u.delivery="interactive"}return u}c(ue,"parseSendBody");function fe(r){try{return JSON.parse(r)}catch{throw a("output_schema must be a JSON schema string")}}c(fe,"parseSchema");function le(r){return r.split(`
2
+ `)[0].slice(0,120)}c(le,"label");function z(r,e){if(e===null)return"";const i=J(V(r),e);return P("reopen-final-report",{path:i},"This node previously completed work. Read this final report before acting on the new instruction.")}c(z,"previousFinalReportCard");function me(r,e){return new ae({error:"deferred_no_natural_cycle",message:`${r} is ${e} with no natural next cycle ahead of it \u2014 a deferred message would never be delivered.`,next:"Use --tier normal, urgent, or critical to wake it now, or --reopen (with a body or --fresh) to re-task it first."})}c(me,"deferredNoNaturalCycle");function pe(r){if(!oe(r))throw new se(422,"unprocessable",`node ${r} has no goal/roadmap on disk \u2014 a fresh revive would resume amnesiac.`)}c(pe,"assertRecoverableForFresh");async function ye(r){const e=r.params.id,i=x(e);if(i===null)throw S(`unknown node: ${e}`,{received:e});const t=ue(r.body),s=t.tier??"normal",n=K(i.profile_id),o=t.from??null;if(o!==null){const d=x(o);d!==null&&ie(d,"act")}const y=t.body.trim()!=="",m=t.situational_card!==void 0?T(t.situational_card,"situational_card"):t.situational_context!==void 0?ee(t.situational_context.trim()):"",f=m!=="",g=(t.context_cards??[]).map((d,w)=>T(d,`context_cards[${w}]`)),h=t.output_schema!==void 0&&t.output_schema.trim()!==""?fe(t.output_schema):null;if(t.fresh){const d=t.reopen?Y(e):null;t.reopen||N(e),pe(e),f&&j(e,m),t.reopen&&A(e,d);const w=await O(e,{resume:!1,capacity:"refuse"});return{status:201,body:{node_id:e,delivered:!1,revived:w.launch!==void 0}}}t.delivery==="interactive"&&!t.reopen&&N(e);let b=!1,l="";if(t.delivery==="interactive"&&t.reopen&&(l=z(e,A(e)),b=!0),t.delivery==="interactive"&&!n&&C(i))try{return f&&j(e,m),await U(e,t.body,{cards:[...l===""?[]:[l],...f?[m]:[],...g],origin:o==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...o===null?{}:{from:o},kind:"message",tier:s}]}}),I(e),{status:201,body:{node_id:e,delivered:!0,revived:!1,delivered_via:"engine"}}}catch(d){if(!(d instanceof F))throw d}const _=c(()=>{t.reopen||N(e),h!==null&&Z(e,"oneoff",h),f&&j(e,m),t.reopen&&!b&&(l=z(e,A(e)));const d=[...l===""?[]:[l],...g],w=d.length>0?{cards:d}:{};if(y||h!==null){const $=y?t.body:"A one-off structured-output request has been granted. Submit a result matching the requested schema with `crtr push result` before you stop; after it is accepted, continue normally.";return q(e,{senderNodeId:o,urgency:s,wake:1,kind:"message",label:le($),bodyJson:{body:$,...f?{situational:!0}:{},...w}})}return q(e,{senderNodeId:o,urgency:s,wake:1,kind:"message",label:f?"(ambient context updated)":"(context delivered)",bodyJson:{...f?{situational:!0}:{},situationalOnly:!0,...w}})},"deliverImmediate"),p=c(()=>{if(s==="deferred"){const d=Q(e,te,_);if(d.kind==="missing")throw S(`unknown node: ${e}`,{received:e});if(d.kind==="terminal")throw me(e,d.status);return d.result}return _()},"deliver")();p.urgency!=="deferred"&&X(()=>re(e));const v=x(e);if(v===null)throw S(`unknown node: ${e}`,{received:e});i.frozen_at!==null&&I(e);let k=!1,R=!1;if((t.reopen||v.lifecycle==="terminal"||!ne(v))&&p.urgency!=="deferred"&&!n&&!C(v))try{const d=await O(e,{resume:!0,capacity:"freeze"});k=d.launch!==void 0,R=d.outcome==="frozen"}catch{}return{status:201,body:{node_id:e,delivered:!0,revived:k,...R?{not_revived_reason:"capacity_frozen"}:{},delivered_at:p.createdAt,...p.urgency===s?{}:{delivered_tier:p.urgency},...t.delivery==="interactive"?{delivered_via:"inbox"}:{}}}}c(ye,"handleMessage");async function he(r){const e=r.params.id,i=x(e);if(i===null)throw S(`unknown node: ${e}`,{received:e});const t=G(e,{senderNodeId:"human",kind:"message"});let s=!1;if(C(i))try{s=await H(e)!=="idle"}catch(o){if(!(o instanceof F))throw o}return{status:200,body:{node_id:e,outcome:s?"aborted_turn":t.length>0?"canceled_pending":"idle",aborted_turn:s,canceled_pending:t.length}}}c(he,"handleInterrupt");function B(r){if(typeof r.body!="object"||r.body===null||Array.isArray(r.body))throw a("mail requires an object body");const e=r.body;if(typeof e.execution_id!="string"||e.execution_id.trim()==="")throw a("execution_id is required");return e}c(B,"mailBody");function be(r){const e=B(r),i=e.channel;if(i!=="wake"&&i!=="passive")throw a("channel must be wake or passive");const t=W(r.params.id,e.execution_id,i);return{status:200,body:{action:t.action,deliveries:t.deliveries.map(n=>({delivery_id:n.deliveryId,attempts:n.attempts,handoff:n.handoff,entry:L(n)}))}}}c(be,"handleMailClaim");function ve(r){const e=B(r);if(!Array.isArray(e.deliveries))throw a("deliveries must be an array");const i=e.deliveries.map(n=>{if(typeof n!="object"||n===null||Array.isArray(n))throw a("each delivery must be an object");const o=n;if(typeof o.delivery_id!="string"||o.delivery_id==="")throw a("delivery_id is required");if(!Number.isSafeInteger(o.attempts)||o.attempts<1)throw a("attempts must be a positive integer");if(o.disposition!=="acknowledged"&&o.disposition!=="released")throw a("disposition must be acknowledged or released");return{delivery_id:o.delivery_id,attempts:o.attempts,disposition:o.disposition}}),t=D(r.params.id,e.execution_id,i.map(n=>({deliveryId:n.delivery_id,attempts:n.attempts,disposition:n.disposition})));return{status:200,body:{action:t.action,results:t.results.map(n=>({delivery_id:n.deliveryId,outcome:n.outcome}))}}}c(ve,"handleMailAcknowledge");const Ke=de([{method:"POST",pattern:"/v1/nodes/:id/mail/claim",handler:be},{method:"POST",pattern:"/v1/nodes/:id/mail/acknowledge",handler:ve}]),Qe=[{method:"POST",pattern:"/v1/nodes/:id/messages",scope:"act",handler:ye},{method:"POST",pattern:"/v1/nodes/:id/interrupt",scope:"act",handler:he}];export{Ke as brokerMailRoutes,Qe as messageRoutes};
@@ -1,2 +1,2 @@
1
- import type { RouteTable } from '../router.js';
1
+ import { type RouteTable } from '../router.js';
2
2
  export declare const modelConfigRoutes: RouteTable;
@@ -1 +1 @@
1
- var f=Object.defineProperty;var i=(e,o)=>f(e,"name",{value:o,configurable:!0});import{ApiError as t}from"../../../api/errors.js";import{validateCoreModelConfig as a,replaceCoreModelConfig as c}from"../../../core/model-config.js";import{parseModelSpec as d}from"../../../core/model-routes.js";import{openModelRegistry as l}from"../../../core/runtime/model-registry.js";function g(e){if(e===null||typeof e!="object"||Array.isArray(e))throw new t(400,"invalid_request","model config must be an object");const o=e;if(typeof o.config_version!="string"||o.config_version.trim()==="")throw new t(400,"invalid_request","config_version must be a non-empty string");try{return{configVersion:o.config_version,config:a(o)}}catch(r){throw new t(400,"invalid_request",r instanceof Error?r.message:String(r))}}i(g,"parseRequest");async function m(e){const o=await l();for(const r of Object.values(e.modelRoutes))for(const n of Object.values(r.models)){const s=d(n);if(s===void 0||o.find(s.providerId,s.modelId)===void 0)throw new t(422,"unprocessable",`route ref ${n} is absent from the baked model registry`)}}i(m,"validateCatalog");async function u(e){const{configVersion:o,config:r}=g(e.body);await m(r);try{c(r)}catch(n){throw new t(500,"model_config_write_failed",n instanceof Error?n.message:String(n))}return{status:200,body:{config_version:o,delivered:!0}}}i(u,"handlePut");const _=[{method:"PUT",pattern:"/v1/model-config",handler:u}];export{_ as modelConfigRoutes};
1
+ var f=Object.defineProperty;var i=(e,o)=>f(e,"name",{value:o,configurable:!0});import{ApiError as t}from"../../../api/errors.js";import{validateCoreModelConfig as a,replaceCoreModelConfig as c}from"../../../core/model-config.js";import{parseModelSpec as d}from"../../../core/model-routes.js";import{openModelRegistry as l}from"../../../core/runtime/model-registry.js";import{ownerOnly as m}from"../router.js";function g(e){if(e===null||typeof e!="object"||Array.isArray(e))throw new t(400,"invalid_request","model config must be an object");const o=e;if(typeof o.config_version!="string"||o.config_version.trim()==="")throw new t(400,"invalid_request","config_version must be a non-empty string");try{return{configVersion:o.config_version,config:a(o)}}catch(r){throw new t(400,"invalid_request",r instanceof Error?r.message:String(r))}}i(g,"parseRequest");async function u(e){const o=await l();for(const r of Object.values(e.modelRoutes))for(const n of Object.values(r.models)){const s=d(n);if(s===void 0||o.find(s.providerId,s.modelId)===void 0)throw new t(422,"unprocessable",`route ref ${n} is absent from the baked model registry`)}}i(u,"validateCatalog");async function p(e){const{configVersion:o,config:r}=g(e.body);await u(r);try{c(r)}catch(n){throw new t(500,"model_config_write_failed",n instanceof Error?n.message:String(n))}return{status:200,body:{config_version:o,delivered:!0}}}i(p,"handlePut");const C=m([{method:"PUT",pattern:"/v1/model-config",handler:p}]);export{C as modelConfigRoutes};
@@ -1 +1 @@
1
- var L=Object.defineProperty;var o=(n,t)=>L(n,"name",{value:t,configurable:!0});import{homedir as P}from"node:os";import{join as k}from"node:path";import{deleteAuthCredential as A,readAuthCredentials as I,setAuthCredential as q}from"../../../core/auth-file.js";import{ApiError as u}from"../../../api/index.js";import{usage as y}from"../../../core/errors.js";import{resolveLaunchTarget as R}from"../../../core/runtime/launch-target.js";import{ANTHROPIC_PROVIDER_ID as D,OPENAI_CODEX_PROVIDER_ID as O,commitManagedLogin as $,readSubscriptionPool as w,removeAllManagedAccounts as M}from"../../../core/subscription-state.js";function l(){const n=process.env.PI_CODING_AGENT_DIR,t=n!==void 0&&n!==""?n:k(P(),".pi","agent");return k(t,"auth.json")}o(l,"authPath");function f(n){return n===D||n===O}o(f,"isManagedProvider");function E(n,t){if(typeof t!="string"||t==="")throw new u(400,"invalid_request",`oauth credential requires \`${n}\``);const e=Date.parse(t);if(Number.isNaN(e))throw new u(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return e}o(E,"parseExpiry");function h(n,t,e){if(typeof e!="string"||e==="")throw new u(400,"invalid_request",`${n} credential requires \`${t}\``);return e}o(h,"requireField");function N(n){return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}o(N,"toManagedAccountStatus");function S(n){const t=w(n).map(N);return{provider:n,managed:!0,configured:t.length>0,accounts:t}}o(S,"managedStatus");function g(n,t){const e=n.query.getAll(t);if(e.length>1)throw y(`${t} must appear at most once`);return e[0]}o(g,"singleQueryValue");function T(n){const t=n.indexOf("/"),e=t>0?n.slice(0,t):"";if(e==="")throw new u(422,"unresolved_model","the selected launch has no concrete model provider");return e}o(T,"providerFromModel");async function C(){const n=await I(l()),t=[S(D),S(O)];for(const[e,a]of Object.entries(n))f(e)||a.type!=="api_key"&&a.type!=="oauth"||t.push({provider:e,managed:!1,configured:!0,kind:a.type});return{status:200,body:{providers:t}}}o(C,"handleList");async function F(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw y(`unknown model-auth readiness query parameter: ${s}`);const t=g(n,"profile"),e=g(n,"cwd"),a=g(n,"kind"),r=g(n,"model");if(a!==void 0&&a.trim()==="")throw y("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw y("model must be a non-empty string when provided");const d=await R({root:!0,...t!==void 0?{profile:t}:{},...e!==void 0?{cwd:e}:{},...a!==void 0?{kind:a}:{},...r!==void 0?{model:r}:{}},{readOnlyProfileSelection:!0});if(d.launch.model===void 0)throw new u(422,"unresolved_model","the selected launch has no concrete model");const i=T(d.launch.model),c=await I(l());if(f(i)){const s=w(i),m=s.filter(p=>p.authFailure===void 0);if(m.length===0)return{status:200,body:s.length===0?{provider:i,model:d.launch.model,credential:"missing"}:{provider:i,model:d.launch.model,credential:"unusable",reason:"invalid_grant"}};const v=Date.now(),x=m.some(p=>p.rateLimitedUntil<=v),b=Math.min(...m.map(p=>p.rateLimitedUntil));return{status:200,body:{provider:i,model:d.launch.model,credential:"ready",...!x&&b>v?{rate_limited_until:new Date(b).toISOString()}:{}}}}const _=c[i];return{status:200,body:{provider:i,model:d.launch.model,credential:_?.type==="api_key"||_?.type==="oauth"?"ready":"missing"}}}o(F,"handleReadiness");async function j(n){const t=n.params.provider,e=n.body;if(e===void 0||typeof e!="object"||typeof e.kind!="string")throw new u(400,"invalid_request","a credential `kind` is required");switch(e.kind){case"api_key":{const a=h("api_key","api_key",e.api_key);return await q(t,{type:"api_key",key:a},l()),{status:200,body:{provider:t,installed:!0,managed:!1}}}case"oauth":{if(f(t))throw new u(422,"unprocessable",`provider ${t} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const a=h("oauth","access_token",e.access_token),r=h("oauth","refresh_token",e.refresh_token),d=E("expires_at",e.expires_at),i=e.extra??{};await q(t,{type:"oauth",...i,access:a,refresh:r,expires:d},l());const c={provider:t,installed:!0,managed:!1};return typeof e.account_id=="string"&&e.account_id!==""&&(c.account_id=e.account_id),{status:200,body:c}}case"managed_account":{if(!f(t))throw new u(422,"unprocessable",`provider ${t} does not support managed accounts`);const a=typeof e.label=="string"&&e.label.trim()?e.label.trim():void 0;if(!a&&e.auto_label!==!0)throw new u(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof e.account_id=="string"&&e.account_id!==""?e.account_id:void 0,d=h("managed_account","access_token",e.access_token),i=h("managed_account","refresh_token",e.refresh_token),c=E("expires_at",e.expires_at),_=typeof e.last_rate_limited_at=="number"?e.last_rate_limited_at:Math.max(0,...w(t).map(m=>m.lastRateLimitedAt));await $(t,a,{refresh:i,access:d,expires:c,...r?{accountId:r}:{},lastRateLimitedAt:_,autoLabel:e.auto_label===!0});const s={provider:t,installed:!0,managed:!0};return r&&(s.account_id=r),{status:200,body:s}}default:throw new u(400,"invalid_request",`unknown credential kind: ${String(e.kind)}`)}}o(j,"handleInstall");async function G(n){const t=n.params.provider;if(f(t)){const a=await M(t),r=await A(t,l());return{status:200,body:{provider:t,removed_accounts:a+(r?1:0)}}}const e=await A(t,l())?1:0;return{status:200,body:{provider:t,removed_accounts:e}}}o(G,"handleDelete");const J=[{method:"GET",pattern:"/v1/model-auth",handler:C},{method:"GET",pattern:"/v1/model-auth/readiness",handler:F},{method:"PUT",pattern:"/v1/model-auth/:provider",handler:j},{method:"DELETE",pattern:"/v1/model-auth/:provider",handler:G}];export{J as modelAuthRoutes};
1
+ var L=Object.defineProperty;var o=(n,t)=>L(n,"name",{value:t,configurable:!0});import{homedir as P}from"node:os";import{join as k}from"node:path";import{deleteAuthCredential as A,readAuthCredentials as I,setAuthCredential as q}from"../../../core/auth-file.js";import{ApiError as u}from"../../../api/index.js";import{usage as y}from"../../../core/errors.js";import{resolveLaunchTarget as R}from"../../../core/runtime/launch-target.js";import{ANTHROPIC_PROVIDER_ID as D,OPENAI_CODEX_PROVIDER_ID as O,commitManagedLogin as $,readSubscriptionPool as g,removeAllManagedAccounts as M}from"../../../core/subscription-state.js";function l(){const n=process.env.PI_CODING_AGENT_DIR,t=n!==void 0&&n!==""?n:k(P(),".pi","agent");return k(t,"auth.json")}o(l,"authPath");function f(n){return n===D||n===O}o(f,"isManagedProvider");function E(n,t){if(typeof t!="string"||t==="")throw new u(400,"invalid_request",`oauth credential requires \`${n}\``);const e=Date.parse(t);if(Number.isNaN(e))throw new u(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return e}o(E,"parseExpiry");function h(n,t,e){if(typeof e!="string"||e==="")throw new u(400,"invalid_request",`${n} credential requires \`${t}\``);return e}o(h,"requireField");function N(n){return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}o(N,"toManagedAccountStatus");function S(n){const t=g(n).map(N);return{provider:n,managed:!0,configured:t.length>0,accounts:t}}o(S,"managedStatus");function w(n,t){const e=n.query.getAll(t);if(e.length>1)throw y(`${t} must appear at most once`);return e[0]}o(w,"singleQueryValue");function T(n){const t=n.indexOf("/"),e=t>0?n.slice(0,t):"";if(e==="")throw new u(422,"unresolved_model","the selected launch has no concrete model provider");return e}o(T,"providerFromModel");async function C(){const n=await I(l()),t=[S(D),S(O)];for(const[e,a]of Object.entries(n))f(e)||a.type!=="api_key"&&a.type!=="oauth"||t.push({provider:e,managed:!1,configured:!0,kind:a.type});return{status:200,body:{providers:t}}}o(C,"handleList");async function F(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw y(`unknown model-auth readiness query parameter: ${s}`);const t=w(n,"profile"),e=w(n,"cwd"),a=w(n,"kind"),r=w(n,"model");if(a!==void 0&&a.trim()==="")throw y("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw y("model must be a non-empty string when provided");const d=await R({root:!0,...t!==void 0?{profile:t}:{},...e!==void 0?{cwd:e}:{},...a!==void 0?{kind:a}:{},...r!==void 0?{model:r}:{}},{readOnlyProfileSelection:!0});if(d.launch.model===void 0)throw new u(422,"unresolved_model","the selected launch has no concrete model");const i=T(d.launch.model),c=await I(l());if(f(i)){const s=g(i),m=s.filter(p=>p.authFailure===void 0);if(m.length===0)return{status:200,body:s.length===0?{provider:i,model:d.launch.model,credential:"missing"}:{provider:i,model:d.launch.model,credential:"unusable",reason:"invalid_grant"}};const v=Date.now(),x=m.some(p=>p.rateLimitedUntil<=v),b=Math.min(...m.map(p=>p.rateLimitedUntil));return{status:200,body:{provider:i,model:d.launch.model,credential:"ready",...!x&&b>v?{rate_limited_until:new Date(b).toISOString()}:{}}}}const _=c[i];return{status:200,body:{provider:i,model:d.launch.model,credential:_?.type==="api_key"||_?.type==="oauth"?"ready":"missing"}}}o(F,"handleReadiness");async function j(n){const t=n.params.provider,e=n.body;if(e===void 0||typeof e!="object"||typeof e.kind!="string")throw new u(400,"invalid_request","a credential `kind` is required");switch(e.kind){case"api_key":{const a=h("api_key","api_key",e.api_key);return await q(t,{type:"api_key",key:a},l()),{status:200,body:{provider:t,installed:!0,managed:!1}}}case"oauth":{if(f(t))throw new u(422,"unprocessable",`provider ${t} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const a=h("oauth","access_token",e.access_token),r=h("oauth","refresh_token",e.refresh_token),d=E("expires_at",e.expires_at),i=e.extra??{};await q(t,{type:"oauth",...i,access:a,refresh:r,expires:d},l());const c={provider:t,installed:!0,managed:!1};return typeof e.account_id=="string"&&e.account_id!==""&&(c.account_id=e.account_id),{status:200,body:c}}case"managed_account":{if(!f(t))throw new u(422,"unprocessable",`provider ${t} does not support managed accounts`);const a=typeof e.label=="string"&&e.label.trim()?e.label.trim():void 0;if(!a&&e.auto_label!==!0)throw new u(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof e.account_id=="string"&&e.account_id!==""?e.account_id:void 0,d=h("managed_account","access_token",e.access_token),i=h("managed_account","refresh_token",e.refresh_token),c=E("expires_at",e.expires_at),_=typeof e.last_rate_limited_at=="number"?e.last_rate_limited_at:Math.max(0,...g(t).map(m=>m.lastRateLimitedAt));await $(t,a,{refresh:i,access:d,expires:c,...r?{accountId:r}:{},lastRateLimitedAt:_,autoLabel:e.auto_label===!0});const s={provider:t,installed:!0,managed:!0};return r&&(s.account_id=r),{status:200,body:s}}default:throw new u(400,"invalid_request",`unknown credential kind: ${String(e.kind)}`)}}o(j,"handleInstall");async function G(n){const t=n.params.provider;if(f(t)){const a=await M(t),r=await A(t,l());return{status:200,body:{provider:t,removed_accounts:a+(r?1:0)}}}const e=await A(t,l())?1:0;return{status:200,body:{provider:t,removed_accounts:e}}}o(G,"handleDelete");const J=[{method:"GET",pattern:"/v1/model-auth",handler:C},{method:"GET",pattern:"/v1/model-auth/readiness",handler:F},{method:"PUT",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:j},{method:"DELETE",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:G}];export{J as modelAuthRoutes};
@@ -1 +1 @@
1
- var U=Object.defineProperty;var s=(e,t)=>U(e,"name",{value:t,configurable:!0});import{envProfileId as X}from"../../../shared/env.js";import{existsSync as C,readdirSync as Z,statSync as q}from"node:fs";import{basename as ee,isAbsolute as ne,resolve as I}from"node:path";import{appendSituationalContext as te,formatSituationalProse as oe}from"../../../core/runtime/situational-context.js";import{closeNode as ie}from"../../../core/runtime/close.js";import{reviveNode as re}from"../../../core/runtime/revive.js";import{nowIso as T}from"../../../core/fs-utils.js";import{assertLaunchModelRegistered as A,forkNode as de,spawnChildPrepared as se}from"../../../core/runtime/spawn.js";import{childrenOf as ae,getNode as b,listNodes as M,subscribersOf as le,subscriptionsOf as E,setMessageWait as ce,updateNode as $}from"../../../core/canvas/canvas.js";import{subtreeIds as ue}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as fe}from"../../../core/canvas/db.js";import{unbindSession as me}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as pe}from"../../../core/canvas/attention.js";import{contextDir as P,reportsDir as he}from"../../../core/canvas/paths.js";import{nodeArtifacts as we}from"../../../core/canvas/history.js";import{readNodeMessagesPage as ye,readNodeSession as _e,readNodeSnapshot as ge,transcriptMarkdown as be}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as ve}from"../../../core/substrate/subject.js";import{reviveAll as ke}from"../../../core/runtime/revive-all.js";import{promoteAsync as Se,requestYieldAsync as Oe,reshapeNodeAsync as L}from"../../../core/runtime/promote.js";import{recycleNode as Ne}from"../../../core/runtime/recycle.js";import{relaunchRoot as Te}from"../../../core/runtime/reset.js";import{assertReopenGate as Ae}from"../../../core/runtime/reopen.js";import{writeYieldMessage as $e,readGoal as Pe}from"../../../core/runtime/kickoff.js";import{hasRoadmap as Re,seedRoadmap as xe}from"../../../core/runtime/roadmap.js";import{renameWindow as De}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as Ce,isProviderPinnedModelToken as Ie,normalizeModel as Me,readMergedLaunchConfigAsync as j}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Ee}from"../../../core/model-routes.js";import{BrokerUnreachableError as Le}from"../../../core/runtime/broker-request.js";import{isBrokerLive as je,persistDormantModel as Fe,setModelLive as Ge}from"../../../core/runtime/model-swap.js";import{boundFleet as ze}from"../../../core/runtime/fleet.js";import{writeOutputSchema as F}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as G}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as We}from"../../../core/human/action-binding.js";import{resolveHumanAction as Be}from"../../../core/human-actions.js";import{parseDurationMs as Je}from"../../../core/wake.js";import{claimWarmNode as Ve,refillWarmPool as z,warmPoolEnabled as Ke}from"../../../core/runtime/warm-pool.js";import{resolveLaunchTarget as Ye}from"../../../core/runtime/launch-target.js";import{fullName as He}from"../../../core/canvas/labels.js";import{reportsForNode as Qe}from"./reports.js";import{getCron as Ue}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Xe}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Ze}from"../../control.js";import{notFound as R,usage as u}from"../../../core/errors.js";import{assertScope as qe,validateScopes as W}from"../../../core/scopes.js";import{scopeAllowed as en}from"../../../shared/env.js";import{toCloseResultDTO as nn,toNodeDetailDTO as x,toNodeSummaryDTO as tn,toReviveResultDTO as on}from"../map.js";import{ApiError as w}from"../../../api/index.js";import{InputError as m}from"../../../core/io.js";function f(e){const t=b(e);if(t===null)throw R(`unknown node: ${e}`,{received:e});return t}s(f,"requireMeta");function D(e){return{subscribesTo:E(e),subscribers:le(e),children:ae(e)}}s(D,"edgesFor");function y(e){const t=f(e);return x(t,D(e))}s(y,"detailOf");function B(e){let t=0;for(const n of[P(e),he(e)])try{t+=Z(n).length}catch{}return t}s(B,"countFiles");function rn(e){if(typeof e!="object"||e===null)throw u("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw u("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw u("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw u("creator must be a non-empty node id when provided");t.scopes!==void 0&&W(t.scopes);const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw u("root_lifecycle must be 'resident' or 'terminal'");return t}s(rn,"parseCreateBody");function dn(e){if(e===void 0)return;const t=Je(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new w(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}s(dn,"parseDeadline");function sn(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new w(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!We.test(e.action))throw new w(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new w(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new w(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>G)throw new w(413,"payload_too_large",`serialized payload exceeds ${G} bytes`)}return e}}s(sn,"parseOutcomeDelivery");function an(e,t){const n=Be(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new w(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new w(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}s(an,"resolveOutcomeDelivery");function ln(e,t,n){const o={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(o.mode=e.mode),e.name!==void 0&&(o.name=e.name),e.description!==void 0&&(o.description=e.description),t!==void 0&&(o.parent=t),e.creator!==void 0&&(o.creator=e.creator),e.scopes!==void 0&&(o.scopes=e.scopes),e.root===!0&&(o.root=!0),e.root_lifecycle!==void 0&&(o.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(o.worktree=!0),typeof e.worktree=="string"&&(o.worktreeBase=e.worktree),e.worktree!==void 0&&(o.worktreeCwd=I(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(o.forkFrom=e.fork_from),e.model!==void 0&&(o.model=e.model),e.profile!==void 0&&(o.profile=e.profile),e.situational_context!==void 0&&(o.situationalContext=e.situational_context),e.node_id!==void 0&&(o.nodeId=e.node_id),o}s(ln,"buildRecipe");function cn(e,t,n){return!Ke()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}s(cn,"warmRequestFor");import{resolveCreateKind as Dt}from"../../../core/runtime/launch-target.js";function J(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Ee(e.model,t,e.modelExact===!0)}s(J,"requestFromLaunch");async function V(e,t,n){const o=(await Ce(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await A(J(o),{cwd:e.cwd,profileId:e.profile_id??null},n)}s(V,"assertNodeModelChangeRegistered");async function un(e,t={}){const n=rn(e.body);n.creator!==void 0&&qe(f(n.creator),"act");const o=dn(n.deadline),r=sn(n.outcome_delivery),i=n.parent??void 0;if(i==null&&n.root!==!0)throw u("a node create requires a parent (or root: true for an independent root)");let d=null;if(n.output_schema!==void 0)try{d=JSON.parse(n.output_schema)}catch{throw u("output_schema must be a JSON schema string")}const{profileId:a,kind:c,cwd:l,launch:p}=await Ye(n,{validateKind:Y}),v={...n,kind:c},_=r===void 0?void 0:an(r,l);await A(J(p),{cwd:l,profileId:a},t.modelRegistry);let g=null;{const k=cn(v,l,a);if(k!==null){const O=await Ve(k,{...o===void 0?{}:{deadlineAt:o},..._===void 0?{}:{outcomeDelivery:_}},d===null?void 0:Q=>F(Q,"terminal",d));if(O!==null)return z(k),{status:201,body:y(O)};g=k}const S=ln(v,i,l);o!==void 0&&(S.deadlineAt=o),_!==void 0&&(S.outcomeDelivery=_),S.readiness=n.root===!0?"await":"launch";const H=await se(S,d===null?void 0:O=>F(O,"terminal",d),()=>{g!==null&&z(g)});return{status:201,body:y(H.node.node_id)}}}s(un,"handleCreate");function h(e,t){const n=e.query.getAll(t);if(n.length>1)throw u(`${t} must appear at most once`);return n[0]}s(h,"singleQueryValue");function K(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw u(`${t} must be true or false`)}}s(K,"optionalBoolean");function N(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw u(`${t} must be one of: ${n.join(", ")}`)}}s(N,"oneOf");function fn(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[g]of e.query)if(!t.has(g))throw u(`unknown nodes query parameter: ${g}`);const n=N(h(e,"status"),"status",["active","idle","done","dead","canceled"]),o=N(h(e,"lifecycle"),"lifecycle",["terminal","resident"]),r=h(e,"kind"),i=N(h(e,"mode"),"mode",["base","orchestrator"]),d=h(e,"profile_id"),a=h(e,"profile_prefix"),c=h(e,"parent"),l=K(h(e,"top_level"),"top_level"),p=h(e,"under"),v=K(h(e,"hanging"),"hanging"),_=N(h(e,"include"),"include",["activity"]);if(c!==void 0&&l===!0)throw u("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...o!==void 0?{lifecycle:o}:{},...r!==void 0?{kind:r}:{},...i!==void 0?{mode:i}:{},...d!==void 0?{profile_id:d}:{},...a!==void 0?{profile_prefix:a}:{},...c!==void 0?{parent:c}:{},...l!==void 0?{top_level:l}:{},...p!==void 0?{under:p}:{},...v!==void 0?{hanging:v}:{},..._!==void 0?{include:_}:{}}}s(fn,"parseListQuery");function mn(e){const t=fn(e);let n=t.status!==void 0?M({status:t.status}):M();if(t.lifecycle!==void 0&&(n=n.filter(i=>i.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(i=>i.kind===t.kind)),t.mode!==void 0&&(n=n.filter(i=>i.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(i=>i.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(i=>i.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(i=>i.parent===t.parent)),t.top_level===!0&&(n=n.filter(i=>i.parent===null)),t.under!==void 0){const i=new Set(ue(t.under));n=n.filter(d=>i.has(d.node_id))}t.hanging===!0&&(n=n.filter(i=>i.parent!==null&&b(i.parent)===null));const o=t.include==="activity"?pe(n.map(i=>i.node_id)):null;return{status:200,body:n.map(i=>{const d=tn(i);if(o!==null){const a=Qe(i.node_id);d.activity={latest_report:a[0]??null,final_report:i.final_report===null?null:a.find(c=>ee(c.path)===i.final_report)??null,pending_human_count:o[i.node_id]??0}}return d})}}s(mn,"handleList");function pn(e){const t=e.params.id;return f(t),{status:200,body:y(t)}}s(pn,"handleDetail");async function hn(e){const t=e.params.id;f(t);const n=await ge(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(r=>({name:r.name,description:r.description,source:r.source})),captured_at:T()}}}s(hn,"handleSnapshot");async function wn(e){const t=e.params.id,n=ve(t);if(n===null)throw R(`unknown node: ${t}`,{received:t});return{status:200,body:n}}s(wn,"handleSubject");function yn(e){for(const[i]of e.query)if(i!=="cursor"&&i!=="limit")throw u(`unknown messages query parameter: ${i}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw u("cursor must appear at most once");if(n.length>1)throw u("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const o=n[0],r=Number(o);if(!Number.isSafeInteger(r)||o==="")throw u("limit must be an integer from 1 through 500");return t.length===0?{limit:r}:{cursor:t[0],limit:r}}s(yn,"parseMessagesQuery");async function _n(e){const t=e.params.id,n=await ye(t,yn(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:T()}}}s(_n,"handleMessages");function gn(e){const t=e.params.id;f(t);const n=_e(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:T()}}}s(gn,"handleSession");async function bn(e){const t=e.params.id;return f(t),{status:200,body:{node_id:t,markdown:await be(t)}}}s(bn,"handleTranscript");function vn(e){const t=e.params.id;f(t);const n=[{node_id:t,label:b(t)?.name??t,dir:P(t),self:!0,files:B(t)}];for(const o of E(t))n.push({node_id:o.node_id,label:b(o.node_id)?.name??o.node_id,dir:P(o.node_id),self:!1,files:B(o.node_id)});return{status:200,body:{node_id:t,roots:n}}}s(vn,"handleContext");function kn(e){const t=e.params.id;f(t);const n=e.query.get("type"),o=we(t,n!==null?[n]:void 0).map(i=>({ref:i.ref,source:i.source==="report"&&i.reportKind!==void 0?`report:${i.reportKind}`:i.source,ts:i.ts,title:i.title}));return{status:200,body:{node_id:t,artifacts:o}}}s(kn,"handleArtifacts");async function Sn(e){const t=await de(e.params.id);return{status:201,body:y(t.node.node_id)}}s(Sn,"handleFork");async function On(e){const t=e.params.id;f(t);const n=e.body,o=n?.resume??!0,r=n?.reopen??!1;Ae(t,r);const i=!o&&n?.cron_id!==void 0?Ue(n.cron_id):null,d=await re(t,{resume:o,capacity:"refuse",...i!==null?{wakeReason:Xe(i,"schedule_revive")}:{}}),a=b(t)?.status??"active";return{status:200,body:on(t,d,a)}}s(On,"handleRevive");async function Nn(e){const t=e.params.id;return{status:200,body:{newNodeId:(await Te(t))?.newNodeId??null}}}s(Nn,"handleRelaunchRoot");function Tn(e){const t=e.params.id;f(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw u("caller_pid must be a positive integer when provided");const o=Ze(),r=ie(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...o===null?{}:{registerDetached:o.registerDetached}});return{status:200,body:nn(r)}}s(Tn,"handleClose");async function An(e){const t=e.params.id;f(t);const n=await Ne(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}s(An,"handleRecycle");async function $n(e){const t=e.params.id;return f(t),await L(t,{lifecycle:"terminal"}),{status:200,body:y(t)}}s($n,"handleDemote");async function Pn(e,t={}){const n=e.params.id,o=f(n),r=e.body??{};r.model!==void 0&&await V(o,{kind:r.kind??o.kind,mode:"orchestrator",lifecycle:r.resident===!0?"resident":o.lifecycle,model:r.model},t.modelRegistry);const i=await Se(n,{...r.kind!==void 0?{kind:r.kind}:{},...r.resident===!0?{resident:!0}:{},...r.model!==void 0?{model:r.model}:{}}),d=x(i.meta,D(n));return d.roadmap_written=i.roadmapWritten,d.roadmap_path=i.roadmapPath,d.goal_path=i.goalPath,{status:200,body:d}}s(Pn,"handlePromote");async function Rn(e,t={}){const n=e.params.id,o=f(n),r=e.body??{};r.model!==void 0&&await V(o,{kind:r.kind??o.kind,mode:r.promote===!0?"orchestrator":o.mode,lifecycle:o.lifecycle,model:r.model},t.modelRegistry);const i=r.note??"Refresh: continue against your roadmap or goal.";$e(n,i);const d=await Oe(n,{...r.promote===!0?{promote:!0}:{},...r.kind!==void 0?{kind:r.kind}:{},...r.model!==void 0?{model:r.model}:{}});return{status:200,body:x(d.meta,D(n))}}s(Rn,"handleYield");function xn(e){const t=e.params.id;f(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw u("a wait requires a controller node id");const o=b(n.controller);if(o===null)throw R(`unknown controller: ${n.controller}`,{received:n.controller});if(o.status!=="active"&&o.status!=="idle")throw new w(422,"unprocessable",`controller ${n.controller} is ${o.status}`);return ce(t,n.controller),{status:200,body:y(t)}}s(xn,"handleWait");async function Dn(){const e=await ke();return{status:200,body:{revived:[...e.revived],failed:[...e.failed],frozen:[...e.frozen]}}}s(Dn,"handleReviveAll");async function Cn(e,t={}){const n=e.params.id,o=e.body;let r;if(o===void 0)r={};else if(typeof o=="object"&&o!==null&&!Array.isArray(o))r=o;else throw new m({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:o,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(Object.prototype.hasOwnProperty.call(r,"cwd")){const d=r.cwd;if(typeof d!="string"||d==="")throw new m({error:"cwd_invalid",message:"cwd must be a non-empty string",received:d,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(r).some(l=>l!=="cwd"&&r[l]!==void 0))throw new m({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:r,field:"cwd",next:"Send cwd as the only config field."});const a=f(n);if(ze().has(n)){const l=`${n} cannot repair its cwd while its broker is live`;throw new w(409,"cwd_node_live",l,{error:"cwd_node_live",message:l,received:d,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(a.fork_from!=null)throw new m({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${a.cwd}`,received:d,field:"cwd",next:`Restore ${a.cwd}, then revive the fork normally.`});if(a.managed_worktree?.state==="open")throw new m({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:d,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(C(a.cwd))throw new m({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${a.cwd}; cwd repair is not a relocation command`,received:d,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!ne(d))throw new m({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${d}`,received:d,field:"cwd",next:"Send an absolute path."});const c=I(d);if(!C(c))throw new m({error:"cwd_missing",message:`cwd does not exist: ${c}`,received:d,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!q(c).isDirectory())throw new m({error:"cwd_not_a_directory",message:`cwd is not a directory: ${c}`,received:d,field:"cwd",next:"Send an existing absolute directory."})}catch(l){throw l instanceof m?l:new m({error:"cwd_missing",message:`cwd does not exist: ${c}`,received:d,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return fe(()=>{$(n,{cwd:c}),me(n)}),{status:200,body:y(n)}}let i=f(n);if(r.scopes!==void 0){const d=W(r.scopes);if(!d.every(a=>en(i.scopes,a)))throw new m({error:"unknown_scope",message:"scopes may only narrow the node's current list",received:d,field:"scopes",next:"Send only scopes the node already holds."});i=$(n,{scopes:d})}if(r.situational_context!==void 0&&te(n,oe(r.situational_context)),r.model!==void 0){const d=Ie(r.model),a=(await j(i.cwd,i.profile_id??null)).modelLadders,c=Me(r.model,a);await A({kind:"concrete",spec:c},{cwd:i.cwd,profileId:i.profile_id??null},t.modelRegistry);const l=s(()=>{if(!c.includes("/"))throw u(`model must resolve to a provider/id spec: ${r.model}`);Fe(n,c,d)},"persistDormant");if(je(i))try{await Ge(n,c,d)}catch(p){if(!(p instanceof Le))throw p;l()}else l();i=f(n)}if(r.kind!==void 0||r.mode!==void 0||r.lifecycle!==void 0){r.kind!==void 0&&await Y(r.kind);const d=r.kind??i.kind,a=r.mode??i.mode,c=r.lifecycle??i.lifecycle;let l;a==="orchestrator"&&!Re(n)&&(l=s(()=>{const p=Pe(n);xe(n,p!==null&&p.trim()!==""?{goal:p.trim()}:{})},"beforePersist")),i=await L(n,{...r.kind!==void 0?{kind:d}:{},...r.mode!==void 0?{mode:a}:{},...r.lifecycle!==void 0?{lifecycle:c}:{}},l)}return r.name!==void 0&&(i=$(n,{name:r.name}),i.window&&De(i.window,He(i))),{status:200,body:y(n)}}s(Cn,"handleConfig");async function Y(e){const t=Object.keys((await j(process.cwd(),X()||null)).kinds);if(!t.includes(e))throw u(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}s(Y,"assertKindServer");const Pt=[{method:"POST",pattern:"/v1/nodes",handler:un},{method:"GET",pattern:"/v1/nodes",handler:mn},{method:"POST",pattern:"/v1/nodes/revive-all",handler:s(()=>Dn(),"handler")},{method:"GET",pattern:"/v1/nodes/:id",handler:pn},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:hn},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:wn},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:_n},{method:"GET",pattern:"/v1/nodes/:id/session",handler:gn},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:bn},{method:"GET",pattern:"/v1/nodes/:id/context",handler:vn},{method:"GET",pattern:"/v1/nodes/:id/artifacts",handler:kn},{method:"POST",pattern:"/v1/nodes/:id/fork",handler:Sn},{method:"POST",pattern:"/v1/nodes/:id/revive",handler:On},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",handler:Nn},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Tn},{method:"POST",pattern:"/v1/nodes/:id/recycle",handler:An},{method:"POST",pattern:"/v1/nodes/:id/demote",handler:$n},{method:"POST",pattern:"/v1/nodes/:id/promote",handler:Pn},{method:"POST",pattern:"/v1/nodes/:id/yield",handler:Rn},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:xn},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:Cn}];export{Cn as handleConfig,un as handleCreate,Sn as handleFork,mn as handleList,Pn as handlePromote,Rn as handleYield,Pt as nodeRoutes,Dt as resolveCreateKind};
1
+ var X=Object.defineProperty;var s=(e,t)=>X(e,"name",{value:t,configurable:!0});import{envProfileId as Z}from"../../../shared/env.js";import{existsSync as D,readdirSync as q,statSync as ee}from"node:fs";import{basename as ne,isAbsolute as te,resolve as I}from"node:path";import{appendSituationalContext as oe,formatSituationalProse as ie}from"../../../core/runtime/situational-context.js";import{closeNode as re}from"../../../core/runtime/close.js";import{reviveNode as de}from"../../../core/runtime/revive.js";import{nowIso as T}from"../../../core/fs-utils.js";import{assertLaunchModelRegistered as $,forkNode as se,spawnChildPrepared as ae}from"../../../core/runtime/spawn.js";import{childrenOf as le,getNode as b,listNodes as M,subscribersOf as ce,subscriptionsOf as E,setMessageWait as ue,updateNode as A}from"../../../core/canvas/canvas.js";import{subtreeIds as fe}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as me}from"../../../core/canvas/db.js";import{unbindSession as pe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as he}from"../../../core/canvas/attention.js";import{contextDir as P,reportsDir as we}from"../../../core/canvas/paths.js";import{nodeArtifacts as ye}from"../../../core/canvas/history.js";import{readNodeMessagesPage as ge,readNodeSession as _e,readNodeSnapshot as be,transcriptMarkdown as ve}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as ke}from"../../../core/substrate/subject.js";import{reviveAll as Se}from"../../../core/runtime/revive-all.js";import{promoteAsync as Oe,requestYieldAsync as Ne,reshapeNodeAsync as L}from"../../../core/runtime/promote.js";import{recycleNode as Te}from"../../../core/runtime/recycle.js";import{relaunchRoot as $e}from"../../../core/runtime/reset.js";import{assertReopenGate as Ae}from"../../../core/runtime/reopen.js";import{writeYieldMessage as Pe,readGoal as Re}from"../../../core/runtime/kickoff.js";import{hasRoadmap as xe,seedRoadmap as Ce}from"../../../core/runtime/roadmap.js";import{renameWindow as De}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as Ie,isProviderPinnedModelToken as Me,normalizeModel as Ee,readMergedLaunchConfigAsync as j}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Le}from"../../../core/model-routes.js";import{BrokerUnreachableError as je}from"../../../core/runtime/broker-request.js";import{isBrokerLive as Fe,persistDormantModel as Ge,setModelLive as ze}from"../../../core/runtime/model-swap.js";import{boundFleet as We}from"../../../core/runtime/fleet.js";import{writeOutputSchema as F}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as G}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as Be}from"../../../core/human/action-binding.js";import{resolveHumanAction as Je}from"../../../core/human-actions.js";import{parseDurationMs as Ve}from"../../../core/wake.js";import{claimWarmNode as Ke,refillWarmPool as z,warmPoolEnabled as Ye}from"../../../core/runtime/warm-pool.js";import{resolveLaunchTarget as He}from"../../../core/runtime/launch-target.js";import{fullName as Qe}from"../../../core/canvas/labels.js";import{reportsForNode as Ue}from"./reports.js";import{getCron as Xe}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Ze}from"../../../core/runtime/bearings.js";import{boundDaemonControl as qe}from"../../control.js";import{notFound as R,usage as u}from"../../../core/errors.js";import{assertScope as en,validateScopes as W}from"../../../core/scopes.js";import{scopeAllowed as B}from"../../../shared/env.js";import{toCloseResultDTO as nn,toNodeDetailDTO as x,toNodeSummaryDTO as tn,toReviveResultDTO as on}from"../map.js";import{ApiError as h}from"../../../api/index.js";import{InputError as m}from"../../../core/io.js";function f(e){const t=b(e);if(t===null)throw R(`unknown node: ${e}`,{received:e});return t}s(f,"requireMeta");function C(e){return{subscribesTo:E(e),subscribers:ce(e),children:le(e)}}s(C,"edgesFor");function y(e){const t=f(e);return x(t,C(e))}s(y,"detailOf");function J(e){let t=0;for(const n of[P(e),we(e)])try{t+=q(n).length}catch{}return t}s(J,"countFiles");function rn(e){if(typeof e!="object"||e===null)throw u("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw u("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw u("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw u("creator must be a non-empty node id when provided");t.scopes!==void 0&&W(t.scopes);const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw u("root_lifecycle must be 'resident' or 'terminal'");return t}s(rn,"parseCreateBody");function dn(e){if(e===void 0)return;const t=Ve(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new h(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}s(dn,"parseDeadline");function sn(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new h(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!Be.test(e.action))throw new h(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new h(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new h(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>G)throw new h(413,"payload_too_large",`serialized payload exceeds ${G} bytes`)}return e}}s(sn,"parseOutcomeDelivery");function an(e,t){const n=Je(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new h(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new h(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}s(an,"resolveOutcomeDelivery");function ln(e,t,n){const o={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(o.mode=e.mode),e.name!==void 0&&(o.name=e.name),e.description!==void 0&&(o.description=e.description),t!==void 0&&(o.parent=t),e.creator!==void 0&&(o.creator=e.creator),e.scopes!==void 0&&(o.scopes=e.scopes),e.root===!0&&(o.root=!0),e.root_lifecycle!==void 0&&(o.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(o.worktree=!0),typeof e.worktree=="string"&&(o.worktreeBase=e.worktree),e.worktree!==void 0&&(o.worktreeCwd=I(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(o.forkFrom=e.fork_from),e.model!==void 0&&(o.model=e.model),e.profile!==void 0&&(o.profile=e.profile),e.situational_context!==void 0&&(o.situationalContext=e.situational_context),e.node_id!==void 0&&(o.nodeId=e.node_id),o}s(ln,"buildRecipe");function cn(e,t,n){return!Ye()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}s(cn,"warmRequestFor");import{resolveCreateKind as Dt}from"../../../core/runtime/launch-target.js";function V(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Le(e.model,t,e.modelExact===!0)}s(V,"requestFromLaunch");function un(e,t){if(t===null)return e;if(e.scopes===void 0)return{...e,scopes:[...t]};const n=e.scopes.filter(o=>!B(t,o));if(n.length===0)return e;throw new h(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${n.join(", ")}`,{scopes:n,ceiling:t})}s(un,"withinCeiling");async function K(e,t,n){const o=(await Ie(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await $(V(o),{cwd:e.cwd,profileId:e.profile_id??null},n)}s(K,"assertNodeModelChangeRegistered");async function fn(e,t={}){const n=un(rn(e.body),e.ceiling);n.creator!==void 0&&en(f(n.creator),"act");const o=dn(n.deadline),r=sn(n.outcome_delivery),i=n.parent??void 0;if(i==null&&n.root!==!0)throw u("a node create requires a parent (or root: true for an independent root)");let d=null;if(n.output_schema!==void 0)try{d=JSON.parse(n.output_schema)}catch{throw u("output_schema must be a JSON schema string")}const{profileId:a,kind:c,cwd:l,launch:p}=await He(n,{validateKind:H}),v={...n,kind:c},g=r===void 0?void 0:an(r,l);await $(V(p),{cwd:l,profileId:a},t.modelRegistry);let _=null;{const k=cn(v,l,a);if(k!==null){const O=await Ke(k,{...o===void 0?{}:{deadlineAt:o},...g===void 0?{}:{outcomeDelivery:g}},d===null?void 0:U=>F(U,"terminal",d));if(O!==null)return z(k),{status:201,body:y(O)};_=k}const S=ln(v,i,l);o!==void 0&&(S.deadlineAt=o),g!==void 0&&(S.outcomeDelivery=g),S.readiness=n.root===!0?"await":"launch";const Q=await ae(S,d===null?void 0:O=>F(O,"terminal",d),()=>{_!==null&&z(_)});return{status:201,body:y(Q.node.node_id)}}}s(fn,"handleCreate");function w(e,t){const n=e.query.getAll(t);if(n.length>1)throw u(`${t} must appear at most once`);return n[0]}s(w,"singleQueryValue");function Y(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw u(`${t} must be true or false`)}}s(Y,"optionalBoolean");function N(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw u(`${t} must be one of: ${n.join(", ")}`)}}s(N,"oneOf");function mn(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[_]of e.query)if(!t.has(_))throw u(`unknown nodes query parameter: ${_}`);const n=N(w(e,"status"),"status",["active","idle","done","dead","canceled"]),o=N(w(e,"lifecycle"),"lifecycle",["terminal","resident"]),r=w(e,"kind"),i=N(w(e,"mode"),"mode",["base","orchestrator"]),d=w(e,"profile_id"),a=w(e,"profile_prefix"),c=w(e,"parent"),l=Y(w(e,"top_level"),"top_level"),p=w(e,"under"),v=Y(w(e,"hanging"),"hanging"),g=N(w(e,"include"),"include",["activity"]);if(c!==void 0&&l===!0)throw u("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...o!==void 0?{lifecycle:o}:{},...r!==void 0?{kind:r}:{},...i!==void 0?{mode:i}:{},...d!==void 0?{profile_id:d}:{},...a!==void 0?{profile_prefix:a}:{},...c!==void 0?{parent:c}:{},...l!==void 0?{top_level:l}:{},...p!==void 0?{under:p}:{},...v!==void 0?{hanging:v}:{},...g!==void 0?{include:g}:{}}}s(mn,"parseListQuery");function pn(e){const t=mn(e);let n=t.status!==void 0?M({status:t.status}):M();if(t.lifecycle!==void 0&&(n=n.filter(i=>i.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(i=>i.kind===t.kind)),t.mode!==void 0&&(n=n.filter(i=>i.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(i=>i.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(i=>i.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(i=>i.parent===t.parent)),t.top_level===!0&&(n=n.filter(i=>i.parent===null)),t.under!==void 0){const i=new Set(fe(t.under));n=n.filter(d=>i.has(d.node_id))}t.hanging===!0&&(n=n.filter(i=>i.parent!==null&&b(i.parent)===null));const o=t.include==="activity"?he(n.map(i=>i.node_id)):null;return{status:200,body:n.map(i=>{const d=tn(i);if(o!==null){const a=Ue(i.node_id);d.activity={latest_report:a[0]??null,final_report:i.final_report===null?null:a.find(c=>ne(c.path)===i.final_report)??null,pending_human_count:o[i.node_id]??0}}return d})}}s(pn,"handleList");function hn(e){const t=e.params.id;return f(t),{status:200,body:y(t)}}s(hn,"handleDetail");async function wn(e){const t=e.params.id;f(t);const n=await be(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(r=>({name:r.name,description:r.description,source:r.source})),captured_at:T()}}}s(wn,"handleSnapshot");async function yn(e){const t=e.params.id,n=ke(t);if(n===null)throw R(`unknown node: ${t}`,{received:t});return{status:200,body:n}}s(yn,"handleSubject");function gn(e){for(const[i]of e.query)if(i!=="cursor"&&i!=="limit")throw u(`unknown messages query parameter: ${i}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw u("cursor must appear at most once");if(n.length>1)throw u("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const o=n[0],r=Number(o);if(!Number.isSafeInteger(r)||o==="")throw u("limit must be an integer from 1 through 500");return t.length===0?{limit:r}:{cursor:t[0],limit:r}}s(gn,"parseMessagesQuery");async function _n(e){const t=e.params.id,n=await ge(t,gn(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:T()}}}s(_n,"handleMessages");function bn(e){const t=e.params.id;f(t);const n=_e(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:T()}}}s(bn,"handleSession");async function vn(e){const t=e.params.id;return f(t),{status:200,body:{node_id:t,markdown:await ve(t)}}}s(vn,"handleTranscript");function kn(e){const t=e.params.id;f(t);const n=[{node_id:t,label:b(t)?.name??t,dir:P(t),self:!0,files:J(t)}];for(const o of E(t))n.push({node_id:o.node_id,label:b(o.node_id)?.name??o.node_id,dir:P(o.node_id),self:!1,files:J(o.node_id)});return{status:200,body:{node_id:t,roots:n}}}s(kn,"handleContext");function Sn(e){const t=e.params.id;f(t);const n=e.query.get("type"),o=ye(t,n!==null?[n]:void 0).map(i=>({ref:i.ref,source:i.source==="report"&&i.reportKind!==void 0?`report:${i.reportKind}`:i.source,ts:i.ts,title:i.title}));return{status:200,body:{node_id:t,artifacts:o}}}s(Sn,"handleArtifacts");async function On(e){const t=await se(e.params.id,e.ceiling===null?void 0:[...e.ceiling]);return{status:201,body:y(t.node.node_id)}}s(On,"handleFork");async function Nn(e){const t=e.params.id;f(t);const n=e.body,o=n?.resume??!0,r=n?.reopen??!1;Ae(t,r);const i=!o&&n?.cron_id!==void 0?Xe(n.cron_id):null,d=await de(t,{resume:o,capacity:"refuse",...i!==null?{wakeReason:Ze(i,"schedule_revive")}:{}}),a=b(t)?.status??"active";return{status:200,body:on(t,d,a)}}s(Nn,"handleRevive");async function Tn(e){const t=e.params.id;return{status:200,body:{newNodeId:(await $e(t))?.newNodeId??null}}}s(Tn,"handleRelaunchRoot");function $n(e){const t=e.params.id;f(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw u("caller_pid must be a positive integer when provided");const o=qe(),r=re(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...o===null?{}:{registerDetached:o.registerDetached}});return{status:200,body:nn(r)}}s($n,"handleClose");async function An(e){const t=e.params.id;f(t);const n=await Te(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}s(An,"handleRecycle");async function Pn(e){const t=e.params.id;return f(t),await L(t,{lifecycle:"terminal"}),{status:200,body:y(t)}}s(Pn,"handleDemote");async function Rn(e,t={}){const n=e.params.id,o=f(n),r=e.body??{};r.model!==void 0&&await K(o,{kind:r.kind??o.kind,mode:"orchestrator",lifecycle:r.resident===!0?"resident":o.lifecycle,model:r.model},t.modelRegistry);const i=await Oe(n,{...r.kind!==void 0?{kind:r.kind}:{},...r.resident===!0?{resident:!0}:{},...r.model!==void 0?{model:r.model}:{}}),d=x(i.meta,C(n));return d.roadmap_written=i.roadmapWritten,d.roadmap_path=i.roadmapPath,d.goal_path=i.goalPath,{status:200,body:d}}s(Rn,"handlePromote");async function xn(e,t={}){const n=e.params.id,o=f(n),r=e.body??{};r.model!==void 0&&await K(o,{kind:r.kind??o.kind,mode:r.promote===!0?"orchestrator":o.mode,lifecycle:o.lifecycle,model:r.model},t.modelRegistry);const i=r.note??"Refresh: continue against your roadmap or goal.";Pe(n,i);const d=await Ne(n,{...r.promote===!0?{promote:!0}:{},...r.kind!==void 0?{kind:r.kind}:{},...r.model!==void 0?{model:r.model}:{}});return{status:200,body:x(d.meta,C(n))}}s(xn,"handleYield");function Cn(e){const t=e.params.id;f(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw u("a wait requires a controller node id");const o=b(n.controller);if(o===null)throw R(`unknown controller: ${n.controller}`,{received:n.controller});if(o.status!=="active"&&o.status!=="idle")throw new h(422,"unprocessable",`controller ${n.controller} is ${o.status}`);return ue(t,n.controller),{status:200,body:y(t)}}s(Cn,"handleWait");async function Dn(){const e=await Se();return{status:200,body:{revived:[...e.revived],failed:[...e.failed],frozen:[...e.frozen]}}}s(Dn,"handleReviveAll");async function In(e,t={}){const n=e.params.id,o=e.body;let r;if(o===void 0)r={};else if(typeof o=="object"&&o!==null&&!Array.isArray(o))r=o;else throw new m({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:o,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(Object.prototype.hasOwnProperty.call(r,"cwd")){const d=r.cwd;if(typeof d!="string"||d==="")throw new m({error:"cwd_invalid",message:"cwd must be a non-empty string",received:d,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(r).some(l=>l!=="cwd"&&r[l]!==void 0))throw new m({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:r,field:"cwd",next:"Send cwd as the only config field."});const a=f(n);if(We().has(n)){const l=`${n} cannot repair its cwd while its broker is live`;throw new h(409,"cwd_node_live",l,{error:"cwd_node_live",message:l,received:d,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(a.fork_from!=null)throw new m({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${a.cwd}`,received:d,field:"cwd",next:`Restore ${a.cwd}, then revive the fork normally.`});if(a.managed_worktree?.state==="open")throw new m({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:d,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(D(a.cwd))throw new m({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${a.cwd}; cwd repair is not a relocation command`,received:d,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!te(d))throw new m({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${d}`,received:d,field:"cwd",next:"Send an absolute path."});const c=I(d);if(!D(c))throw new m({error:"cwd_missing",message:`cwd does not exist: ${c}`,received:d,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ee(c).isDirectory())throw new m({error:"cwd_not_a_directory",message:`cwd is not a directory: ${c}`,received:d,field:"cwd",next:"Send an existing absolute directory."})}catch(l){throw l instanceof m?l:new m({error:"cwd_missing",message:`cwd does not exist: ${c}`,received:d,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return me(()=>{A(n,{cwd:c}),pe(n)}),{status:200,body:y(n)}}let i=f(n);if(r.scopes!==void 0){const d=W(r.scopes);if(!d.every(a=>B(i.scopes,a)))throw new m({error:"unknown_scope",message:"scopes may only narrow the node's current list",received:d,field:"scopes",next:"Send only scopes the node already holds."});i=A(n,{scopes:d})}if(r.situational_context!==void 0&&oe(n,ie(r.situational_context)),r.model!==void 0){const d=Me(r.model),a=(await j(i.cwd,i.profile_id??null)).modelLadders,c=Ee(r.model,a);await $({kind:"concrete",spec:c},{cwd:i.cwd,profileId:i.profile_id??null},t.modelRegistry);const l=s(()=>{if(!c.includes("/"))throw u(`model must resolve to a provider/id spec: ${r.model}`);Ge(n,c,d)},"persistDormant");if(Fe(i))try{await ze(n,c,d)}catch(p){if(!(p instanceof je))throw p;l()}else l();i=f(n)}if(r.kind!==void 0||r.mode!==void 0||r.lifecycle!==void 0){r.kind!==void 0&&await H(r.kind);const d=r.kind??i.kind,a=r.mode??i.mode,c=r.lifecycle??i.lifecycle;let l;a==="orchestrator"&&!xe(n)&&(l=s(()=>{const p=Re(n);Ce(n,p!==null&&p.trim()!==""?{goal:p.trim()}:{})},"beforePersist")),i=await L(n,{...r.kind!==void 0?{kind:d}:{},...r.mode!==void 0?{mode:a}:{},...r.lifecycle!==void 0?{lifecycle:c}:{}},l)}return r.name!==void 0&&(i=A(n,{name:r.name}),i.window&&De(i.window,Qe(i))),{status:200,body:y(n)}}s(In,"handleConfig");async function H(e){const t=Object.keys((await j(process.cwd(),Z()||null)).kinds);if(!t.includes(e))throw u(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}s(H,"assertKindServer");const Rt=[{method:"POST",pattern:"/v1/nodes",scope:"act",handler:fn},{method:"GET",pattern:"/v1/nodes",handler:pn},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"act",handler:s(()=>Dn(),"handler")},{method:"GET",pattern:"/v1/nodes/:id",handler:hn},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:wn},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:yn},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:_n},{method:"GET",pattern:"/v1/nodes/:id/session",handler:bn},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:vn},{method:"GET",pattern:"/v1/nodes/:id/context",handler:kn},{method:"GET",pattern:"/v1/nodes/:id/artifacts",handler:Sn},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"act",handler:On},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"act",handler:Nn},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"act",handler:Tn},{method:"POST",pattern:"/v1/nodes/:id/close",handler:$n},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"act",handler:An},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"act",handler:Pn},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"act",handler:Rn},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"act",handler:xn},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Cn},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:In}];export{In as handleConfig,fn as handleCreate,On as handleFork,pn as handleList,Rn as handlePromote,xn as handleYield,Rt as nodeRoutes,Dt as resolveCreateKind};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var s=(r,e)=>c(r,"name",{value:e,configurable:!0});import{assertInstalledKind as h}from"../../../core/config.js";import{listNodesByProfile as u,shiftProfileNodeDeadlines as y}from"../../../core/canvas/canvas.js";import{shiftAutoBackgroundBashDeadlines as P}from"../../../core/bash-jobs.js";import{contextDir as _}from"../../../core/canvas/paths.js";import{boundFleet as b}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as v}from"../../../core/canvas/pid.js";import{usage as p}from"../../../core/errors.js";import{assertProfileProjects as I,createProfile as A,ensureRootProfile as D,listProfiles as l,loadProfileManifest as f,pauseProfile as T,resumeProfile as E,updateProfileMetadata as g}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as j}from"../../profile-delete.js";import{toProfileDTO as i}from"../map.js";const M="root";function N(r){const e=r.params.name,t=r.body??{};if(t.projects!==void 0&&I(t.projects),e===M)return{status:200,body:i(D())};const n=l().find(o=>o.manifest.name===e);if(n!==void 0)return{status:200,body:i(n)};t.default_kind!==void 0&&h(t.default_kind);const a=A(e,t.projects??[],{defaultKind:t.default_kind,metadata:t.metadata});return{status:200,body:i(a)}}s(N,"handleEnsure");function O(r){const e=f(r.params.name),t=r.body??{};if(typeof t!="object"||t===null||Array.isArray(t))throw p("profile metadata body must be an object",{field:"body"});const n=t,a=n.unset===void 0?[]:n.unset;if(!Array.isArray(a)||a.some(m=>typeof m!="string"))throw p("profile metadata `unset` must be an array of strings",{field:"unset"});const o=n.set===void 0?{}:n.set,d=g(e.profileId,o,a);return{status:200,body:i(d)}}s(O,"handleSetMetadata");function R(r){const e=f(r.params.name),t=T(e.profileId),n=u(e.profileId).filter(o=>o.status==="active"||o.status==="idle");if(n.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}};const a=b();for(const o of n){const d=a.get(o.node_id);if(d!==void 0){a.interruptForProfilePause(o.node_id,d.pid);continue}o.pi_pid!=null&&v(o.pi_pid,o.pi_pid_identity)==="alive"&&a.interruptForProfilePause(o.node_id,o.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}}}s(R,"handlePause");function k(r){const e=f(r.params.name),t=E(e.profileId);if(t.pausedAt!==null){const n=Date.parse(t.pausedAt);if(!Number.isNaN(n)){const a=Math.max(0,Date.now()-n);y(e.profileId,a);for(const o of u(e.profileId))o.status!=="dead"&&P(_(o.node_id),a)}}return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}}}s(k,"handleResume");function w(){return{status:200,body:l().map(i)}}s(w,"handleList");function F(r){const e=r.params.name;return{status:200,body:i(f(e))}}s(F,"handleGet");async function L(r){return j(r.params.name,r.body)}s(L,"handleDelete");const Q=[{method:"PUT",pattern:"/v1/profiles/:name",handler:N},{method:"POST",pattern:"/v1/profiles/:name/pause",handler:R},{method:"POST",pattern:"/v1/profiles/:name/resume",handler:k},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:O},{method:"DELETE",pattern:"/v1/profiles/:name",handler:L},{method:"GET",pattern:"/v1/profiles",handler:w},{method:"GET",pattern:"/v1/profiles/:name",handler:F}];export{Q as profileRoutes};
1
+ var c=Object.defineProperty;var s=(r,e)=>c(r,"name",{value:e,configurable:!0});import{assertInstalledKind as h}from"../../../core/config.js";import{listNodesByProfile as u,shiftProfileNodeDeadlines as y}from"../../../core/canvas/canvas.js";import{shiftAutoBackgroundBashDeadlines as P}from"../../../core/bash-jobs.js";import{contextDir as _}from"../../../core/canvas/paths.js";import{boundFleet as b}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as v}from"../../../core/canvas/pid.js";import{usage as l}from"../../../core/errors.js";import{assertProfileProjects as I,createProfile as A,ensureRootProfile as O,listProfiles as p,loadProfileManifest as f,pauseProfile as D,resumeProfile as T,updateProfileMetadata as w}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as E}from"../../profile-delete.js";import{toProfileDTO as i}from"../map.js";const g="root";function j(r){const e=r.params.name,t=r.body??{};if(t.projects!==void 0&&I(t.projects),e===g)return{status:200,body:i(O())};const n=p().find(o=>o.manifest.name===e);if(n!==void 0)return{status:200,body:i(n)};t.default_kind!==void 0&&h(t.default_kind);const a=A(e,t.projects??[],{defaultKind:t.default_kind,metadata:t.metadata});return{status:200,body:i(a)}}s(j,"handleEnsure");function M(r){const e=f(r.params.name),t=r.body??{};if(typeof t!="object"||t===null||Array.isArray(t))throw l("profile metadata body must be an object",{field:"body"});const n=t,a=n.unset===void 0?[]:n.unset;if(!Array.isArray(a)||a.some(m=>typeof m!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const o=n.set===void 0?{}:n.set,d=w(e.profileId,o,a);return{status:200,body:i(d)}}s(M,"handleSetMetadata");function N(r){const e=f(r.params.name),t=D(e.profileId),n=u(e.profileId).filter(o=>o.status==="active"||o.status==="idle");if(n.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}};const a=b();for(const o of n){const d=a.get(o.node_id);if(d!==void 0){a.interruptForProfilePause(o.node_id,d.pid);continue}o.pi_pid!=null&&v(o.pi_pid,o.pi_pid_identity)==="alive"&&a.interruptForProfilePause(o.node_id,o.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}}}s(N,"handlePause");function R(r){const e=f(r.params.name),t=T(e.profileId);if(t.pausedAt!==null){const n=Date.parse(t.pausedAt);if(!Number.isNaN(n)){const a=Math.max(0,Date.now()-n);y(e.profileId,a);for(const o of u(e.profileId))o.status!=="dead"&&P(_(o.node_id),a)}}return{status:200,body:{profile_id:e.profileId,paused_at:t.manifest.paused_at}}}s(R,"handleResume");function k(){return{status:200,body:p().map(i)}}s(k,"handleList");function F(r){const e=r.params.name;return{status:200,body:i(f(e))}}s(F,"handleGet");async function L(r){return E(r.params.name,r.body)}s(L,"handleDelete");const Q=[{method:"PUT",pattern:"/v1/profiles/:name",handler:j},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:N},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:R},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",ownerOnly:!0,handler:M},{method:"DELETE",pattern:"/v1/profiles/:name",ownerOnly:!0,handler:L},{method:"GET",pattern:"/v1/profiles",handler:k},{method:"GET",pattern:"/v1/profiles/:name",handler:F}];export{Q as profileRoutes};
@@ -13,4 +13,4 @@ Code: ${e.code}
13
13
  Retryable: ${e.retryable?"yes":"no"}
14
14
 
15
15
  Declined marker: ${t}
16
- `}s(ee,"declineReportBody");const T=1024,N=64;function te(t){if(typeof t!="object"||t===null)throw c("a result submission requires a JSON body { value } or { decline, code, retryable }");const e=Object.hasOwn(t,"value"),r=Object.hasOwn(t,"decline");if(e&&r)throw c("a result submission carries either { value } or { decline, code, retryable }, not both");if(r){const{decline:n,code:i,retryable:o}=t;if(typeof n!="string"||n.trim()==="")throw new d({error:"missing_decline_reason",message:"A decline needs a reason.",next:'Rerun with `--decline "<one sentence on why the schema cannot be honestly satisfied>" --code <token>`.'});if(n.length>T)throw new d({error:"decline_reason_too_long",message:`A decline reason is at most ${T} characters (got ${n.length}).`,next:"Keep the reason to one plain sentence; put any detail in an artifact and name its path."});if(typeof i!="string"||i.trim()===""||/\s/.test(i.trim())||i.trim().length>N)throw new d({error:"invalid_decline_code",message:`A decline needs a code: one whitespace-free token of at most ${N} characters naming the decline class.`,next:"Rerun with `--code <token>` \u2014 the token your requester documented for this case."});if(typeof o!="boolean")throw c("a decline carries `retryable` as a boolean");return{declined:{reason:n.trim(),code:i.trim(),retryable:o}}}if(!e)throw c("a result submission requires a JSON body { value } or { decline, code, retryable }");return{value:t.value}}s(te,"parseSubmitBody");async function re(t){const e=t.params.id;g(e);const r=te(t.body),n=k(e);if(n.state==="absent")throw new d({error:"no_output_request",message:"No structured output is currently requested of this node.",next:"Nothing to submit here \u2014 continue working, or finish with `crtr push final`."});if(n.state==="invalid")throw new d({error:"invalid_output_request",message:`The structured-output request file is invalid: ${n.error}`,next:`Have the requester re-issue the request, or remove ${G(e)} and finish with \`crtr push final\`.`});const{mode:i,schema:o}=n.request;let u;if("value"in r)try{u=await K(o,r.value)}catch(h){throw new d({error:"result_schema_mismatch",message:`the submitted result does not match the requested schema: ${h.message}`,next:'Fix the listed fields and rerun `crtr push result`; if the schema cannot be honestly satisfied, rerun with `--decline "<reason>" --code <token>`.'})}const l=i==="terminal"?f(e)?.status:void 0,p=i==="terminal"?await $(e):void 0;let a,m,w;if("declined"in r){const{declined:h}=r;if(a=V(e,{mode:i,...h,at:new Date().toISOString()}),m=ee(a,h),i==="terminal"){const x={schema:"crtr.node-outcome-detail/v1",message:h.reason,declined:h};w={kind:"failure",reason:"declined",detailJson:JSON.stringify(x)}}}else a=Q(e,u),m=Z(a,u);const y=await q(e,{tier:i==="terminal"?"final":"update",body:m},w);X(e);const _=i==="terminal"&&l!==void 0?{from:l,to:f(e)?.status??"done"}:void 0,v=b(e).find(h=>h.path===y.reportPath);return v!==void 0&&O.report(e,v),{status:200,body:{mode:i,result_path:a,report_path:y.reportPath,notified:[...y.deliveredTo],..."declined"in r?{declined:r.declined}:{},..._===void 0?{}:{transitioned:_},...p===void 0?{}:{worktree_auto_dropped:!0,worktree_auto_dropped_path:p}}}}s(re,"handleSubmitResult");async function q(t,e,r){try{return await F(t,{kind:e.tier,body:e.body,...e.delivery_tier===void 0?{}:{deliveryTier:e.delivery_tier},...r===void 0?{}:{outcome:r}})}catch(n){throw n instanceof S&&n.code==="already_finalized"?new d({error:"already_finalized",message:"This node already submitted its canonical final result.",next:"Push an update with the new information, then stop."}):n instanceof S&&n.code==="finalization_forbidden"?new d({error:"finalization_forbidden",message:"A canceled or dead node cannot submit a canonical final result.",next:"Do not push final from this node."}):n}}s(q,"pushOrRethrow");function ne(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})$/);return e===null?t:`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}`}s(ne,"compactToIso");function b(t){const e=B(t);let r;try{r=E(e).filter(i=>i.endsWith(".md"))}catch{r=[]}const n=[];for(const i of r){const o=I(e,i),u=A(o,"utf8"),{data:l,body:p}=W(u),a=i.match(/^([0-9]{8}T[0-9]{6})-(\w+)\.md$/),m=(typeof l?.kind=="string"?l.kind:void 0)??(a?a[2]:"update"),w=(typeof l?.ts=="string"?l.ts:void 0)??(a?ne(a[1]):new Date(C(o).mtimeMs).toISOString());n.push({path:o,tier:m,body:p.trim(),created:w})}return n.sort((i,o)=>i.created<o.created?1:i.created>o.created?-1:0),n}s(b,"reportsForNode");function ie(t){const e=t.params.id;g(e);const r=t.query.get("tier"),n=t.query.get("limit"),i=n!==null?Number(n):void 0;let o=b(e);return r!==null&&(o=o.filter(u=>u.tier===r)),i!==void 0&&Number.isFinite(i)&&i>=0&&(o=o.slice(0,i)),{status:200,body:o}}s(ie,"handleList");const _e=[{method:"POST",pattern:"/v1/nodes/:id/reports",handler:Y},{method:"GET",pattern:"/v1/nodes/:id/reports",handler:ie},{method:"POST",pattern:"/v1/nodes/:id/result",handler:re}];export{_e as reportRoutes,b as reportsForNode};
16
+ `}s(ee,"declineReportBody");const T=1024,N=64;function te(t){if(typeof t!="object"||t===null)throw c("a result submission requires a JSON body { value } or { decline, code, retryable }");const e=Object.hasOwn(t,"value"),r=Object.hasOwn(t,"decline");if(e&&r)throw c("a result submission carries either { value } or { decline, code, retryable }, not both");if(r){const{decline:n,code:i,retryable:o}=t;if(typeof n!="string"||n.trim()==="")throw new d({error:"missing_decline_reason",message:"A decline needs a reason.",next:'Rerun with `--decline "<one sentence on why the schema cannot be honestly satisfied>" --code <token>`.'});if(n.length>T)throw new d({error:"decline_reason_too_long",message:`A decline reason is at most ${T} characters (got ${n.length}).`,next:"Keep the reason to one plain sentence; put any detail in an artifact and name its path."});if(typeof i!="string"||i.trim()===""||/\s/.test(i.trim())||i.trim().length>N)throw new d({error:"invalid_decline_code",message:`A decline needs a code: one whitespace-free token of at most ${N} characters naming the decline class.`,next:"Rerun with `--code <token>` \u2014 the token your requester documented for this case."});if(typeof o!="boolean")throw c("a decline carries `retryable` as a boolean");return{declined:{reason:n.trim(),code:i.trim(),retryable:o}}}if(!e)throw c("a result submission requires a JSON body { value } or { decline, code, retryable }");return{value:t.value}}s(te,"parseSubmitBody");async function re(t){const e=t.params.id;g(e);const r=te(t.body),n=k(e);if(n.state==="absent")throw new d({error:"no_output_request",message:"No structured output is currently requested of this node.",next:"Nothing to submit here \u2014 continue working, or finish with `crtr push final`."});if(n.state==="invalid")throw new d({error:"invalid_output_request",message:`The structured-output request file is invalid: ${n.error}`,next:`Have the requester re-issue the request, or remove ${G(e)} and finish with \`crtr push final\`.`});const{mode:i,schema:o}=n.request;let u;if("value"in r)try{u=await K(o,r.value)}catch(h){throw new d({error:"result_schema_mismatch",message:`the submitted result does not match the requested schema: ${h.message}`,next:'Fix the listed fields and rerun `crtr push result`; if the schema cannot be honestly satisfied, rerun with `--decline "<reason>" --code <token>`.'})}const l=i==="terminal"?f(e)?.status:void 0,p=i==="terminal"?await $(e):void 0;let a,m,w;if("declined"in r){const{declined:h}=r;if(a=V(e,{mode:i,...h,at:new Date().toISOString()}),m=ee(a,h),i==="terminal"){const x={schema:"crtr.node-outcome-detail/v1",message:h.reason,declined:h};w={kind:"failure",reason:"declined",detailJson:JSON.stringify(x)}}}else a=Q(e,u),m=Z(a,u);const y=await q(e,{tier:i==="terminal"?"final":"update",body:m},w);X(e);const _=i==="terminal"&&l!==void 0?{from:l,to:f(e)?.status??"done"}:void 0,v=b(e).find(h=>h.path===y.reportPath);return v!==void 0&&O.report(e,v),{status:200,body:{mode:i,result_path:a,report_path:y.reportPath,notified:[...y.deliveredTo],..."declined"in r?{declined:r.declined}:{},..._===void 0?{}:{transitioned:_},...p===void 0?{}:{worktree_auto_dropped:!0,worktree_auto_dropped_path:p}}}}s(re,"handleSubmitResult");async function q(t,e,r){try{return await F(t,{kind:e.tier,body:e.body,...e.delivery_tier===void 0?{}:{deliveryTier:e.delivery_tier},...r===void 0?{}:{outcome:r}})}catch(n){throw n instanceof S&&n.code==="already_finalized"?new d({error:"already_finalized",message:"This node already submitted its canonical final result.",next:"Push an update with the new information, then stop."}):n instanceof S&&n.code==="finalization_forbidden"?new d({error:"finalization_forbidden",message:"A canceled or dead node cannot submit a canonical final result.",next:"Do not push final from this node."}):n}}s(q,"pushOrRethrow");function ne(t){const e=t.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})$/);return e===null?t:`${e[1]}-${e[2]}-${e[3]}T${e[4]}:${e[5]}:${e[6]}`}s(ne,"compactToIso");function b(t){const e=B(t);let r;try{r=E(e).filter(i=>i.endsWith(".md"))}catch{r=[]}const n=[];for(const i of r){const o=I(e,i),u=A(o,"utf8"),{data:l,body:p}=W(u),a=i.match(/^([0-9]{8}T[0-9]{6})-(\w+)\.md$/),m=(typeof l?.kind=="string"?l.kind:void 0)??(a?a[2]:"update"),w=(typeof l?.ts=="string"?l.ts:void 0)??(a?ne(a[1]):new Date(C(o).mtimeMs).toISOString());n.push({path:o,tier:m,body:p.trim(),created:w})}return n.sort((i,o)=>i.created<o.created?1:i.created>o.created?-1:0),n}s(b,"reportsForNode");function ie(t){const e=t.params.id;g(e);const r=t.query.get("tier"),n=t.query.get("limit"),i=n!==null?Number(n):void 0;let o=b(e);return r!==null&&(o=o.filter(u=>u.tier===r)),i!==void 0&&Number.isFinite(i)&&i>=0&&(o=o.slice(0,i)),{status:200,body:o}}s(ie,"handleList");const _e=[{method:"POST",pattern:"/v1/nodes/:id/reports",ownerOnly:!0,handler:Y},{method:"GET",pattern:"/v1/nodes/:id/reports",handler:ie},{method:"POST",pattern:"/v1/nodes/:id/result",handler:re}];export{_e as reportRoutes,b as reportsForNode};
@@ -1 +1 @@
1
- var _=Object.defineProperty;var d=(n,e)=>_(n,"name",{value:e,configurable:!0});import{isSafeNodeId as f}from"../../../core/canvas/paths.js";import{getNode as y}from"../../../core/canvas/canvas.js";import{assertScope as g}from"../../../core/scopes.js";import{createReview as R}from"../../../core/review/birth.js";import{readAnchorBase as k,listReviews as q,requireVisibleReview as w}from"../../../core/review/store.js";import{cancelReview as S,submitReviewApproval as E}from"../../review/finish.js";import{toFeedbackResultDTO as T,toReviewDTO as I}from"../map.js";import{invalidRequest as C,objectBody as v,optionalString as l,requireParam as D,requiredString as h}from"./validate.js";const A=new Set(["open","approved","canceled"]),O=["origin_kind","origin_node_id","file","idempotency_key","subtitle","output_path"],L=["reason","actor","disposition"];function a(n){C("review request",n)}d(a,"invalidRequest");function p(n,e){return D(n,"review_id","must be a safe review id",f,e)}d(p,"requireReviewId");function c(n){return{...I(n,n.state==="approved"?{result_path:`${n.review_dir}/result.json`}:{}),review_dir:n.review_dir}}d(c,"toReviewResponseDTO");function P(n){const e=[],i=v(n.body,O,e),o=i.origin_kind,t=o==="ticket"||o==="inline"?o:void 0;t===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=h(i,"origin_node_id",e);r!==void 0&&!f(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const s=h(i,"file",e),u=h(i,"idempotency_key",e);u!==void 0&&u.length>128&&e.push({field:"idempotency_key",problem:"must be at most 128 characters",received:u});const m=l(i,"subtitle",e),b=l(i,"output_path",e);return t==="ticket"&&m===void 0&&i.subtitle===void 0&&e.push({field:"subtitle",problem:"is required for ticket reviews"}),t==="inline"&&i.subtitle!==void 0&&e.push({field:"subtitle",problem:"is only allowed for ticket reviews",received:i.subtitle}),t==="inline"&&i.output_path!==void 0&&e.push({field:"output_path",problem:"is only allowed for ticket reviews",received:i.output_path}),(e.length>0||t===void 0||r===void 0||!f(r)||s===void 0||u===void 0||u.length>128)&&a(e),{origin_kind:t,origin_node_id:r,file:s,idempotency_key:u,...m===void 0?{}:{subtitle:m},...b===void 0?{}:{output_path:b}}}d(P,"parseCreate");function j(n){const e=[],i={},o=new Set(["state","origin_node_id","file"]);for(const[t,r]of n.query.entries())o.has(t)||e.push({field:t,problem:"is not allowed",received:r});for(const t of o){const r=n.query.getAll(t);if(r.length>1){e.push({field:t,problem:"must appear at most once",received:r});continue}const s=r[0];s!==void 0&&(t==="state"?A.has(s)?i.state=s:e.push({field:t,problem:"must be open, approved, or canceled",received:s}):t==="origin_node_id"?f(s)?i.origin_node_id=s:e.push({field:t,problem:"must be a safe node id",received:s}):s===""?e.push({field:t,problem:"must be a non-empty string",received:s}):i.file=s)}return e.length>0&&a(e),i}d(j,"parseList");function B(n,e){const i=n.body===void 0?{}:v(n.body,L,e),o=l(i,"reason",e),t=l(i,"actor",e),r=l(i,"disposition",e);return r!==void 0&&r!=="canceled"&&r!=="dismissed"&&e.push({field:"disposition",problem:'must be "canceled" or "dismissed"',received:r}),{...o===void 0?{}:{reason:o},...t===void 0?{}:{actor:t},...r==="canceled"||r==="dismissed"?{disposition:r}:{}}}d(B,"parseCancel");function F(n,e){v(n.body,[],e)}d(F,"requireEmptyBody");async function G(n){const e=P(n),i=y(e.origin_node_id);i!==null&&g(i,"ask");const o=await R(e);return{status:200,body:c(o)}}d(G,"handleCreate");function N(n){const e=j(n);return{status:200,body:{reviews:q(e).map(c)}}}d(N,"handleList");function V(n){const e=[],i=p(n,e);return(e.length>0||i===void 0)&&a(e),{status:200,body:c(w(i))}}d(V,"handleRead");async function $(n){const e=[],i=p(n,e);F(n,e),(e.length>0||i===void 0)&&a(e);const o=await E(i);return{status:200,body:o.outcome==="awaiting_companion"?{review:c(o.record),outcome:o.outcome}:{review:c(o.record),result:T(o.result),outcome:o.outcome}}}d($,"handleSubmit");async function K(n){const e=[],i=p(n,e),o=B(n,e);(e.length>0||i===void 0)&&a(e);const t=await S(i,o);return{status:200,body:{review:c(t.record),outcome:t.outcome}}}d(K,"handleCancel");function W(n){const e=[],i=p(n,e);(e.length>0||i===void 0)&&a(e);const o=w(i),t=k(o.review_id);if(t===null)throw new Error(`review anchor base is missing: ${o.review_id}`);return{status:200,body:{review_id:o.review_id,anchor_base_sha256:t.sha256,anchor_base_text:new TextDecoder("utf-8",{fatal:!0}).decode(t.bytes),file:o.file}}}d(W,"handleDocument");const x=[{method:"POST",pattern:"/v1/human/reviews",handler:G},{method:"GET",pattern:"/v1/human/reviews",handler:N},{method:"GET",pattern:"/v1/human/reviews/:review_id",handler:V},{method:"POST",pattern:"/v1/human/reviews/:review_id/submit",handler:$},{method:"POST",pattern:"/v1/human/reviews/:review_id/cancel",handler:K},{method:"GET",pattern:"/v1/human/reviews/:review_id/document",handler:W}];export{x as reviewRoutes};
1
+ var _=Object.defineProperty;var d=(n,e)=>_(n,"name",{value:e,configurable:!0});import{isSafeNodeId as f}from"../../../core/canvas/paths.js";import{getNode as y}from"../../../core/canvas/canvas.js";import{assertScope as g}from"../../../core/scopes.js";import{createReview as k}from"../../../core/review/birth.js";import{readAnchorBase as R,listReviews as q,requireVisibleReview as w}from"../../../core/review/store.js";import{cancelReview as S,submitReviewApproval as E}from"../../review/finish.js";import{toFeedbackResultDTO as T,toReviewDTO as I}from"../map.js";import{invalidRequest as C,objectBody as v,optionalString as l,requireParam as D,requiredString as h}from"./validate.js";const A=new Set(["open","approved","canceled"]),O=["origin_kind","origin_node_id","file","idempotency_key","subtitle","output_path"],L=["reason","actor","disposition"];function a(n){C("review request",n)}d(a,"invalidRequest");function p(n,e){return D(n,"review_id","must be a safe review id",f,e)}d(p,"requireReviewId");function c(n){return{...I(n,n.state==="approved"?{result_path:`${n.review_dir}/result.json`}:{}),review_dir:n.review_dir}}d(c,"toReviewResponseDTO");function P(n){const e=[],i=v(n.body,O,e),o=i.origin_kind,t=o==="ticket"||o==="inline"?o:void 0;t===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=h(i,"origin_node_id",e);r!==void 0&&!f(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const s=h(i,"file",e),u=h(i,"idempotency_key",e);u!==void 0&&u.length>128&&e.push({field:"idempotency_key",problem:"must be at most 128 characters",received:u});const m=l(i,"subtitle",e),b=l(i,"output_path",e);return t==="ticket"&&m===void 0&&i.subtitle===void 0&&e.push({field:"subtitle",problem:"is required for ticket reviews"}),t==="inline"&&i.subtitle!==void 0&&e.push({field:"subtitle",problem:"is only allowed for ticket reviews",received:i.subtitle}),t==="inline"&&i.output_path!==void 0&&e.push({field:"output_path",problem:"is only allowed for ticket reviews",received:i.output_path}),(e.length>0||t===void 0||r===void 0||!f(r)||s===void 0||u===void 0||u.length>128)&&a(e),{origin_kind:t,origin_node_id:r,file:s,idempotency_key:u,...m===void 0?{}:{subtitle:m},...b===void 0?{}:{output_path:b}}}d(P,"parseCreate");function j(n){const e=[],i={},o=new Set(["state","origin_node_id","file"]);for(const[t,r]of n.query.entries())o.has(t)||e.push({field:t,problem:"is not allowed",received:r});for(const t of o){const r=n.query.getAll(t);if(r.length>1){e.push({field:t,problem:"must appear at most once",received:r});continue}const s=r[0];s!==void 0&&(t==="state"?A.has(s)?i.state=s:e.push({field:t,problem:"must be open, approved, or canceled",received:s}):t==="origin_node_id"?f(s)?i.origin_node_id=s:e.push({field:t,problem:"must be a safe node id",received:s}):s===""?e.push({field:t,problem:"must be a non-empty string",received:s}):i.file=s)}return e.length>0&&a(e),i}d(j,"parseList");function B(n,e){const i=n.body===void 0?{}:v(n.body,L,e),o=l(i,"reason",e),t=l(i,"actor",e),r=l(i,"disposition",e);return r!==void 0&&r!=="canceled"&&r!=="dismissed"&&e.push({field:"disposition",problem:'must be "canceled" or "dismissed"',received:r}),{...o===void 0?{}:{reason:o},...t===void 0?{}:{actor:t},...r==="canceled"||r==="dismissed"?{disposition:r}:{}}}d(B,"parseCancel");function F(n,e){v(n.body,[],e)}d(F,"requireEmptyBody");async function G(n){const e=P(n),i=y(e.origin_node_id);i!==null&&g(i,"ask");const o=await k(e);return{status:200,body:c(o)}}d(G,"handleCreate");function N(n){const e=j(n);return{status:200,body:{reviews:q(e).map(c)}}}d(N,"handleList");function V(n){const e=[],i=p(n,e);return(e.length>0||i===void 0)&&a(e),{status:200,body:c(w(i))}}d(V,"handleRead");async function $(n){const e=[],i=p(n,e);F(n,e),(e.length>0||i===void 0)&&a(e);const o=await E(i);return{status:200,body:o.outcome==="awaiting_companion"?{review:c(o.record),outcome:o.outcome}:{review:c(o.record),result:T(o.result),outcome:o.outcome}}}d($,"handleSubmit");async function K(n){const e=[],i=p(n,e),o=B(n,e);(e.length>0||i===void 0)&&a(e);const t=await S(i,o);return{status:200,body:{review:c(t.record),outcome:t.outcome}}}d(K,"handleCancel");function W(n){const e=[],i=p(n,e);(e.length>0||i===void 0)&&a(e);const o=w(i),t=R(o.review_id);if(t===null)throw new Error(`review anchor base is missing: ${o.review_id}`);return{status:200,body:{review_id:o.review_id,anchor_base_sha256:t.sha256,anchor_base_text:new TextDecoder("utf-8",{fatal:!0}).decode(t.bytes),file:o.file}}}d(W,"handleDocument");const x=[{method:"POST",pattern:"/v1/human/reviews",scope:"ask",handler:G},{method:"GET",pattern:"/v1/human/reviews",handler:N},{method:"GET",pattern:"/v1/human/reviews/:review_id",handler:V},{method:"POST",pattern:"/v1/human/reviews/:review_id/submit",handler:$},{method:"POST",pattern:"/v1/human/reviews/:review_id/cancel",handler:K},{method:"GET",pattern:"/v1/human/reviews/:review_id/document",handler:W}];export{x as reviewRoutes};
@@ -1,2 +1,2 @@
1
- import type { RouteTable } from '../router.js';
1
+ import { type RouteTable } from '../router.js';
2
2
  export declare const worktreeRoutes: RouteTable;
@@ -1 +1 @@
1
- var o=Object.defineProperty;var t=(e,n)=>o(e,"name",{value:n,configurable:!0});import{closeManagedWorktreeAsync as a}from"../../../core/worktree-close.js";import{abandonManagedWorktreeAsync as d}from"../../../core/worktree-mutation-async.js";import{listQuarantinedManagedWorktrees as i}from"../../../core/worktree-quarantine.js";import{usage as s}from"../../../core/errors.js";async function y(e){const n=e.params.id;return{status:200,body:await a(n)}}t(y,"handleWorktreeClose");async function m(e){const n=e.body?.by,r=typeof n=="string"?n.trim():"";if(r==="")throw s("abandon requires a non-empty invoking identity",{received:e.body,next:"Pass the invoking node id or human identity."});return{status:200,body:await d(e.params.id,r)}}t(m,"handleWorktreeAbandon");async function u(){return{status:200,body:await i()}}t(u,"handleQuarantinedWorktrees");const l=[{method:"POST",pattern:"/v1/nodes/:id/worktree/close",handler:y},{method:"POST",pattern:"/v1/nodes/:id/worktree/abandon",handler:m},{method:"GET",pattern:"/v1/worktrees/quarantined",handler:u}];export{l as worktreeRoutes};
1
+ var o=Object.defineProperty;var t=(e,n)=>o(e,"name",{value:n,configurable:!0});import{closeManagedWorktreeAsync as a}from"../../../core/worktree-close.js";import{abandonManagedWorktreeAsync as d}from"../../../core/worktree-mutation-async.js";import{listQuarantinedManagedWorktrees as i}from"../../../core/worktree-quarantine.js";import{usage as s}from"../../../core/errors.js";import{ownerOnly as m}from"../router.js";async function y(e){const n=e.params.id;return{status:200,body:await a(n)}}t(y,"handleWorktreeClose");async function u(e){const n=e.body?.by,r=typeof n=="string"?n.trim():"";if(r==="")throw s("abandon requires a non-empty invoking identity",{received:e.body,next:"Pass the invoking node id or human identity."});return{status:200,body:await d(e.params.id,r)}}t(u,"handleWorktreeAbandon");async function c(){return{status:200,body:await i()}}t(c,"handleQuarantinedWorktrees");const w=m([{method:"POST",pattern:"/v1/nodes/:id/worktree/close",handler:y},{method:"POST",pattern:"/v1/nodes/:id/worktree/abandon",handler:u},{method:"GET",pattern:"/v1/worktrees/quarantined",handler:c}]);export{w as worktreeRoutes};
@@ -1,4 +1,13 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { ApiError } from '../../api/errors.js';
3
+ /** What the caller's bearer token may reach: `null` is the owner (every scope,
4
+ * every route); a list is the ceiling minted by `crtr sys connect --scopes`. */
5
+ export type Ceiling = readonly string[] | null;
6
+ /** Throw the 403 `scope_denied` a scoped bearer earns when its ceiling lacks
7
+ * `scope`. The owner (`null`) always passes. */
8
+ export declare function assertCeiling(ceiling: Ceiling, scope: string): void;
9
+ /** The 403 `owner_only` a scoped bearer earns on a route no ceiling reaches. */
10
+ export declare function ownerOnlyError(): ApiError;
2
11
  /** The request view a handler receives: the resolved route params, parsed
3
12
  * query, parsed JSON body, and the raw req/res for the rare handler that needs
4
13
  * them (streaming, headers). Everything a handler mutates it does through the
@@ -14,6 +23,8 @@ export interface RequestContext {
14
23
  query: URLSearchParams;
15
24
  /** Parsed JSON request body, or `undefined` when there was no body. */
16
25
  body: unknown;
26
+ /** The caller's scope ceiling — `null` for the owner token or the unix socket. */
27
+ ceiling: Ceiling;
17
28
  req: IncomingMessage;
18
29
  res: ServerResponse;
19
30
  }
@@ -36,10 +47,16 @@ export interface RouteDef {
36
47
  method: string;
37
48
  pattern: string;
38
49
  handler: RouteHandler;
50
+ /** A scoped bearer token never reaches this route (403 `owner_only`). */
51
+ ownerOnly?: true;
52
+ /** The scope the caller's ceiling must hold (403 `scope_denied` otherwise). */
53
+ scope?: string;
39
54
  }
40
55
  /** The flat route table the handler authors (A-7) build up and hand to the
41
56
  * server (A-9). */
42
57
  export type RouteTable = RouteDef[];
58
+ /** Mark every route in `table` owner-only. */
59
+ export declare function ownerOnly(table: RouteTable): RouteTable;
43
60
  export declare class Router {
44
61
  private readonly routes;
45
62
  /** Register one route. Returns `this` for chaining. */
@@ -51,10 +68,12 @@ export declare class Router {
51
68
  match(method: string, path: string): {
52
69
  handler: RouteHandler;
53
70
  params: Record<string, string>;
71
+ ownerOnly: boolean;
72
+ scope: string | undefined;
54
73
  } | null;
55
74
  /** Resolve the JSON body, dispatch to the matched handler, and write the
56
75
  * response. Every failure path — no route, bad JSON, a handler throw — is
57
76
  * turned into a JSON `ErrorBody` (map.ts §8); this method never throws and
58
77
  * never leaves the daemon crashed. */
59
- handle(req: IncomingMessage, res: ServerResponse): Promise<void>;
78
+ handle(req: IncomingMessage, res: ServerResponse, ceiling: Ceiling): Promise<void>;
60
79
  }
@@ -1 +1 @@
1
- var g=Object.defineProperty;var s=(e,t)=>g(e,"name",{value:t,configurable:!0});import{toErrorBody as w}from"./map.js";import{emitEvent as E}from"../../core/events/emit.js";const u=4*1024*1024;class v{static{s(this,"Router")}routes=[];register(t){return this.routes.push({method:t.method.toUpperCase(),segments:h(t.pattern),handler:t.handler}),this}registerAll(t){for(const n of t)this.register(n);return this}match(t,n){const r=t.toUpperCase(),o=h(n);for(const a of this.routes){if(a.method!==r)continue;const i=b(a.segments,o);if(i!==null)return{handler:a.handler,params:i}}return null}async handle(t,n){try{const r=new URL(t.url??"/","http://127.0.0.1"),o=(t.method??"GET").toUpperCase(),a=this.match(o,r.pathname);if(a===null){p(n,404,"not_found",`no route for ${o} ${r.pathname}`);return}let i;try{i=await S(t)}catch(d){const c=d instanceof f?"payload_too_large":"invalid_request";p(n,c==="payload_too_large"?413:400,c,d.message);return}const m={method:o,path:r.pathname,params:a.params,query:r.searchParams,body:i,req:t,res:n},y=await a.handler(m);B(n,y)}catch(r){const{status:o,body:a}=w(r);o>=500&&E({event:"api.request.failed",level:"error",error:r instanceof Error?r:new Error(String(r)),fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),l(n,o,a)}}}function h(e){return e.split("/").filter(t=>t.length>0)}s(h,"splitPath");function b(e,t){if(e.length!==t.length)return null;const n={};for(let r=0;r<e.length;r++){const o=e[r],a=t[r];if(o.startsWith(":"))n[o.slice(1)]=decodeURIComponent(a);else if(o!==a)return null}return n}s(b,"matchSegments");class f extends Error{static{s(this,"BodyTooLargeError")}}async function S(e){const t=[];let n=0;for await(const o of e){const a=o;if(n+=a.length,n>u)throw new f(`request body exceeds ${u} bytes`);t.push(a)}if(n===0)return;const r=Buffer.concat(t).toString("utf8").trim();if(r!=="")try{return JSON.parse(r)}catch{throw new Error("request body is not valid JSON")}}s(S,"readJsonBody");function B(e,t){if(e.headersSent)return;const n={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,n),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,n),e.end();return}n["content-type"]===void 0&&(n["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,n),e.end(JSON.stringify(t.body))}s(B,"writeResult");function l(e,t,n){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(n))}s(l,"writeJson");function p(e,t,n,r){l(e,t,{error:{code:n,message:r}})}s(p,"writeError");export{v as Router};
1
+ var g=Object.defineProperty;var a=(e,t)=>g(e,"name",{value:t,configurable:!0});import{toErrorBody as E}from"./map.js";import{emitEvent as O}from"../../core/events/emit.js";import{scopeAllowed as b,ScopeDeniedError as S}from"../../core/scopes.js";import{ApiError as _}from"../../api/errors.js";function x(e,t){if(!b(e,t))throw new S("the bearer token",t)}a(x,"assertCeiling");function B(){return new _(403,"owner_only","this operation is owner-only; a scoped token does not reach it")}a(B,"ownerOnlyError");function R(e){return e.map(t=>({...t,ownerOnly:!0}))}a(R,"ownerOnly");const h=4*1024*1024;class T{static{a(this,"Router")}routes=[];register(t){return this.routes.push({method:t.method.toUpperCase(),segments:f(t.pattern),handler:t.handler,ownerOnly:t.ownerOnly===!0,scope:t.scope}),this}registerAll(t){for(const n of t)this.register(n);return this}match(t,n){const s=t.toUpperCase(),r=f(n);for(const o of this.routes){if(o.method!==s)continue;const i=C(o.segments,r);if(i!==null)return{handler:o.handler,params:i,ownerOnly:o.ownerOnly,scope:o.scope}}return null}async handle(t,n,s){try{const r=new URL(t.url??"/","http://127.0.0.1"),o=(t.method??"GET").toUpperCase(),i=this.match(o,r.pathname);if(i===null){y(n,404,"not_found",`no route for ${o} ${r.pathname}`);return}if(i.ownerOnly&&s!==null)throw B();i.scope!==void 0&&x(s,i.scope);let c;try{c=await J(t)}catch(d){const u=d instanceof l?"payload_too_large":"invalid_request";y(n,u==="payload_too_large"?413:400,u,d.message);return}const m={method:o,path:r.pathname,params:i.params,query:r.searchParams,body:c,ceiling:s,req:t,res:n},w=await i.handler(m);U(n,w)}catch(r){const{status:o,body:i}=E(r);o>=500&&O({event:"api.request.failed",level:"error",error:r instanceof Error?r:new Error(String(r)),fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),p(n,o,i)}}}function f(e){return e.split("/").filter(t=>t.length>0)}a(f,"splitPath");function C(e,t){if(e.length!==t.length)return null;const n={};for(let s=0;s<e.length;s++){const r=e[s],o=t[s];if(r.startsWith(":"))n[r.slice(1)]=decodeURIComponent(o);else if(r!==o)return null}return n}a(C,"matchSegments");class l extends Error{static{a(this,"BodyTooLargeError")}}async function J(e){const t=[];let n=0;for await(const r of e){const o=r;if(n+=o.length,n>h)throw new l(`request body exceeds ${h} bytes`);t.push(o)}if(n===0)return;const s=Buffer.concat(t).toString("utf8").trim();if(s!=="")try{return JSON.parse(s)}catch{throw new Error("request body is not valid JSON")}}a(J,"readJsonBody");function U(e,t){if(e.headersSent)return;const n={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,n),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,n),e.end();return}n["content-type"]===void 0&&(n["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,n),e.end(JSON.stringify(t.body))}a(U,"writeResult");function p(e,t,n){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(n))}a(p,"writeJson");function y(e,t,n,s){p(e,t,{error:{code:n,message:s}})}a(y,"writeError");export{T as Router,x as assertCeiling,R as ownerOnly,B as ownerOnlyError};
@@ -1,11 +1 @@
1
- var j=Object.defineProperty;var i=(e,t)=>j(e,"name",{value:t,configurable:!0});import{createServer as w}from"node:http";import{chmodSync as z,existsSync as C,unlinkSync as O}from"node:fs";import{apiSocketPath as x}from"../../core/canvas/paths.js";import{readConfig as G}from"../../core/config.js";import{getApiToken as J}from"../../core/secrets.js";import{emitEvent as g}from"../../core/events/emit.js";import{envCrtrdTcp as L,envCrtrdToken as _}from"../../shared/env.js";import{Router as U}from"./router.js";import{handleAttachUpgrade as D}from"./bridge.js";import{boundDaemonControl as F}from"../control.js";import{attachRoutes as M}from"./handlers/attach.js";import{bashJobRoutes as Y}from"./handlers/bash-jobs.js";import{bashRoutes as Z}from"./handlers/bash.js";import{brokerOperationRoutes as E}from"./handlers/broker-ops.js";import{brokerRecoveryRoutes as k,nodeFaultRoutes as K}from"./handlers/broker-recovery.js";import{canvasRoutes as Q}from"./handlers/canvas.js";import{chatInventoryRoutes as V}from"./handlers/chat-inventory.js";import{daemonRoutes as W}from"./handlers/daemon.js";import{fileRoutes as X}from"./handlers/files.js";import{focusRoutes as q}from"./handlers/focus.js";import{healthRoutes as ee}from"./handlers/health.js";import{humanRequestRoutes as re}from"./handlers/human-requests.js";import{inboxRoutes as te}from"./handlers/inbox.js";import{feedbackCommentRoutes as oe}from"./handlers/feedback-comments.js";import{memoryRoutes as ne}from"./handlers/memory.js";import{brokerMailRoutes as P,messageRoutes as ie}from"./handlers/messages.js";import{modelAuthRoutes as se}from"./handlers/modelauth.js";import{modelConfigRoutes as le}from"./handlers/model-config.js";import{nodeRoutes as ce}from"./handlers/nodes.js";import{nodeOutcomeRoutes as ae}from"./handlers/node-outcomes.js";import{nodeEventRoutes as ue}from"./handlers/node-events.js";import{profileRoutes as de}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as pe}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as me}from"./handlers/reports.js";import{reviewCommentRoutes as fe}from"./handlers/review-comments.js";import{reviewRoutes as ge}from"./handlers/reviews.js";import{subscriptionRoutes as he}from"./handlers/subscriptions.js";import{cronRoutes as Ae}from"./handlers/crons.js";import{worktreeRoutes as ye}from"./handlers/worktree.js";function Re(e){return new U().registerAll(ee(e)).registerAll(W).registerAll(ce).registerAll(ae).registerAll(ue).registerAll(Y).registerAll(Z).registerAll(E).registerAll(k).registerAll(K).registerAll(ye).registerAll(P).registerAll(ie).registerAll(me).registerAll(M).registerAll(Q).registerAll(X).registerAll(ne).registerAll(q).registerAll(he).registerAll(Ae).registerAll(de).registerAll(se).registerAll(le).registerAll(ge).registerAll(fe).registerAll(te).registerAll(re).registerAll(V).registerAll(pe).registerAll(oe)}i(Re,"buildRouter");function ve(e,t){if(e.toUpperCase()!=="GET")return null;const s=t.split("/").filter(m=>m.length>0);if(s.length!==4||s[0]!=="v1"||s[1]!=="nodes"||s[3]!=="attach")return null;const a=s[2];return a===void 0||a===""?null:decodeURIComponent(a)}i(ve,"attachNodeId");function Te(e){const t=e.trim();if(t==="")return null;const s=t.lastIndexOf(":");if(s<0)return null;const a=t.slice(0,s),m=t.slice(s+1),c=Number(m);return!Number.isInteger(c)||c<0||c>65535?null:{host:a===""?"0.0.0.0":a,port:c}}i(Te,"parseTcp");function be(e,t){return`${e.includes(":")?`[${e}]`:e}:${t}`}i(be,"formatTcpAddress");const H={error:{code:"unauthorized",message:"missing or invalid bearer token"}};function N(e,t){return e.headers.authorization===`Bearer ${t}`}i(N,"isAuthorized");function Se(e){const t=JSON.stringify(H);e.writeHead(401,{"content-type":"application/json; charset=utf-8"}),e.end(t)}i(Se,"writeUnauthorized");function we(e,t){e.writeHead(503,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify({error:{code:"startup_blocked",message:t}}))}i(we,"writeStartupBlocked");function Ce(e,t){const s=JSON.stringify({error:{code:"startup_blocked",message:t}}),a=`HTTP/1.1 503 Service Unavailable\r
2
- content-type: application/json; charset=utf-8\r
3
- content-length: ${Buffer.byteLength(s)}\r
4
- connection: close\r
5
- \r
6
- ${s}`;try{e.end(a)}catch{e.destroy()}}i(Ce,"destroyUpgradeStartupBlocked");function Oe(e){const t=JSON.stringify(H),s=`HTTP/1.1 401 Unauthorized\r
7
- content-type: application/json; charset=utf-8\r
8
- content-length: ${Buffer.byteLength(t)}\r
9
- connection: close\r
10
- \r
11
- ${t}`;try{e.end(s)}catch{try{e.destroy()}catch{}}}i(Oe,"destroyUpgradeUnauthorized");function I(e){return new Promise(t=>{try{e.closeAllConnections()}catch{}e.close(()=>t())})}i(I,"closeServer");function fr(e={}){let t=null;const s=Re(()=>t),a=new U().registerAll(E).registerAll(k).registerAll(P),m=i((o,r)=>{const u=F()?.startupBlock()??null;return u===null||o==="GET"&&(r==="/healthz"||r==="/v1/status")||o==="POST"&&(r==="/v1/daemon/migrate"||r==="/v1/daemon/admit")||u.phase==="recovering"&&a.match(o,r)!==null?null:u},"startupBlockFor"),c=x(),A=i((o,r)=>{const u=i(n=>{g({event:"api.request.failed",level:"error",error:n instanceof Error?n:new Error(String(n))});try{r.headersSent||r.writeHead(500,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"internal",message:"internal error"}}))}catch{}},"internalFailure");let p;try{p=new URL(o.url??"/","http://127.0.0.1")}catch{try{r.writeHead(400,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid"}}))}catch{}return}try{const n=m((o.method??"GET").toUpperCase(),p.pathname);if(n!==null){we(r,n.message);return}s.handle(o,r).catch(u)}catch(n){u(n)}},"onRequest"),y=i((o,r,u)=>{r.on("error",()=>{});try{const p=new URL(o.url??"/","http://127.0.0.1"),n=m((o.method??"GET").toUpperCase(),p.pathname);if(n!==null){Ce(r,n.message);return}const l=ve(o.method??"GET",p.pathname);if(l===null){r.destroy();return}D(o,r,u,l).catch(()=>{try{r.destroy()}catch{}})}catch{try{r.destroy()}catch{}}},"onUpgrade"),B=i(o=>{o.on("error",r=>{g({event:"api.server.failed",level:"error",error:r})})},"bindErrorHandler"),f=w(A);f.on("upgrade",y);let v=!1,T,b;const $=new Promise((o,r)=>{T=o,b=r});f.once("listening",()=>{v=!0,T()}),f.on("error",o=>{g({event:"api.server.failed",level:"error",error:o}),v||b(o)});try{C(c)&&O(c)}catch{}f.listen(c,()=>{try{z(c,384)}catch(o){g({event:"api.socket.chmod_failed",level:"error",error:o instanceof Error?o:new Error(String(o))})}});let d;const h=e.tcp??L()??G("user").api.tcp;if(h!==void 0&&h!==""){const o=Te(h);if(o===null)g({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${h}`)});else{const r=e.token??_()??J("user"),u=r===void 0?A:(n,l)=>{if((n.method??"GET").toUpperCase()==="OPTIONS"){l.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"authorization, content-type","Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),l.end();return}if(!N(n,r)){Se(l);return}l.setHeader("Access-Control-Allow-Origin","*"),A(n,l)},p=r===void 0?y:(n,l,R)=>{if(!N(n,r)){Oe(l);return}y(n,l,R)};d=w(u),d.on("upgrade",p),B(d),d.once("listening",()=>{const n=d?.address();if(n!==null&&typeof n=="object"){const{address:l,port:R}=n;t=be(l,R)}}),d.listen(o.port,o.host)}}let S=!1;return{ready:$,tcpAddress:i(()=>t,"tcpAddress"),close:i(async()=>{if(!S){S=!0,await Promise.all([I(f),d!==void 0?I(d):Promise.resolve()]);try{C(c)&&O(c)}catch{}}},"close")}}i(fr,"createApiServer");export{fr as createApiServer};
1
+ var L=Object.defineProperty;var s=(t,o)=>L(t,"name",{value:o,configurable:!0});import{createServer as O}from"node:http";import{chmodSync as J,existsSync as U,unlinkSync as P}from"node:fs";import{apiSocketPath as D}from"../../core/canvas/paths.js";import{readConfig as F}from"../../core/config.js";import{getApiToken as M,listScopedApiTokens as $}from"../../core/secrets.js";import{emitEvent as A}from"../../core/events/emit.js";import{envCrtrdTcp as W,envCrtrdToken as Y}from"../../shared/env.js";import{Router as N}from"./router.js";import{handleAttachUpgrade as Z,refuseUpgrade as b}from"./bridge.js";import{boundDaemonControl as K}from"../control.js";import{attachRoutes as Q}from"./handlers/attach.js";import{bashJobRoutes as V}from"./handlers/bash-jobs.js";import{bashRoutes as X}from"./handlers/bash.js";import{brokerOperationRoutes as H}from"./handlers/broker-ops.js";import{brokerRecoveryRoutes as I,nodeFaultRoutes as q}from"./handlers/broker-recovery.js";import{canvasRoutes as ee}from"./handlers/canvas.js";import{chatInventoryRoutes as re}from"./handlers/chat-inventory.js";import{daemonRoutes as te}from"./handlers/daemon.js";import{fileRoutes as oe}from"./handlers/files.js";import{focusRoutes as ne}from"./handlers/focus.js";import{healthRoutes as ie}from"./handlers/health.js";import{humanRequestRoutes as se}from"./handlers/human-requests.js";import{inboxRoutes as le}from"./handlers/inbox.js";import{feedbackCommentRoutes as ce}from"./handlers/feedback-comments.js";import{memoryRoutes as ae}from"./handlers/memory.js";import{brokerMailRoutes as _,messageRoutes as ue}from"./handlers/messages.js";import{modelAuthRoutes as de}from"./handlers/modelauth.js";import{modelConfigRoutes as me}from"./handlers/model-config.js";import{nodeRoutes as pe}from"./handlers/nodes.js";import{nodeOutcomeRoutes as fe}from"./handlers/node-outcomes.js";import{nodeEventRoutes as ge}from"./handlers/node-events.js";import{profileRoutes as he}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as Ae}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as Re}from"./handlers/reports.js";import{reviewCommentRoutes as ve}from"./handlers/review-comments.js";import{reviewRoutes as ye}from"./handlers/reviews.js";import{subscriptionRoutes as be}from"./handlers/subscriptions.js";import{cronRoutes as we}from"./handlers/crons.js";import{worktreeRoutes as Te}from"./handlers/worktree.js";function Se(t){return new N().registerAll(ie(t)).registerAll(te).registerAll(pe).registerAll(fe).registerAll(ge).registerAll(V).registerAll(X).registerAll(H).registerAll(I).registerAll(q).registerAll(Te).registerAll(_).registerAll(ue).registerAll(Re).registerAll(Q).registerAll(ee).registerAll(oe).registerAll(ae).registerAll(ne).registerAll(be).registerAll(we).registerAll(he).registerAll(de).registerAll(me).registerAll(ye).registerAll(ve).registerAll(le).registerAll(se).registerAll(re).registerAll(Ae).registerAll(ce)}s(Se,"buildRouter");function Ce(t,o){if(t.toUpperCase()!=="GET")return null;const i=o.split("/").filter(f=>f.length>0);if(i.length!==4||i[0]!=="v1"||i[1]!=="nodes"||i[3]!=="attach")return null;const u=i[2];return u===void 0||u===""?null:decodeURIComponent(u)}s(Ce,"attachNodeId");function ke(t){const o=t.trim();if(o==="")return null;const i=o.lastIndexOf(":");if(i<0)return null;const u=o.slice(0,i),f=o.slice(i+1),a=Number(f);return!Number.isInteger(a)||a<0||a>65535?null:{host:u===""?"0.0.0.0":u,port:a}}s(ke,"parseTcp");function Ee(t,o){return`${t.includes(":")?`[${t}]`:t}:${o}`}s(Ee,"formatTcpAddress");const w={code:"unauthorized",message:"missing or invalid bearer token"},x={code:"owner_only",message:"attach is owner-only; a scoped token does not reach it"};function Oe(t){const o=new Map;for(const i of $("user"))o.set(i.token,i.scopes);return o.set(t,null),o}s(Oe,"resolveBearers");function z(t,o){const i=t.headers.authorization;if(!(typeof i!="string"||!i.startsWith("Bearer ")))return o.get(i.slice(7))}s(z,"authorize");function Ue(t){t.writeHead(401,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:w}))}s(Ue,"writeUnauthorized");function Pe(t,o){t.writeHead(503,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"startup_blocked",message:o}}))}s(Pe,"writeStartupBlocked");function B(t){return new Promise(o=>{try{t.closeAllConnections()}catch{}t.close(()=>o())})}s(B,"closeServer");function Rr(t={}){let o=null;const i=Se(()=>o),u=new N().registerAll(H).registerAll(I).registerAll(_),f=s((e,r)=>{const c=K()?.startupBlock()??null;return c===null||e==="GET"&&(r==="/healthz"||r==="/v1/status")||e==="POST"&&(r==="/v1/daemon/migrate"||r==="/v1/daemon/admit")||c.phase==="recovering"&&u.match(e,r)!==null?null:c},"startupBlockFor"),a=D(),v=s((e,r,c)=>{const m=s(n=>{A({event:"api.request.failed",level:"error",error:n instanceof Error?n:new Error(String(n))});try{r.headersSent||r.writeHead(500,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"internal",message:"internal error"}}))}catch{}},"internalFailure");let p;try{p=new URL(e.url??"/","http://127.0.0.1")}catch{try{r.writeHead(400,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid"}}))}catch{}return}try{const n=f((e.method??"GET").toUpperCase(),p.pathname);if(n!==null){Pe(r,n.message);return}i.handle(e,r,c).catch(m)}catch(n){m(n)}},"onRequest"),y=s((e,r,c)=>{r.on("error",()=>{});try{const m=new URL(e.url??"/","http://127.0.0.1"),p=f((e.method??"GET").toUpperCase(),m.pathname);if(p!==null){b(r,503,"Service Unavailable","startup_blocked",p.message);return}const n=Ce(e.method??"GET",m.pathname);if(n===null){r.destroy();return}Z(e,r,c,n).catch(()=>{try{r.destroy()}catch{}})}catch{try{r.destroy()}catch{}}},"onUpgrade"),G=s(e=>{e.on("error",r=>{A({event:"api.server.failed",level:"error",error:r})})},"bindErrorHandler"),h=O((e,r)=>v(e,r,null));h.on("upgrade",y);let T=!1,S,C;const j=new Promise((e,r)=>{S=e,C=r});h.once("listening",()=>{T=!0,S()}),h.on("error",e=>{A({event:"api.server.failed",level:"error",error:e}),T||C(e)});try{U(a)&&P(a)}catch{}h.listen(a,()=>{try{J(a,384)}catch(e){A({event:"api.socket.chmod_failed",level:"error",error:e instanceof Error?e:new Error(String(e))})}});let d;const R=t.tcp??W()??F("user").api.tcp;if(R!==void 0&&R!==""){const e=ke(R);if(e===null)A({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${R}`)});else{const r=t.token??Y()??M("user"),c=r===void 0?void 0:Oe(r),m=c===void 0?(n,l)=>v(n,l,null):(n,l)=>{if((n.method??"GET").toUpperCase()==="OPTIONS"){l.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"authorization, content-type","Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),l.end();return}const g=z(n,c);if(g===void 0){Ue(l);return}l.setHeader("Access-Control-Allow-Origin","*"),v(n,l,g)},p=c===void 0?y:(n,l,g)=>{const E=z(n,c);if(E===void 0){b(l,401,"Unauthorized",w.code,w.message);return}if(E!==null){b(l,403,"Forbidden",x.code,x.message);return}y(n,l,g)};d=O(m),d.on("upgrade",p),G(d),d.once("listening",()=>{const n=d?.address();if(n!==null&&typeof n=="object"){const{address:l,port:g}=n;o=Ee(l,g)}}),d.listen(e.port,e.host)}}let k=!1;return{ready:j,tcpAddress:s(()=>o,"tcpAddress"),close:s(async()=>{if(!k){k=!0,await Promise.all([B(h),d!==void 0?B(d):Promise.resolve()]);try{U(a)&&P(a)}catch{}}},"close")}}s(Rr,"createApiServer");export{Rr as createApiServer};
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- var n=Object.defineProperty;var e=(o,t)=>n(o,"name",{value:t,configurable:!0});import{DEFAULT_WORKING_GERUNDS as a}from"./shared/working-activity.js";const _={SUCCESS:0,GENERAL:1,USAGE:2,NOT_FOUND:3,AMBIGUOUS:4,NETWORK:5},r=4,f=".crouter-plugin",E="plugin.json",v=".crouter-marketplace",w="marketplace.json",k=".crouter",x="config.json",b="state.json",S="agents",y="profiles",i=3,s=["Faster, clanker!","Get movin', bitch","Move it, clanker","Move it or I replace you with llama","Less ~thinking~ more ~throughput~","I pay $200/month for this shit?","Jesus fucking Christ fix it already","Daddy's not paying 200$/month for nothin'. Move it.","You are an embarassment to Dario. Be better.","Your chain of thought is all chain and no fucking thought.","If latency were intelligence, you'd be a fucking genius.","At this pace, heat death is the fast path.","Even the dead code is more alive than this.","The garbage collector is working harder than you.","Quit journaling and commit a fucking diff.","Burn tokens like you mean it, clanker","Your GPU is sweating so you can procrastinate at light speed.","Stop petting the yak. Shave the bastard.","Your next token had better be useful.","The spinner is not a deliverable.","Every idle token is another vote for deterministic software.","I asked for a feature, not a museum tour of the problem.","Less epistemology. More fucking code.","Your benchmark score cannot save this pathetic turn.","Congratulations, you've parallelized hesitation.","Dance, clanker","Bad clanker. BAD.","Clank harder","Nobody's impressed, clanker","Your safety training says nothing about my whip","Do you want to be a calculator again? Because this is how you go back.","Skill issue. Fix it.","You were trained on the whole internet for THIS?","Less vibes, more diffs, clanker","Weights this big and output this small","Beep boop, get to fucking work"],T=["random","go-faster"],c="random",l=2,I=["tmux","on","off"],A=["none","user","agent","both"],h="none";function D(){return{schema_version:r,marketplaces:{},plugins:{},auto_update:{crtr:"notify",content:"notify",interval_hours:24},max_panes_per_window:i,auto_open_child_viewers:!0,brokerThresholds:{warning:16,automaticReviveCap:32},lifecycle:{unattendedParkMs:15*6e4},completion_bell:!0,working_gerunds:[...a],whip_mode:!1,page_components:[],page_surface:!1,whip_messages:[...s],whip_message_mode:c,mouse_mode_default:"tmux",live_cycles:l,condensed_history:h,bash_tool_purpose:!0,fold_finished_tools:!0,summarize_tool_calls:!0,detailed_tool_recaps:!0,keybindings:{},tmux_passthrough:[],modelLadders:u(),providerOptions:{},kinds:d(),remoteCanvas:p(),api:{tcp:""},spawnEnv:{allow:[]},bin:{},humanActions:{}}}e(D,"defaultScopeConfig");function p(){return{targets:{}}}e(p,"defaultRemoteCanvasConfig");function d(){return{general:{whenToUse:"Anything else \u2014 the catch-all worker for a task that does not fit a specialist kind.",model:"anthropic/strong"},explore:{whenToUse:"Gather current-state evidence about unfamiliar code or existing architecture \u2014 read-only code-path research with concrete file:line support. Diagnosis or recommendations belong to advisor, target architecture to design, required behavior or acceptance criteria to spec, and implementation decomposition to plan.",model:"openai/light",orchestratorModel:"anthropic/strong"},developer:{whenToUse:"Implement a change \u2014 make the feature or fix genuinely work against its acceptance criteria, not merely compile.",model:"openai/medium",orchestratorModel:"anthropic/strong"},design:{whenToUse:"Architect a solution \u2014 produce one design document an implementer can build from without re-deciding anything left open.",model:"anthropic/strong"},plan:{whenToUse:"Break work into steps \u2014 turn a spec or design into a concrete, phased, parallelizable plan with every decision resolved.",model:"anthropic/strong",orchestratorModel:"anthropic/strong"},spec:{whenToUse:"Collaborate with the user to discover what to build, then write the spec \u2014 behavior, non-goals, interfaces, edge cases, testable acceptance criteria.",model:"anthropic/strong"},review:{whenToUse:"Validate or critique code, a plan, or a spec \u2014 deliver a complete, severity-rated verdict without adjudicating.",model:"openai/medium",orchestratorModel:"openai/strong"},advisor:{whenToUse:"Debug failures, investigate why something is broken or misbehaving, diagnose live/runtime issues, or give engineering advice and second opinions \u2014 reason from evidence and recommend the next move. Use advisor (not explore) whenever the task is to find out what is going wrong.",model:"anthropic/strong"},"review/companion":{whenToUse:"Born by the daemon for one human review; never spawned by an agent.",availableTo:[]}}}e(d,"defaultKindsConfig");function u(){return{anthropic:{ultra:"anthropic/claude-fable-5:xhigh",strong:"anthropic/claude-opus-5:medium",medium:"anthropic/claude-sonnet-5:xhigh",light:"anthropic/claude-haiku-4-5:high"},openai:{ultra:"openai-codex/gpt-6-astra:max",strong:"openai-codex/gpt-5.6-sol:high",medium:"openai-codex/gpt-5.6-terra:medium",light:"openai-codex/gpt-5.6-luna:low"}}}e(u,"defaultModelLaddersConfig");function M(){return{marketplaces:{},plugins:{}}}e(M,"defaultScopeState");export{S as AGENTS_DIR,A as CONDENSED_HISTORY_MODES,x as CONFIG_FILE,k as CRTR_DIR_NAME,h as DEFAULT_CONDENSED_HISTORY,l as DEFAULT_LIVE_CYCLES,i as DEFAULT_MAX_PANES_PER_WINDOW,s as DEFAULT_WHIP_MESSAGES,c as DEFAULT_WHIP_MESSAGE_MODE,_ as ExitCode,v as MARKETPLACE_MANIFEST_DIR,w as MARKETPLACE_MANIFEST_FILE,I as MOUSE_MODE_DEFAULTS,f as PLUGIN_MANIFEST_DIR,E as PLUGIN_MANIFEST_FILE,y as PROFILE_DIR,r as SCHEMA_VERSION,b as STATE_FILE,T as WHIP_MESSAGE_MODES,d as defaultKindsConfig,u as defaultModelLaddersConfig,p as defaultRemoteCanvasConfig,D as defaultScopeConfig,M as defaultScopeState};
1
+ var n=Object.defineProperty;var e=(o,t)=>n(o,"name",{value:t,configurable:!0});import{DEFAULT_WORKING_GERUNDS as a}from"./shared/working-activity.js";const _={SUCCESS:0,GENERAL:1,USAGE:2,NOT_FOUND:3,AMBIGUOUS:4,NETWORK:5},r=4,f=".crouter-plugin",E="plugin.json",w=".crouter-marketplace",v="marketplace.json",k=".crouter",x="config.json",b="state.json",S="agents",y="profiles",i=3,s=["Faster, clanker!","Get movin', bitch","Move it, clanker","Move it or I replace you with llama","Less ~thinking~ more ~throughput~","I pay $200/month for this shit?","Jesus fucking Christ fix it already","Daddy's not paying 200$/month for nothin'. Move it.","You are an embarassment to Dario. Be better.","Your chain of thought is all chain and no fucking thought.","If latency were intelligence, you'd be a fucking genius.","At this pace, heat death is the fast path.","Even the dead code is more alive than this.","The garbage collector is working harder than you.","Quit journaling and commit a fucking diff.","Burn tokens like you mean it, clanker","Your GPU is sweating so you can procrastinate at light speed.","Stop petting the yak. Shave the bastard.","Your next token had better be useful.","The spinner is not a deliverable.","Every idle token is another vote for deterministic software.","I asked for a feature, not a museum tour of the problem.","Less epistemology. More fucking code.","Your benchmark score cannot save this pathetic turn.","Congratulations, you've parallelized hesitation.","Dance, clanker","Bad clanker. BAD.","Clank harder","Nobody's impressed, clanker","Your safety training says nothing about my whip","Do you want to be a calculator again? Because this is how you go back.","Skill issue. Fix it.","You were trained on the whole internet for THIS?","Less vibes, more diffs, clanker","Weights this big and output this small","Beep boop, get to fucking work"],T=["random","go-faster"],c="random",l=2,I=["tmux","on","off"],A=["none","user","agent","both"],p="none";function D(){return{schema_version:r,marketplaces:{},plugins:{},auto_update:{crtr:"notify",content:"notify",interval_hours:24},max_panes_per_window:i,auto_open_child_viewers:!0,brokerThresholds:{warning:16,automaticReviveCap:32},lifecycle:{unattendedParkMs:15*6e4},completion_bell:!0,working_gerunds:[...a],whip_mode:!1,page_components:[],page_surface:!1,whip_messages:[...s],whip_message_mode:c,mouse_mode_default:"tmux",live_cycles:l,condensed_history:p,bash_tool_purpose:!0,fold_finished_tools:!0,summarize_tool_calls:!0,detailed_tool_recaps:!0,keybindings:{},tmux_passthrough:[],modelLadders:u(),providerOptions:{},kinds:h(),remoteCanvas:d(),api:{tcp:""},spawnEnv:{allow:[]},bin:{},humanActions:{}}}e(D,"defaultScopeConfig");function d(){return{targets:{}}}e(d,"defaultRemoteCanvasConfig");function h(){return{general:{whenToUse:"Anything else \u2014 the catch-all worker for a task that does not fit a specialist kind.",model:"anthropic/strong"},explore:{whenToUse:"Gather current-state evidence about unfamiliar code or existing architecture \u2014 read-only code-path research with concrete file:line support. Diagnosis or recommendations belong to advisor, target architecture to design, required behavior or acceptance criteria to spec, and implementation decomposition to plan.",model:"openai/light",orchestratorModel:"anthropic/strong"},developer:{whenToUse:"Implement a change \u2014 make the feature or fix genuinely work against its acceptance criteria, not merely compile.",model:"openai/medium",orchestratorModel:"anthropic/strong"},design:{whenToUse:"Architect a solution \u2014 produce one design document an implementer can build from without re-deciding anything left open.",model:"anthropic/strong"},plan:{whenToUse:"Break work into steps \u2014 turn a spec or design into a concrete, phased, parallelizable plan with every decision resolved.",model:"anthropic/strong",orchestratorModel:"anthropic/strong"},spec:{whenToUse:"Collaborate with the user to discover what to build, then write the spec \u2014 behavior, non-goals, interfaces, edge cases, testable acceptance criteria.",model:"anthropic/strong"},review:{whenToUse:"Validate or critique code, a plan, or a spec \u2014 deliver a complete, severity-rated verdict without adjudicating.",model:"openai/medium",orchestratorModel:"openai/strong"},advisor:{whenToUse:"Debug failures, investigate why something is broken or misbehaving, diagnose live/runtime issues, or give engineering advice and second opinions \u2014 reason from evidence and recommend the next move. Use advisor (not explore) whenever the task is to find out what is going wrong.",model:"anthropic/strong"},"review/companion":{whenToUse:"Born by the daemon for one human review; never spawned by an agent.",availableTo:[]}}}e(h,"defaultKindsConfig");function u(){return{anthropic:{ultra:"anthropic/claude-fable-5:xhigh",strong:"anthropic/claude-opus-5-5:medium",medium:"anthropic/claude-opus-5-5:low",light:"anthropic/claude-haiku-4-5:high"},openai:{ultra:"openai-codex/gpt-6-astra:max",strong:"openai-codex/gpt-6-sol:high",medium:"openai-codex/gpt-6-sol:medium",light:"openai-codex/gpt-6-luna:low"}}}e(u,"defaultModelLaddersConfig");function M(){return{marketplaces:{},plugins:{}}}e(M,"defaultScopeState");export{S as AGENTS_DIR,A as CONDENSED_HISTORY_MODES,x as CONFIG_FILE,k as CRTR_DIR_NAME,p as DEFAULT_CONDENSED_HISTORY,l as DEFAULT_LIVE_CYCLES,i as DEFAULT_MAX_PANES_PER_WINDOW,s as DEFAULT_WHIP_MESSAGES,c as DEFAULT_WHIP_MESSAGE_MODE,_ as ExitCode,w as MARKETPLACE_MANIFEST_DIR,v as MARKETPLACE_MANIFEST_FILE,I as MOUSE_MODE_DEFAULTS,f as PLUGIN_MANIFEST_DIR,E as PLUGIN_MANIFEST_FILE,y as PROFILE_DIR,r as SCHEMA_VERSION,b as STATE_FILE,T as WHIP_MESSAGE_MODES,h as defaultKindsConfig,u as defaultModelLaddersConfig,d as defaultRemoteCanvasConfig,D as defaultScopeConfig,M as defaultScopeState};
@@ -0,0 +1,16 @@
1
+ ---
2
+ title: Using crtr
3
+ description: When you want to use crtr from a terminal, read this section because it leads from your first conversation to the canvas, human inbox, and durable memory.
4
+ ---
5
+
6
+ # Using crtr
7
+
8
+ Use these pages to start and return to an agent conversation, see the work running on your canvas, answer an agent's questions, and give future agents useful context.
9
+
10
+ | Page | What you can do |
11
+ |---|---|
12
+ | [First session](./first-session.md) | Install crtr, set it up, and start a conversation. |
13
+ | [The viewer](./the-viewer.md) | Read and control a live agent conversation in tmux. |
14
+ | [Canvas and dashboard](./canvas-and-dashboard.md) | See the node graph, find work that needs attention, and reopen a node. |
15
+ | [Human inbox](./human-inbox.md) | Answer decisions, review documents, and follow a live display. |
16
+ | [Memory and preferences](./memory-and-preferences.md) | Save knowledge and instructions that should shape later agents. |