@north-light/cli 0.3.551 → 0.3.553

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 (110) hide show
  1. package/dist/api/client.d.ts +11 -0
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/charges.d.ts +122 -0
  6. package/dist/api/dto/charges.js +0 -0
  7. package/dist/api/dto/usage.d.ts +3 -3
  8. package/dist/api/index.d.ts +1 -0
  9. package/dist/api/index.js +1 -1
  10. package/dist/api/routes.d.ts +3 -0
  11. package/dist/api/routes.js +1 -1
  12. package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
  13. package/dist/clients/attach/viewer.js +50 -50
  14. package/dist/commands/sys/spend.d.ts +1 -0
  15. package/dist/commands/sys/spend.js +3 -0
  16. package/dist/commands/sys.js +1 -1
  17. package/dist/core/canvas/canvas.js +4 -4
  18. package/dist/core/canvas/db.js +4 -4
  19. package/dist/core/canvas/export-sqlite.js +2 -2
  20. package/dist/core/canvas/import-sqlite.d.ts +2 -0
  21. package/dist/core/canvas/import-sqlite.js +4 -4
  22. package/dist/core/canvas/person.js +7 -16
  23. package/dist/core/canvas/schema-chain.d.ts +34 -0
  24. package/dist/core/canvas/schema-chain.js +1 -0
  25. package/dist/core/canvas/schema-pg/.gitkeep +0 -0
  26. package/dist/core/canvas/schema-pg.sql +61 -0
  27. package/dist/core/canvas/schema-version.d.ts +29 -3
  28. package/dist/core/canvas/schema-version.js +1 -1
  29. package/dist/core/canvas/types.d.ts +4 -0
  30. package/dist/core/config.js +1 -1
  31. package/dist/core/grants/mirror.d.ts +2 -1
  32. package/dist/core/grants/mirror.js +2 -2
  33. package/dist/core/ledger/backfill.d.ts +12 -0
  34. package/dist/core/ledger/backfill.js +22 -0
  35. package/dist/core/ledger/charges.d.ts +18 -0
  36. package/dist/core/ledger/charges.js +1 -0
  37. package/dist/core/ledger/check.d.ts +44 -0
  38. package/dist/core/ledger/check.js +7 -0
  39. package/dist/core/ledger/index.d.ts +9 -0
  40. package/dist/core/ledger/index.js +1 -0
  41. package/dist/core/ledger/limits.d.ts +15 -0
  42. package/dist/core/ledger/limits.js +3 -0
  43. package/dist/core/ledger/months.d.ts +6 -0
  44. package/dist/core/ledger/months.js +1 -0
  45. package/dist/core/ledger/payer.d.ts +34 -0
  46. package/dist/core/ledger/payer.js +1 -0
  47. package/dist/core/ledger/read.d.ts +44 -0
  48. package/dist/core/ledger/read.js +3 -0
  49. package/dist/core/ledger/totals.d.ts +19 -0
  50. package/dist/core/ledger/totals.js +4 -0
  51. package/dist/core/ledger/types.d.ts +66 -0
  52. package/dist/core/ledger/types.js +0 -0
  53. package/dist/core/llm/run.d.ts +17 -5
  54. package/dist/core/llm/run.js +2 -2
  55. package/dist/core/providers/call.d.ts +7 -1
  56. package/dist/core/providers/call.js +1 -1
  57. package/dist/core/providers/errors.js +1 -1
  58. package/dist/core/providers/receipts.d.ts +7 -1
  59. package/dist/core/providers/receipts.js +1 -3
  60. package/dist/core/runs/operations.d.ts +1 -0
  61. package/dist/core/runs/operations.js +7 -7
  62. package/dist/core/runtime/broker/cli-relay.js +1 -1
  63. package/dist/core/runtime/broker/model-adapter.js +2 -2
  64. package/dist/core/runtime/broker/turn-cause.d.ts +7 -0
  65. package/dist/core/runtime/broker/turn-cause.js +1 -0
  66. package/dist/core/runtime/broker.js +1 -1
  67. package/dist/core/runtime/nodes.d.ts +2 -0
  68. package/dist/core/runtime/nodes.js +1 -1
  69. package/dist/core/runtime/recycle.js +1 -1
  70. package/dist/core/runtime/reset.js +1 -1
  71. package/dist/core/runtime/revive.js +2 -2
  72. package/dist/core/runtime/spawn.d.ts +2 -0
  73. package/dist/core/runtime/spawn.js +2 -2
  74. package/dist/core/runtime/start-check.d.ts +15 -0
  75. package/dist/core/runtime/start-check.js +1 -0
  76. package/dist/core/runtime/warm-pool.js +1 -1
  77. package/dist/core/user-settings.d.ts +4 -0
  78. package/dist/core/user-settings.js +1 -1
  79. package/dist/daemon/api/app-listener.js +13 -13
  80. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  81. package/dist/daemon/api/handlers/charges.d.ts +3 -0
  82. package/dist/daemon/api/handlers/charges.js +1 -0
  83. package/dist/daemon/api/handlers/llm.d.ts +9 -5
  84. package/dist/daemon/api/handlers/llm.js +3 -3
  85. package/dist/daemon/api/handlers/messages.js +2 -2
  86. package/dist/daemon/api/handlers/providers.d.ts +2 -0
  87. package/dist/daemon/api/handlers/providers.js +1 -1
  88. package/dist/daemon/api/handlers/run-routes.js +1 -1
  89. package/dist/daemon/api/handlers/runs.d.ts +1 -1
  90. package/dist/daemon/api/handlers/runs.js +1 -1
  91. package/dist/daemon/api/operations.js +1 -1
  92. package/dist/daemon/api/router.d.ts +8 -0
  93. package/dist/daemon/api/router.js +1 -1
  94. package/dist/daemon/api/server.js +1 -1
  95. package/dist/daemon/cron/authority.d.ts +1 -1
  96. package/dist/daemon/cron-run.js +2 -2
  97. package/dist/daemon/crtrd.js +10 -10
  98. package/dist/daemon/fleet.js +4 -4
  99. package/dist/daemon/reconcilers/action-lane.js +1 -1
  100. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +2 -0
  101. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  102. package/dist/types.d.ts +4 -0
  103. package/docs/sdk/release-notes.md +10 -0
  104. package/package.json +3 -2
  105. package/packages/crouter-identity/package.json +1 -1
  106. package/runtime.lock.json +13 -13
  107. package/scripts/install-runtime.mjs +6 -20
  108. package/scripts/lib/canvas-schema-gate.mjs +20 -0
  109. package/dist/core/usage/ledger.d.ts +0 -49
  110. package/dist/core/usage/ledger.js +0 -10
@@ -57,6 +57,8 @@ export interface SpawnChildOpts {
57
57
  isolated?: boolean;
58
58
  /** App run identity set at birth; children inherit from the spawner. */
59
59
  run?: SpawnNodeOpts['run'];
60
+ /** What caused this run, stored on its root node. */
61
+ causedBy?: string;
60
62
  /** Commit run rows inside the same transaction as the newborn node. */
61
63
  withinCreate?: SpawnNodeOpts['withinCreate'];
62
64
  /** Select the profile this node runs under — an exact profile id or a unique
@@ -1,3 +1,3 @@
1
- var de=Object.defineProperty;var d=(e,o)=>de(e,"name",{value:o,configurable:!0});import{accessSync as se,constants as ce}from"node:fs";import{isAbsolute as le,resolve as fe,join as ue}from"node:path";import{appSpace as me}from"../layout.js";import{ApiError as q}from"../../api/errors.js";import{spawnNode as we,forkSourceNode as he,currentNodeContext as pe,rootOfSpine as ke,newNodeId as _e,preflightNodeId as ve}from"./nodes.js";import{resolveProfileOperand as ye}from"../profiles/manifest.js";import{selectProfileForCwd as ge,selectProfileForCwdReadOnly as be}from"../profiles/select.js";import{buildLaunchSpecAsync as Y,buildPiArgv as xe}from"./launch.js";import{createManagedWorktreeAsync as Ce,rollbackManagedWorktreeAsync as Ee}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as I}from"../errors.js";import{writeGoal as $e}from"./kickoff.js";import{appendSituationalContext as Fe,formatSituationalProse as Oe}from"./situational-context.js";import{ensureRoadmap as Re}from"./roadmap.js";import{buildWakeBearings as Se}from"./bearings.js";import{encodeKickoffOrigin as Ie,KICKOFF_ORIGIN_ENV as Ne}from"./stamp/protocol.js";import{beginExecution as Pe,crtrHome as De,getNode as f,fullName as J,jobDir as Te,recordExecutionPid as Be,abortExecution as B,setFrozen as Le}from"../canvas/index.js";import{contextDir as L,nodeAgentDir as A}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ae}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as x}from"../conversation-store/index.js";import{appMemoryTooSmall as Me,boundFleet as je,brokerThresholdsForDaemon as We}from"./fleet.js";import{admitBrokerMemory as He}from"./memory-admission.js";import{emitEvent as Ke}from"../events/emit.js";import{openViewerWindow as ze,focusOf as Ge,windowOfPane as Ue}from"./placement.js";import{waitForBrokerViewSocket as Ve}from"./placement-tmux.js";import{transition as h}from"./lifecycle.js";import{beginBootFaultAttempt as Xe}from"../canvas/recovery.js";import{headlessBrokerHost as M}from"./host.js";import{ensureDaemon as qe}from"../../daemon/manage.js";import{readConfig as Ye}from"../config.js";import{modelRequestFromConfig as Je,unregisteredConcreteModel as Qe}from"../model-routes.js";import{openModelRegistry as Ze}from"./model-registry.js";import{MODEL_SPEC_NEXT as en}from"./model-selection.js";import{forkNodeLedger as nn}from"./ledger.js";import{appRungForGrant as on}from"../llm/app-rungs.js";import{APP_FAMILY as j}from"../model-routes.js";import{discoverLifecycleHookRegistry as rn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as tn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as an}from"../async-array.js";function p(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(p,"launchFailureOutcome");async function dn(e,o,a){try{return await M.launch(e,o,a)}catch(r){try{await h(e,"crash",{reason:"launch_failed",outcome:p(r)})}catch{}const t=r.message;throw I(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(dn,"launchBrokerOrCrash");async function sn(e,o){try{await h(e,"crash",{reason:"launch_failed",outcome:p(o)})}catch{}try{M.teardown(e)}catch{}}d(sn,"crashAndTearDown");async function cn(e){const o=(await x().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw u(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(cn,"resolveSessionUuid");async function Q(e){const o=e.trim();if(o==="")throw u("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(le(o)?o:fe(process.cwd(),o));if(r===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await x().header(r)).path}const a=await f(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw u(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await x().header(t)).path}return await cn(o)}d(Q,"resolveForkSource");async function ln(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?ye(e).profileId:o!==null?(await f(o))?.profile_id??null:r.readOnlySelection===!0?be(a):ge(a)}d(ln,"resolveProfileId");function Z(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Je(e.model,o,e.modelExact===!0)}d(Z,"requestFromLaunch");async function ee(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await on(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...c}=e.env??{};return{...e,model:t.model,modelIntent:{family:j,strength:t.strength},modelExact:void 0,env:{...c,CRTR_MODEL_INTENT:`${j}/${t.strength}`}}}d(ee,"appPaidLaunch");async function ne(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==j)return;const r=Qe(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await Ze(),o);if(r!==void 0)throw u(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:en})}d(ne,"assertLaunchModelRegistered");function fn(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d(fn,"resolveSpawner");async function oe(e,o,a){try{qe()}catch{}const r=pe(),t=e.root===!0,s=fn(e.parent,r.nodeId??null,t),c=e.mode??"base",k=e.rootLifecycle??(t?"resident":"terminal"),re=t&&k==="resident",P=s===null?null:await f(s),ie=e.creator===void 0||e.creator===null?null:await f(e.creator);e.nodeId!==void 0&&await ve(e.nodeId);const _=e.forkFrom!==void 0?await Q(e.forkFrom):void 0,W=_===void 0?null:await he(_),D=await an([P,ie,W],async l=>l?.isolated===!0||l?.run_id!=null&&(await f(l.run_id))?.isolated===!0);if(D&&e.isolated===!1)throw new q(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const $=D||e.isolated===!0;if($&&e.worktree===!0)throw new q(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const F=e.worktree===!0,v=$||F?e.nodeId??await _e():e.nodeId,O=$?e.run!==void 0&&t&&!D?e.cwd:ue(me(e.run?.grantee??P?.grantee??"app:terminal").nodes,v):e.cwd,C=await ln(e.profile,s,O),H=e.run?.grant_id??P?.grant_id??null,K=await ee((await Y(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:C})).launch,H,e.model);await ne(Z(K),{cwd:O,profileId:C});const z=W?.node_id??null;let y,R=O;try{F&&(y=await Ce(e.worktreeCwd??e.cwd,v,e.worktreeBase),R=y.path);const l=F?await ee((await Y(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:R,profileId:C})).launch,H,e.model):K;F&&await ne(Z(l),{cwd:R,profileId:C});const n=await we({kind:e.kind,mode:c,lifecycle:k,cwd:R,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:z,spawnedBy:t?s??void 0:void 0,profile_id:C,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:$,...e.run===void 0?{}:{run:e.run},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:_,modelOverride:e.model===void 0?void 0:l.model,...y!==void 0?{managedWorktree:y}:{},...v!==void 0?{nodeId:v}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:l});if(a?.(n.node_id),e.forkFrom!==void 0)try{await nn(n.node_id,z??null)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(await $e(n.node_id,e.prompt),e.situationalContext!==void 0&&Fe(n.node_id,Oe(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const T=e.prompt!=="",te=`${T&&e.wakeOrigin!==void 0?`${Se(e.wakeOrigin)}
1
+ var se=Object.defineProperty;var d=(e,o)=>se(e,"name",{value:o,configurable:!0});import{accessSync as ce,constants as le}from"node:fs";import{isAbsolute as fe,resolve as ue,join as me}from"node:path";import{appSpace as we}from"../layout.js";import{ApiError as J}from"../../api/errors.js";import{spawnNode as he,forkSourceNode as pe,currentNodeContext as ke,rootOfSpine as _e,newNodeId as ve,preflightNodeId as ye}from"./nodes.js";import{resolveProfileOperand as ge}from"../profiles/manifest.js";import{selectProfileForCwd as be,selectProfileForCwdReadOnly as xe}from"../profiles/select.js";import{buildLaunchSpecAsync as Q,buildPiArgv as Ce}from"./launch.js";import{createManagedWorktreeAsync as Ee,rollbackManagedWorktreeAsync as $e}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as N}from"../errors.js";import{writeGoal as Fe}from"./kickoff.js";import{appendSituationalContext as Se,formatSituationalProse as Oe}from"./situational-context.js";import{ensureRoadmap as Re}from"./roadmap.js";import{buildWakeBearings as Ie}from"./bearings.js";import{encodeKickoffOrigin as Ne,KICKOFF_ORIGIN_ENV as Pe}from"./stamp/protocol.js";import{beginExecution as Be,crtrHome as De,getNode as f,fullName as Z,jobDir as Te,recordExecutionPid as Le,abortExecution as A,setFrozen as Ae}from"../canvas/index.js";import{contextDir as M,nodeAgentDir as j}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Me}from"../spaces/open-beneath.js";import{conversationIdFromPath as P,conversationStore as x}from"../conversation-store/index.js";import{appMemoryTooSmall as je,boundFleet as We,brokerThresholdsForDaemon as He}from"./fleet.js";import{admitBrokerMemory as Ke}from"./memory-admission.js";import{emitEvent as ze}from"../events/emit.js";import{openViewerWindow as Ge,focusOf as Ue,windowOfPane as Ve}from"./placement.js";import{waitForBrokerViewSocket as Xe}from"./placement-tmux.js";import{transition as h}from"./lifecycle.js";import{beginBootFaultAttempt as qe}from"../canvas/recovery.js";import{headlessBrokerHost as W}from"./host.js";import{ensureDaemon as Ye}from"../../daemon/manage.js";import{readConfig as Je}from"../config.js";import{modelRequestFromConfig as Qe,unregisteredConcreteModel as Ze}from"../model-routes.js";import{openModelRegistry as en}from"./model-registry.js";import{MODEL_SPEC_NEXT as nn}from"./model-selection.js";import{forkNodeLedger as on}from"./ledger.js";import{appRungForGrant as rn}from"../llm/app-rungs.js";import{APP_FAMILY as H}from"../model-routes.js";import{discoverLifecycleHookRegistry as tn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as an}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as dn}from"../async-array.js";import{checkStart as sn}from"./start-check.js";function p(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(p,"launchFailureOutcome");async function cn(e,o,a){try{return await W.launch(e,o,a)}catch(r){try{await h(e,"crash",{reason:"launch_failed",outcome:p(r)})}catch{}const t=r.message;throw N(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(cn,"launchBrokerOrCrash");async function ln(e,o){try{await h(e,"crash",{reason:"launch_failed",outcome:p(o)})}catch{}try{W.teardown(e)}catch{}}d(ln,"crashAndTearDown");async function fn(e){const o=(await x().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw u(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(fn,"resolveSessionUuid");async function ee(e){const o=e.trim();if(o==="")throw u("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=P(fe(o)?o:ue(process.cwd(),o));if(r===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await x().header(r)).path}const a=await f(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw u(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=P(r);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await x().header(t)).path}return await fn(o)}d(ee,"resolveForkSource");async function un(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?ge(e).profileId:o!==null?(await f(o))?.profile_id??null:r.readOnlySelection===!0?xe(a):be(a)}d(un,"resolveProfileId");function ne(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Qe(e.model,o,e.modelExact===!0)}d(ne,"requestFromLaunch");async function oe(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await rn(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...c}=e.env??{};return{...e,model:t.model,modelIntent:{family:H,strength:t.strength},modelExact:void 0,env:{...c,CRTR_MODEL_INTENT:`${H}/${t.strength}`}}}d(oe,"appPaidLaunch");async function re(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==H)return;const r=Ze(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await en(),o);if(r!==void 0)throw u(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:nn})}d(re,"assertLaunchModelRegistered");function mn(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d(mn,"resolveSpawner");async function ie(e,o,a){try{Ye()}catch{}const r=ke(),t=e.root===!0,s=mn(e.parent,r.nodeId??null,t),c=e.mode??"base",k=e.rootLifecycle??(t?"resident":"terminal"),te=t&&k==="resident",$=s===null?null:await f(s),K=e.creator===void 0||e.creator===null?null:await f(e.creator);e.nodeId!==void 0&&await ye(e.nodeId);const _=e.forkFrom!==void 0?await ee(e.forkFrom):void 0,B=_===void 0?null:await pe(_),D=await dn([$,K,B],async l=>l?.isolated===!0||l?.run_id!=null&&(await f(l.run_id))?.isolated===!0);if(D&&e.isolated===!1)throw new J(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const F=D||e.isolated===!0;if(F&&e.worktree===!0)throw new J(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const S=e.worktree===!0,v=F||S?e.nodeId??await ve():e.nodeId,O=F?e.run!==void 0&&t&&!D?e.cwd:me(we(e.run?.grantee??$?.grantee??"app:terminal").nodes,v):e.cwd,C=await un(e.profile,s,O),z=e.run?.grant_id??$?.grant_id??null,G=await oe((await Q(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:C})).launch,z,e.model);await re(ne(G),{cwd:O,profileId:C});const T=e.run??K??$??B;await sn({grantee:T?.grantee??"app:terminal",sub:T?.sub,grant_id:T?.grant_id});const U=B?.node_id??null;let y,R=O;try{S&&(y=await Ee(e.worktreeCwd??e.cwd,v,e.worktreeBase),R=y.path);const l=S?await oe((await Q(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:R,profileId:C})).launch,z,e.model):G;S&&await re(ne(l),{cwd:R,profileId:C});const n=await he({kind:e.kind,mode:c,lifecycle:k,cwd:R,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:U,spawnedBy:t?s??void 0:void 0,profile_id:C,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:F,...e.run===void 0?{}:{run:e.run},...e.causedBy===void 0?{}:{causedBy:e.causedBy},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:_,modelOverride:e.model===void 0?void 0:l.model,...y!==void 0?{managedWorktree:y}:{},...v!==void 0?{nodeId:v}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:l});if(a?.(n.node_id),e.forkFrom!==void 0)try{await on(n.node_id,U??null)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(await Fe(n.node_id,e.prompt),e.situationalContext!==void 0&&Se(n.node_id,Oe(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const L=e.prompt!=="",ae=`${L&&e.wakeOrigin!==void 0?`${Ie(e.wakeOrigin)}
2
2
 
3
- `:""}${e.prompt}`;c==="orchestrator"&&await Re(n.node_id,{goal:e.prompt.trim()}),await un(n);let G;if(_!==void 0)try{const i=N(_);if(i===null)throw new Error(`invalid fork source ${_}`);const w=await x().fork(i,n.node_id);G=(await x().header(w)).path}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const g=xe(n,{prompt:te,resumeSessionPath:G});if(g.env={...g.env,CRTR_SUBTREE:await ke(n.node_id)},T){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};g.env[Ne]=Ie(i)}const b=je(),U=b.reserveSlot(n.node_id),m=U?await He(n.node_id):null;if(m?.verdict==="too_small"){b.releaseReservation(n.node_id);const i=Me(m);throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(!U||m?.verdict==="denied")return m?.verdict==="denied"&&b.releaseReservation(n.node_id),await Le(n.node_id,new Date().toISOString()),Ke({level:"info",event:"broker.frozen",node_id:n.node_id,fields:m?.verdict==="denied"?{reason:"app_memory",free_bytes:m.free_bytes,needed_bytes:m.needed_bytes}:{reason:"broker_cap",live_count:b.size(),hard_cap:We().automaticReviveCap}}),{node:await f(n.node_id),frozen:!0,window:null,session:null};const ae=await Xe(n.node_id),E=await Pe(n.node_id,{daemonEpoch:b.epoch()});g.env={...g.env,CRTR_EXECUTION_ID:E};let S;try{S=await dn(n.node_id,g,{cwd:n.cwd,name:J(n),resuming:!1})}catch(i){throw await B(E,{reason:"launch_failed"}),i}finally{b.releaseReservation(n.node_id)}if(S.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw await B(E,{reason:"launch_failed"}),await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),I(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(await Be(E,n.node_id,S.pid)==="shutdown")throw await B(E,{reason:"superseded"}),M.teardown(n.node_id),I(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(re&&e.readiness==="await"&&!await Ve(n.node_id,S.exited)){const i=await ae.explanation();throw await sn(n.node_id,new Error(i??`broker view socket never bound for ${n.node_id}`)),I(i!==null?`the root broker ${n.node_id} could not start \u2014 ${i}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,i!==null?"Resolve the cause named above, then retry.":`The broker engine exited before binding its view socket. Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}let V=null,X=null;if(!t&&s!==null&&Ye("user").auto_open_child_viewers)try{const i=await Ge(s);if(i!==null&&i.pane!==null&&i.pane!==""){const w=await ze(n.node_id,i.session??"",{name:J(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:T});w!==null&&w.pane!==null&&w.pane!==""&&(X=w.session,V=Ue(w.pane))}}catch{}return{node:await f(n.node_id),frozen:!1,window:V,session:X}}catch(l){throw y!==void 0&&v!==void 0&&await f(v)===null&&await Ee(y),l}}d(oe,"spawnChildPrepared");async function no(e){return oe(e)}d(no,"spawnChild");async function un(e){const o=rn(e.cwd,e.profile_id).plans.get("node:start")??[];await tn(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await A(e.node_id),contextDir:await L(e.node_id),jobDir:Te(e.node_id)},runtime:{isBirth:!0,canvasHome:De(),profile:e.profile_id??null}})}d(un,"invokeBirthLifecycleHooks");const mn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function oo(e,o,a){const r=await f(e);if(r===null)throw u(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=await Q(e),s=await L(e);try{await x().header(N(t)),se(s,ce.R_OK)}catch(c){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${c.message}`)}return oe({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},async c=>{const k=await L(c);Ae(await A(e),s,await A(c),k,mn)})}d(oo,"forkNode");export{ee as appPaidLaunch,ne as assertLaunchModelRegistered,oo as forkNode,un as invokeBirthLifecycleHooks,Q as resolveForkSource,ln as resolveProfileId,fn as resolveSpawner,no as spawnChild,oe as spawnChildPrepared};
3
+ `:""}${e.prompt}`;c==="orchestrator"&&await Re(n.node_id,{goal:e.prompt.trim()}),await wn(n);let V;if(_!==void 0)try{const i=P(_);if(i===null)throw new Error(`invalid fork source ${_}`);const w=await x().fork(i,n.node_id);V=(await x().header(w)).path}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const g=Ce(n,{prompt:ae,resumeSessionPath:V});if(g.env={...g.env,CRTR_SUBTREE:await _e(n.node_id)},L){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};g.env[Pe]=Ne(i)}const b=We(),X=b.reserveSlot(n.node_id),m=X?await Ke(n.node_id):null;if(m?.verdict==="too_small"){b.releaseReservation(n.node_id);const i=je(m);throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(!X||m?.verdict==="denied")return m?.verdict==="denied"&&b.releaseReservation(n.node_id),await Ae(n.node_id,new Date().toISOString()),ze({level:"info",event:"broker.frozen",node_id:n.node_id,fields:m?.verdict==="denied"?{reason:"app_memory",free_bytes:m.free_bytes,needed_bytes:m.needed_bytes}:{reason:"broker_cap",live_count:b.size(),hard_cap:He().automaticReviveCap}}),{node:await f(n.node_id),frozen:!0,window:null,session:null};const de=await qe(n.node_id),E=await Be(n.node_id,{daemonEpoch:b.epoch()});g.env={...g.env,CRTR_EXECUTION_ID:E};let I;try{I=await cn(n.node_id,g,{cwd:n.cwd,name:Z(n),resuming:!1})}catch(i){throw await A(E,{reason:"launch_failed"}),i}finally{b.releaseReservation(n.node_id)}if(I.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw await A(E,{reason:"launch_failed"}),await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),N(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(await Le(E,n.node_id,I.pid)==="shutdown")throw await A(E,{reason:"superseded"}),W.teardown(n.node_id),N(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(te&&e.readiness==="await"&&!await Xe(n.node_id,I.exited)){const i=await de.explanation();throw await ln(n.node_id,new Error(i??`broker view socket never bound for ${n.node_id}`)),N(i!==null?`the root broker ${n.node_id} could not start \u2014 ${i}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,i!==null?"Resolve the cause named above, then retry.":`The broker engine exited before binding its view socket. Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}let q=null,Y=null;if(!t&&s!==null&&Je("user").auto_open_child_viewers)try{const i=await Ue(s);if(i!==null&&i.pane!==null&&i.pane!==""){const w=await Ge(n.node_id,i.session??"",{name:Z(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:L});w!==null&&w.pane!==null&&w.pane!==""&&(Y=w.session,q=Ve(w.pane))}}catch{}return{node:await f(n.node_id),frozen:!1,window:q,session:Y}}catch(l){throw y!==void 0&&v!==void 0&&await f(v)===null&&await $e(y),l}}d(ie,"spawnChildPrepared");async function io(e){return ie(e)}d(io,"spawnChild");async function wn(e){const o=tn(e.cwd,e.profile_id).plans.get("node:start")??[];await an(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await j(e.node_id),contextDir:await M(e.node_id),jobDir:Te(e.node_id)},runtime:{isBirth:!0,canvasHome:De(),profile:e.profile_id??null}})}d(wn,"invokeBirthLifecycleHooks");const hn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function to(e,o,a){const r=await f(e);if(r===null)throw u(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=await ee(e),s=await M(e);try{await x().header(P(t)),ce(s,le.R_OK)}catch(c){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${c.message}`)}return ie({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},async c=>{const k=await M(c);Me(await j(e),s,await j(c),k,hn)})}d(to,"forkNode");export{oe as appPaidLaunch,re as assertLaunchModelRegistered,to as forkNode,wn as invokeBirthLifecycleHooks,ee as resolveForkSource,un as resolveProfileId,mn as resolveSpawner,io as spawnChild,ie as spawnChildPrepared};
@@ -0,0 +1,15 @@
1
+ import { type Refusal, type StartCandidate } from '../ledger/index.js';
2
+ import { RunError } from '../runs/operations.js';
3
+ export interface StartIdentity {
4
+ grantee?: string;
5
+ sub?: string | null;
6
+ grant_id?: string | null;
7
+ }
8
+ /** The start candidate for an identity, or null when no person is known yet (a terminal node before its first grant snapshot). */
9
+ export declare function startCandidateOf(who: StartIdentity): Promise<StartCandidate | null>;
10
+ /** Throw `402 cap_exhausted` (limit named) when a limit covering every charge of this identity's payer is reached. */
11
+ export declare function checkStart(who: StartIdentity): Promise<void>;
12
+ /** The refusal, without throwing, for callers that settle a refused state instead of failing (cron fire). */
13
+ export declare function startRefusal(who: StartIdentity): Promise<Refusal | null>;
14
+ /** Whether an error is the start check's `402 cap_exhausted` refusal. */
15
+ export declare function isStartRefusal(error: unknown): error is RunError;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var n=(a,t)=>c(a,"name",{value:t,configurable:!0});import{check as s,findRefusal as u,payerOf as o}from"../ledger/index.js";import{RunError as l}from"../runs/operations.js";import{payerOfGrant as p,terminalGrant as f}from"../grants/mirror.js";async function e(a){const t=a.grantee??"app:terminal",r=a.sub??(t==="app:terminal"?(await f())?.sub:void 0)??null;if(r===null)return null;const i=await p(a.grant_id);return{scope:"start",payer:o({call:"start",grantPayer:i,sub:r,grantee:t}).payer,sub:r,grantee:t}}n(e,"startCandidateOf");async function w(a){const t=await e(a);t!==null&&await s(t)}n(w,"checkStart");async function R(a){const t=await e(a);return t===null?null:await u(t)}n(R,"startRefusal");function b(a){return a instanceof l&&a.code==="cap_exhausted"}n(b,"isStartRefusal");export{w as checkStart,b as isStartRefusal,e as startCandidateOf,R as startRefusal};
@@ -1 +1 @@
1
- var S=Object.defineProperty;var n=(e,r)=>S(e,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{claimWarmSpare as x,deleteNode as N,getNode as u,listNodes as $,listWarmSpares as C,registerWarmSpare as R,unregisterWarmSpare as W,updateNode as b,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as P}from"../canvas/pid.js";import{nowIso as y}from"../fs-utils.js";import{admitNodeCreate as L}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as M}from"./spawn.js";import{buildLaunchSpecAsync as A}from"./launch.js";import{setModelLive as E}from"./model-swap.js";import{setSituationalContextLive as O}from"./situational-live.js";import{deliverBearingsLive as I}from"./deliver-live.js";import{closeNode as h}from"./close.js";function g(){return process.env.CRTR_WARM_POOL!=="0"}n(g,"warmPoolEnabled");function T(e,r,t){const a=Object.entries(t.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,t.tools??[],t.extensions??[],t.systemPrompt??null,a]);return _("sha256").update(o).digest("hex").slice(0,32)}n(T,"warmRecipeKey");async function d(e){const{launch:r}=await A(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId});return{key:T(e.cwd,e.profileId,r),launch:r,request:e}}n(d,"resolveRecipe");async function Z(e,r={},t){const a=await d(e);if(await w(a.key)===0)return null;const o=y(),s=await L({kind:e.kind,mode:e.mode,cwd:e.cwd,profile:e.profileId,root:!0,parentId:null,requestingNodeId:e.creator,lifecycle:"resident",replaces:null},e.creator===null?"app:terminal":await(async()=>{const l=await u(e.creator);if(!l?.grantee)throw new Error("warm node creator has no app");return l.grantee})());let i;try{i=await x(a.key,o,r)}finally{s()}return i===null?null:v(i,a,o,t)}n(Z,"claimWarmNode");async function q(e,r,t){return v(r,await d(e),y(),t)}n(q,"resumeWarmClaim");async function v(e,r,t,a){const{request:o}=r,i=(await u(e))?.launch?.model;await b(e,{created:t,kind:o.kind,mode:o.mode,name:o.name??o.kind,creator:o.creator,launch:r.launch,persona_ack:{kind:o.kind,mode:o.mode,lifecycle:"resident"},...o.model!==null?{model_override:o.model}:{}});try{a?.(e)}catch(c){return await m(e,"birth preparation",c)}try{await I(e)}catch(c){return await m(e,"bearings delivery",c)}const l=r.launch.model;if(l!==void 0&&l!==i)try{await E(e,l,r.launch.modelIntent)}catch(c){return await m(e,"model swap",c)}if(o.situationalContext!==null)try{await O(e,o.situationalContext)}catch(c){return await m(e,"situational-context delivery",c)}return e}n(v,"completeWarmClaim");async function m(e,r,t){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${t.message}`);try{await h(e)}catch{}return null}n(m,"abandonSpare");const D=3600*1e3;async function ee(){const e=[];let r;try{r=await C()}catch(a){return console.error(`[warm-pool] spare scan failed: ${a.message}`),e}const t=Date.now()-D;for(const a of r){if(f.has(a.node_id))continue;const o=Date.parse(a.created),s=Number.isNaN(o)||o<t,i=P(a.pi_pid,a.pi_pid_identity),l=(a.status==="active"||a.status==="idle")&&i==="alive";if(!(l&&!s)&&!(i==="indeterminate"&&!s))try{if(!await W(a.node_id))continue;if(l)try{await h(a.node_id)}catch{}await N(a.node_id),e.push(a.node_id)}catch(c){console.error(`[warm-pool] reap failed for ${a.node_id}: ${c.message}`)}}return e}n(ee,"reapStaleSpares");const p=new Set,f=new Set;function re(e){if(g())try{d({...e,model:null,situationalContext:null}).then(k).catch(r=>console.error(`[warm-pool] recipe resolution failed: ${r.message}`))}catch(r){console.error(`[warm-pool] recipe resolution failed: ${r.message}`)}}n(re,"refillWarmPool");async function k(e){const{key:r,request:t}=e;p.has(r)||await w(r)>0||(p.add(r),(async()=>{let a=null;try{await M({kind:t.kind,mode:t.mode,cwd:t.cwd,prompt:"",root:!0,readiness:"await",profile:t.profileId},async o=>{a=o,f.add(o),await R(o,r)})}catch(o){console.error(`[warm-pool] mint failed for ${t.kind}: ${o.message}`)}finally{a!==null&&f.delete(a),p.delete(r)}})())}n(k,"mint");const j=2;async function te(){if(!g())return;let e;try{const r=new Set;e=[];for(const t of(await $({status:["active","idle"]})).reverse()){if(t.parent!==null||t.kind==="human")continue;const a=t.profile_id??null;if(!r.has(a??"")&&(r.add(a??""),e.push({cwd:t.cwd,profileId:a}),e.length>=j))break}}catch(r){console.error(`[warm-pool] prewarm scan failed: ${r.message}`);return}for(const r of e)try{d({kind:"general",mode:"base",cwd:r.cwd,profileId:r.profileId,model:null,situationalContext:null,name:null,creator:null}).then(k).catch(t=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`))}catch(t){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`)}}n(te,"prewarmRecentRecipes");export{Z as claimWarmNode,te as prewarmRecentRecipes,ee as reapStaleSpares,re as refillWarmPool,q as resumeWarmClaim,g as warmPoolEnabled};
1
+ var _=Object.defineProperty;var n=(e,r)=>_(e,"name",{value:r,configurable:!0});import{createHash as x}from"node:crypto";import{claimWarmSpare as N,deleteNode as $,getNode as p,listNodes as C,listWarmSpares as b,registerWarmSpare as R,unregisterWarmSpare as W,updateNode as P,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as L}from"../canvas/pid.js";import{nowIso as y}from"../fs-utils.js";import{admitNodeCreate as M}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as A}from"./spawn.js";import{checkStart as E}from"./start-check.js";import{buildLaunchSpecAsync as O}from"./launch.js";import{setModelLive as I}from"./model-swap.js";import{setSituationalContextLive as T}from"./situational-live.js";import{deliverBearingsLive as D}from"./deliver-live.js";import{closeNode as h}from"./close.js";function g(){return process.env.CRTR_WARM_POOL!=="0"}n(g,"warmPoolEnabled");function j(e,r,t){const a=Object.entries(t.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,t.tools??[],t.extensions??[],t.systemPrompt??null,a]);return x("sha256").update(o).digest("hex").slice(0,32)}n(j,"warmRecipeKey");async function d(e){const{launch:r}=await O(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId});return{key:j(e.cwd,e.profileId,r),launch:r,request:e}}n(d,"resolveRecipe");async function k(e){const r=e.creator===null?null:await p(e.creator);await E({grantee:r?.grantee??"app:terminal",sub:r?.sub,grant_id:r?.grant_id})}n(k,"checkClaimantStart");async function re(e,r={},t){await k(e);const a=await d(e);if(await w(a.key)===0)return null;const o=y(),s=await M({kind:e.kind,mode:e.mode,cwd:e.cwd,profile:e.profileId,root:!0,parentId:null,requestingNodeId:e.creator,lifecycle:"resident",replaces:null},e.creator===null?"app:terminal":await(async()=>{const c=await p(e.creator);if(!c?.grantee)throw new Error("warm node creator has no app");return c.grantee})());let i;try{i=await N(a.key,o,r)}finally{s()}return i===null?null:v(i,a,o,t)}n(re,"claimWarmNode");async function te(e,r,t){return await k(e),v(r,await d(e),y(),t)}n(te,"resumeWarmClaim");async function v(e,r,t,a){const{request:o}=r,i=(await p(e))?.launch?.model;await P(e,{created:t,kind:o.kind,mode:o.mode,name:o.name??o.kind,creator:o.creator,launch:r.launch,persona_ack:{kind:o.kind,mode:o.mode,lifecycle:"resident"},...o.model!==null?{model_override:o.model}:{}});try{a?.(e)}catch(l){return await m(e,"birth preparation",l)}try{await D(e)}catch(l){return await m(e,"bearings delivery",l)}const c=r.launch.model;if(c!==void 0&&c!==i)try{await I(e,c,r.launch.modelIntent)}catch(l){return await m(e,"model swap",l)}if(o.situationalContext!==null)try{await T(e,o.situationalContext)}catch(l){return await m(e,"situational-context delivery",l)}return e}n(v,"completeWarmClaim");async function m(e,r,t){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${t.message}`);try{await h(e)}catch{}return null}n(m,"abandonSpare");const B=3600*1e3;async function ae(){const e=[];let r;try{r=await b()}catch(a){return console.error(`[warm-pool] spare scan failed: ${a.message}`),e}const t=Date.now()-B;for(const a of r){if(u.has(a.node_id))continue;const o=Date.parse(a.created),s=Number.isNaN(o)||o<t,i=L(a.pi_pid,a.pi_pid_identity),c=(a.status==="active"||a.status==="idle")&&i==="alive";if(!(c&&!s)&&!(i==="indeterminate"&&!s))try{if(!await W(a.node_id))continue;if(c)try{await h(a.node_id)}catch{}await $(a.node_id),e.push(a.node_id)}catch(l){console.error(`[warm-pool] reap failed for ${a.node_id}: ${l.message}`)}}return e}n(ae,"reapStaleSpares");const f=new Set,u=new Set;function oe(e){if(g())try{d({...e,model:null,situationalContext:null}).then(S).catch(r=>console.error(`[warm-pool] recipe resolution failed: ${r.message}`))}catch(r){console.error(`[warm-pool] recipe resolution failed: ${r.message}`)}}n(oe,"refillWarmPool");async function S(e){const{key:r,request:t}=e;f.has(r)||await w(r)>0||(f.add(r),(async()=>{let a=null;try{await A({kind:t.kind,mode:t.mode,cwd:t.cwd,prompt:"",root:!0,readiness:"await",profile:t.profileId},async o=>{a=o,u.add(o),await R(o,r)})}catch(o){console.error(`[warm-pool] mint failed for ${t.kind}: ${o.message}`)}finally{a!==null&&u.delete(a),f.delete(r)}})())}n(S,"mint");const F=2;async function ne(){if(!g())return;let e;try{const r=new Set;e=[];for(const t of(await C({status:["active","idle"]})).reverse()){if(t.parent!==null||t.kind==="human")continue;const a=t.profile_id??null;if(!r.has(a??"")&&(r.add(a??""),e.push({cwd:t.cwd,profileId:a}),e.length>=F))break}}catch(r){console.error(`[warm-pool] prewarm scan failed: ${r.message}`);return}for(const r of e)try{d({kind:"general",mode:"base",cwd:r.cwd,profileId:r.profileId,model:null,situationalContext:null,name:null,creator:null}).then(S).catch(t=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`))}catch(t){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`)}}n(ne,"prewarmRecentRecipes");export{re as claimWarmNode,ne as prewarmRecentRecipes,ae as reapStaleSpares,oe as refillWarmPool,te as resumeWarmClaim,g as warmPoolEnabled};
@@ -377,6 +377,10 @@ export declare const CONFIG_SETTINGS_COVERAGE: {
377
377
  surface: "specialized";
378
378
  owner: string;
379
379
  };
380
+ ledger: {
381
+ surface: "specialized";
382
+ owner: string;
383
+ };
380
384
  store: {
381
385
  surface: "specialized";
382
386
  owner: string;
@@ -1 +1 @@
1
- var v=Object.defineProperty;var n=(e,t)=>v(e,"name",{value:t,configurable:!0});import{CONDENSED_HISTORY_MODES as u,MOUSE_MODE_DEFAULTS as p,WHIP_MESSAGE_MODES as d}from"../types.js";function i(e,t,o){const s=e.indexOf(t),a=s>=0?s:0;return e[(a+o+e.length)%e.length]}n(i,"cycleChoice");function c(e,t,o){const s=e.indexOf(t);return s>=0?e[(s+o+e.length)%e.length]:o>=0?e.find(a=>a>t)??e[0]:[...e].reverse().find(a=>a<t)??e[e.length-1]}n(c,"cycleNumber");function r(e,t){return e==="true"?!0:e==="false"?!1:`${t} must be true or false`}n(r,"booleanFromString");function f(e,t){if(!/^\d+$/.test(e))return`${t} must be an integer >= 0`;const o=Number(e);return Number.isSafeInteger(o)?o:`${t} must be an integer >= 0`}n(f,"nonNegativeIntegerFromString");function _(e,t){const o=f(e,t);return typeof o=="string"||o<1?`${t} must be an integer >= 1`:o}n(_,"positiveIntegerFromString");const m=[!1,"notify","apply"],w=[0,1,6,12,24,48,72,168],b=[1,2,3,4,5,6,8,10,12],l="openai-codex";function g(e,t){const o=e.providerOptions[t];if(o!==void 0)return o;const s={};return e.providerOptions[t]=s,s}n(g,"providerOptionsFor");const x=[1,2,3,4,5,6],h={schema_version:{surface:"specialized",owner:"internal schema migration"},marketplaces:{surface:"specialized",owner:"Plugins and pkg market commands"},plugins:{surface:"specialized",owner:"Plugins tab and pkg plugin commands"},auto_update:{surface:"settings",settings:{crtr:{key:"auto_update.crtr",label:"crouter updates",description:"Notify about crouter releases, install them automatically, or turn checks off.",valueConstraint:"true|false|notify|apply; true stores notify",applies:"Applies on the next crouter command.",group:"updates",order:70,format:n(e=>e.auto_update.crtr===!1?"off":e.auto_update.crtr,"format"),cycle:n((e,t)=>{e.auto_update.crtr=i(m,e.auto_update.crtr,t)},"cycle"),setFromString:n((e,t)=>{const o=t==="true"?"notify":t;return o!=="notify"&&o!=="apply"&&o!=="false"?"auto_update.crtr must be notify, apply, or false":(e.auto_update.crtr=o==="false"?!1:o,null)},"setFromString")},content:{key:"auto_update.content",label:"Content updates",description:"Notify about plugin and marketplace updates, apply them automatically, or turn checks off.",valueConstraint:"false|notify|apply",applies:"Applies on the next crouter command.",group:"updates",order:80,format:n(e=>e.auto_update.content===!1?"off":e.auto_update.content,"format"),cycle:n((e,t)=>{e.auto_update.content=i(m,e.auto_update.content,t)},"cycle"),setFromString:n((e,t)=>t!=="notify"&&t!=="apply"&&t!=="false"?"auto_update.content must be notify, apply, or false":(e.auto_update.content=t==="false"?!1:t,null),"setFromString")},interval_hours:{key:"auto_update.interval_hours",label:"Update interval",description:"Minimum hours between automatic update checks. Zero checks on every command.",valueConstraint:"integer >= 0",applies:"Applies on the next crouter command.",group:"updates",order:90,format:n(e=>`${e.auto_update.interval_hours}h`,"format"),cycle:n((e,t)=>{e.auto_update.interval_hours=c(w,e.auto_update.interval_hours,t)},"cycle"),setFromString:n((e,t)=>{const o=f(t,"auto_update.interval_hours");return typeof o=="string"?o:(e.auto_update.interval_hours=o,null)},"setFromString")}}},max_panes_per_window:{surface:"settings",setting:{key:"max_panes_per_window",label:"Maximum panes",description:"Maximum human-review panes placed in one tmux window before using another window.",valueConstraint:"integer >= 1",applies:"Applies to the next pane placement.",group:"panes",order:20,format:n(e=>String(e.max_panes_per_window),"format"),cycle:n((e,t)=>{e.max_panes_per_window=c(b,e.max_panes_per_window,t)},"cycle"),setFromString:n((e,t)=>{const o=_(t,"max_panes_per_window");return typeof o=="string"?o:(e.max_panes_per_window=o,null)},"setFromString")}},auto_open_child_viewers:{surface:"settings",setting:{key:"auto_open_child_viewers",label:"Open child panes",description:"Open each managed child beside its watched parent. Off keeps new children running in the background.",valueConstraint:"true|false",applies:"Applies to the next managed child created; independent roots still open their attended viewer.",group:"panes",order:10,format:n(e=>e.auto_open_child_viewers?"on":"off","format"),cycle:n(e=>{e.auto_open_child_viewers=!e.auto_open_child_viewers},"cycle"),setFromString:n((e,t)=>{const o=r(t,"auto_open_child_viewers");return typeof o=="string"?o:(e.auto_open_child_viewers=o,null)},"setFromString")}},brokerThresholds:{surface:"specialized",owner:"Broker limits tab"},lifecycle:{surface:"specialized",owner:"sys config set lifecycle.unattendedParkMs"},completion_bell:{surface:"settings",setting:{key:"completion_bell",label:"Completion bell",description:"Ring a short sound when the node in an attached viewer finishes a turn.",valueConstraint:"true|false",applies:"Applies on the next turn end.",group:"display",order:41,format:n(e=>e.completion_bell?"on":"off","format"),cycle:n(e=>{e.completion_bell=!e.completion_bell},"cycle"),setFromString:n((e,t)=>{const o=r(t,"completion_bell");return typeof o=="string"?o:(e.completion_bell=o,null)},"setFromString")}},working_gerunds:{surface:"specialized",owner:"sys config set working_gerunds"},whip_mode:{surface:"settings",setting:{key:"whip_mode",label:"Whip mode",description:"Play the whip animation when you send a prompt and when a viewer opens for an agent with an initial prompt.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:39,format:n(e=>e.whip_mode?"on":"off","format"),cycle:n(e=>{e.whip_mode=!e.whip_mode},"cycle"),setFromString:n((e,t)=>{const o=r(t,"whip_mode");return typeof o=="string"?o:(e.whip_mode=o,null)},"setFromString")}},page_surface:{surface:"settings",setting:{key:"page_surface",label:"Page human surface",description:"This host reads pages in a browser rather than a terminal. Agents are told the page module runs as written, HTML pages are offered, and document review and live display leave the command tree.",valueConstraint:"true|false",applies:"Applies when human command help is assembled.",group:"display",order:37,format:n(e=>e.page_surface?"on":"off","format"),cycle:n(e=>{e.page_surface=!e.page_surface},"cycle"),setFromString:n((e,t)=>{const o=r(t,"page_surface");return typeof o=="string"?o:(e.page_surface=o,null)},"setFromString")}},whip_messages:{surface:"specialized",owner:"sys config set whip_messages"},whip_message_mode:{surface:"settings",setting:{key:"whip_message_mode",label:"Whip message",description:"What the whip action sends: a random line from whip_messages, or the fixed \u201CGo faster\u201D.",valueConstraint:d.join("|"),applies:"Applies on the next attach.",group:"display",order:40,format:n(e=>e.whip_message_mode==="go-faster"?"go faster":"random","format"),cycle:n((e,t)=>{e.whip_message_mode=i(d,e.whip_message_mode,t)},"cycle"),setFromString:n((e,t)=>d.includes(t)?(e.whip_message_mode=t,null):`whip_message_mode must be one of: ${d.join("|")}`,"setFromString")}},mouse_mode_default:{surface:"settings",setting:{key:"mouse_mode_default",label:"Default mouse mode",description:"Initial mouse wheel scrolling for each attached viewer.",valueConstraint:p.join("|"),applies:"Applies on the next attach.",group:"display",order:38,format:n(e=>e.mouse_mode_default==="tmux"?"follow tmux":e.mouse_mode_default,"format"),cycle:n((e,t)=>{e.mouse_mode_default=i(p,e.mouse_mode_default,t)},"cycle"),setFromString:n((e,t)=>p.includes(t)?(e.mouse_mode_default=t,null):`mouse_mode_default must be one of: ${p.join("|")}`,"setFromString")}},live_cycles:{surface:"settings",setting:{key:"live_cycles",label:"Live cycles",description:"Trailing refresh cycles rendered at full fidelity; older cycles condense to text.",valueConstraint:"integer >= 1",applies:"Applies on the next attach.",group:"display",order:50,format:n(e=>String(e.live_cycles),"format"),cycle:n((e,t)=>{e.live_cycles=c(x,e.live_cycles,t)},"cycle"),setFromString:n((e,t)=>{const o=_(t,"live_cycles");return typeof o=="string"?o:(e.live_cycles=o,null)},"setFromString")}},condensed_history:{surface:"settings",setting:{key:"condensed_history",label:"Condensed history",description:"Messages retained from condensed cycles. Tool calls are never kept.",valueConstraint:u.join("|"),applies:"Applies on the next attach.",group:"display",order:60,format:n(e=>e.condensed_history,"format"),cycle:n((e,t)=>{e.condensed_history=i(u,e.condensed_history,t)},"cycle"),setFromString:n((e,t)=>u.includes(t)?(e.condensed_history=t,null):`condensed_history must be one of: ${u.join("|")}`,"setFromString")}},bash_tool_purpose:{surface:"settings",setting:{key:"bash_tool_purpose",label:"Bash purpose field",description:"Expose the optional purpose label to agents in the bash tool schema. Off removes the field without disabling the bash valve.",valueConstraint:"true|false",applies:"Applies on the next node session.",group:"display",order:25,format:n(e=>e.bash_tool_purpose?"on":"off","format"),cycle:n(e=>{e.bash_tool_purpose=!e.bash_tool_purpose},"cycle"),setFromString:n((e,t)=>{const o=r(t,"bash_tool_purpose");return typeof o=="string"?o:(e.bash_tool_purpose=o,null)},"setFromString")}},fold_finished_tools:{surface:"settings",setting:{key:"fold_finished_tools",label:"Fold finished tools",description:"Fold every settled tool call to its call line. Toggle live with /fold-tools.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:30,format:n(e=>e.fold_finished_tools?"on":"off","format"),cycle:n(e=>{e.fold_finished_tools=!e.fold_finished_tools},"cycle"),setFromString:n((e,t)=>{const o=r(t,"fold_finished_tools");return typeof o=="string"?o:(e.fold_finished_tools=o,null)},"setFromString")}},summarize_tool_calls:{surface:"settings",setting:{key:"summarize_tool_calls",label:"Summarize tool calls",description:"Replace completed folded tool-call groups with a one-line broker summary when available.",valueConstraint:"true|false",applies:"Applies when the next visible message closes a tool-call group.",group:"display",order:35,format:n(e=>e.summarize_tool_calls?"on":"off","format"),cycle:n(e=>{e.summarize_tool_calls=!e.summarize_tool_calls},"cycle"),setFromString:n((e,t)=>{const o=r(t,"summarize_tool_calls");return typeof o=="string"?o:(e.summarize_tool_calls=o,null)},"setFromString")}},document_port:{surface:"settings",setting:{key:"document_port",label:"Document browser port",description:"Fixed localhost port where crtrd serves editable document pages.",valueConstraint:"1-65535",applies:"Applies after daemon handover and on the next attach.",group:"display",order:37.5,format:n(e=>String(e.document_port),"format"),cycle:n((e,t)=>{e.document_port=Math.max(1,Math.min(65535,e.document_port+t))},"cycle"),setFromString:n((e,t)=>{const o=Number(t);return!/^\d+$/.test(t)||!Number.isInteger(o)||o<1||o>65535?"document_port must be an integer from 1 to 65535":(e.document_port=o,null)},"setFromString")}},detailed_tool_recaps:{surface:"settings",setting:{key:"detailed_tool_recaps",label:"Detailed tool recaps",description:"Show each document read and edited file in folded tool recaps. Off shows a compact count line instead.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:36,format:n(e=>e.detailed_tool_recaps?"on":"off","format"),cycle:n(e=>{e.detailed_tool_recaps=!e.detailed_tool_recaps},"cycle"),setFromString:n((e,t)=>{const o=r(t,"detailed_tool_recaps");return typeof o=="string"?o:(e.detailed_tool_recaps=o,null)},"setFromString")}},consolidate_replies:{surface:"settings",setting:{key:"consolidate_replies",label:"Consolidate replies",description:"Experiment: show one rewritten agent reply per message you type, with the working folded behind it (/show-working).",valueConstraint:"true|false",applies:"Applies on the next attach; the broker reads it per turn.",group:"display",order:36.5,format:n(e=>e.consolidate_replies?"on":"off","format"),cycle:n(e=>{e.consolidate_replies=!e.consolidate_replies},"cycle"),setFromString:n((e,t)=>{const o=r(t,"consolidate_replies");return typeof o=="string"?o:(e.consolidate_replies=o,null)},"setFromString")}},keybindings:{surface:"specialized",owner:"Keybindings tab"},tmux_passthrough:{surface:"specialized",owner:"Keybindings tab"},providerOptions:{surface:"settings",settings:{"openai-codex.fastMode":{key:`providerOptions.${l}.fastMode`,label:"Codex fast mode",description:"Serve Codex turns at the ChatGPT priority tier: about 1.5x faster generation for about 2x the credits. Displayed cost does not reflect the premium.",valueConstraint:"true|false",applies:"Applies on each node's next turn.",group:"providers",order:40,format:n(e=>e.providerOptions[l]?.fastMode?"on":"off","format"),cycle:n(e=>{const t=g(e,l);t.fastMode=!t.fastMode},"cycle"),setFromString:n((e,t)=>{const o=r(t,`providerOptions.${l}.fastMode`);return typeof o=="string"?o:(g(e,l).fastMode=o,null)},"setFromString")}}},modelLadders:{surface:"specialized",owner:"Models tab"},modelRoutes:{surface:"specialized",owner:"Models route declarations"},modelRouting:{surface:"specialized",owner:"Models route declarations"},kinds:{surface:"specialized",owner:"Models tab and kind registry"},page_components:{surface:"specialized",owner:"Page component catalog: product-registered page component kinds"},remoteCanvas:{surface:"specialized",owner:"canvas config commands"},api:{surface:"specialized",owner:"sys connect"},paths:{surface:"specialized",owner:"runtime layout"},store:{surface:"specialized",owner:"daemon conversation store"},runtime:{surface:"specialized",owner:"app-facing listener"},spawnEnv:{surface:"specialized",owner:"spawn environment allow-list"},bin:{surface:"specialized",owner:"bare-binary contributions on every node PATH"},humanActions:{surface:"specialized",owner:"scope-configured human completion actions"}},O=Object.keys(h);function S(){const e=[];for(const t of Object.values(h))t.surface==="settings"&&("setting"in t?e.push(t.setting):e.push(...Object.values(t.settings)));return e.sort((t,o)=>t.order-o.order)}n(S,"collectUserSettings");const y=S();function A(e){return y.find(t=>t.key===e)}n(A,"findUserSetting");function z(e){return y.filter(t=>t.group===e)}n(z,"userSettingsInGroup");export{h as CONFIG_SETTINGS_COVERAGE,O as SCOPE_CONFIG_KEYS,y as USER_SETTINGS,A as findUserSetting,z as userSettingsInGroup};
1
+ var v=Object.defineProperty;var n=(e,t)=>v(e,"name",{value:t,configurable:!0});import{CONDENSED_HISTORY_MODES as u,MOUSE_MODE_DEFAULTS as p,WHIP_MESSAGE_MODES as d}from"../types.js";function i(e,t,o){const s=e.indexOf(t),a=s>=0?s:0;return e[(a+o+e.length)%e.length]}n(i,"cycleChoice");function c(e,t,o){const s=e.indexOf(t);return s>=0?e[(s+o+e.length)%e.length]:o>=0?e.find(a=>a>t)??e[0]:[...e].reverse().find(a=>a<t)??e[e.length-1]}n(c,"cycleNumber");function r(e,t){return e==="true"?!0:e==="false"?!1:`${t} must be true or false`}n(r,"booleanFromString");function f(e,t){if(!/^\d+$/.test(e))return`${t} must be an integer >= 0`;const o=Number(e);return Number.isSafeInteger(o)?o:`${t} must be an integer >= 0`}n(f,"nonNegativeIntegerFromString");function _(e,t){const o=f(e,t);return typeof o=="string"||o<1?`${t} must be an integer >= 1`:o}n(_,"positiveIntegerFromString");const m=[!1,"notify","apply"],w=[0,1,6,12,24,48,72,168],b=[1,2,3,4,5,6,8,10,12],l="openai-codex";function g(e,t){const o=e.providerOptions[t];if(o!==void 0)return o;const s={};return e.providerOptions[t]=s,s}n(g,"providerOptionsFor");const x=[1,2,3,4,5,6],h={schema_version:{surface:"specialized",owner:"internal schema migration"},marketplaces:{surface:"specialized",owner:"Plugins and pkg market commands"},plugins:{surface:"specialized",owner:"Plugins tab and pkg plugin commands"},auto_update:{surface:"settings",settings:{crtr:{key:"auto_update.crtr",label:"crouter updates",description:"Notify about crouter releases, install them automatically, or turn checks off.",valueConstraint:"true|false|notify|apply; true stores notify",applies:"Applies on the next crouter command.",group:"updates",order:70,format:n(e=>e.auto_update.crtr===!1?"off":e.auto_update.crtr,"format"),cycle:n((e,t)=>{e.auto_update.crtr=i(m,e.auto_update.crtr,t)},"cycle"),setFromString:n((e,t)=>{const o=t==="true"?"notify":t;return o!=="notify"&&o!=="apply"&&o!=="false"?"auto_update.crtr must be notify, apply, or false":(e.auto_update.crtr=o==="false"?!1:o,null)},"setFromString")},content:{key:"auto_update.content",label:"Content updates",description:"Notify about plugin and marketplace updates, apply them automatically, or turn checks off.",valueConstraint:"false|notify|apply",applies:"Applies on the next crouter command.",group:"updates",order:80,format:n(e=>e.auto_update.content===!1?"off":e.auto_update.content,"format"),cycle:n((e,t)=>{e.auto_update.content=i(m,e.auto_update.content,t)},"cycle"),setFromString:n((e,t)=>t!=="notify"&&t!=="apply"&&t!=="false"?"auto_update.content must be notify, apply, or false":(e.auto_update.content=t==="false"?!1:t,null),"setFromString")},interval_hours:{key:"auto_update.interval_hours",label:"Update interval",description:"Minimum hours between automatic update checks. Zero checks on every command.",valueConstraint:"integer >= 0",applies:"Applies on the next crouter command.",group:"updates",order:90,format:n(e=>`${e.auto_update.interval_hours}h`,"format"),cycle:n((e,t)=>{e.auto_update.interval_hours=c(w,e.auto_update.interval_hours,t)},"cycle"),setFromString:n((e,t)=>{const o=f(t,"auto_update.interval_hours");return typeof o=="string"?o:(e.auto_update.interval_hours=o,null)},"setFromString")}}},max_panes_per_window:{surface:"settings",setting:{key:"max_panes_per_window",label:"Maximum panes",description:"Maximum human-review panes placed in one tmux window before using another window.",valueConstraint:"integer >= 1",applies:"Applies to the next pane placement.",group:"panes",order:20,format:n(e=>String(e.max_panes_per_window),"format"),cycle:n((e,t)=>{e.max_panes_per_window=c(b,e.max_panes_per_window,t)},"cycle"),setFromString:n((e,t)=>{const o=_(t,"max_panes_per_window");return typeof o=="string"?o:(e.max_panes_per_window=o,null)},"setFromString")}},auto_open_child_viewers:{surface:"settings",setting:{key:"auto_open_child_viewers",label:"Open child panes",description:"Open each managed child beside its watched parent. Off keeps new children running in the background.",valueConstraint:"true|false",applies:"Applies to the next managed child created; independent roots still open their attended viewer.",group:"panes",order:10,format:n(e=>e.auto_open_child_viewers?"on":"off","format"),cycle:n(e=>{e.auto_open_child_viewers=!e.auto_open_child_viewers},"cycle"),setFromString:n((e,t)=>{const o=r(t,"auto_open_child_viewers");return typeof o=="string"?o:(e.auto_open_child_viewers=o,null)},"setFromString")}},brokerThresholds:{surface:"specialized",owner:"Broker limits tab"},lifecycle:{surface:"specialized",owner:"sys config set lifecycle.unattendedParkMs"},completion_bell:{surface:"settings",setting:{key:"completion_bell",label:"Completion bell",description:"Ring a short sound when the node in an attached viewer finishes a turn.",valueConstraint:"true|false",applies:"Applies on the next turn end.",group:"display",order:41,format:n(e=>e.completion_bell?"on":"off","format"),cycle:n(e=>{e.completion_bell=!e.completion_bell},"cycle"),setFromString:n((e,t)=>{const o=r(t,"completion_bell");return typeof o=="string"?o:(e.completion_bell=o,null)},"setFromString")}},working_gerunds:{surface:"specialized",owner:"sys config set working_gerunds"},whip_mode:{surface:"settings",setting:{key:"whip_mode",label:"Whip mode",description:"Play the whip animation when you send a prompt and when a viewer opens for an agent with an initial prompt.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:39,format:n(e=>e.whip_mode?"on":"off","format"),cycle:n(e=>{e.whip_mode=!e.whip_mode},"cycle"),setFromString:n((e,t)=>{const o=r(t,"whip_mode");return typeof o=="string"?o:(e.whip_mode=o,null)},"setFromString")}},page_surface:{surface:"settings",setting:{key:"page_surface",label:"Page human surface",description:"This host reads pages in a browser rather than a terminal. Agents are told the page module runs as written, HTML pages are offered, and document review and live display leave the command tree.",valueConstraint:"true|false",applies:"Applies when human command help is assembled.",group:"display",order:37,format:n(e=>e.page_surface?"on":"off","format"),cycle:n(e=>{e.page_surface=!e.page_surface},"cycle"),setFromString:n((e,t)=>{const o=r(t,"page_surface");return typeof o=="string"?o:(e.page_surface=o,null)},"setFromString")}},whip_messages:{surface:"specialized",owner:"sys config set whip_messages"},whip_message_mode:{surface:"settings",setting:{key:"whip_message_mode",label:"Whip message",description:"What the whip action sends: a random line from whip_messages, or the fixed \u201CGo faster\u201D.",valueConstraint:d.join("|"),applies:"Applies on the next attach.",group:"display",order:40,format:n(e=>e.whip_message_mode==="go-faster"?"go faster":"random","format"),cycle:n((e,t)=>{e.whip_message_mode=i(d,e.whip_message_mode,t)},"cycle"),setFromString:n((e,t)=>d.includes(t)?(e.whip_message_mode=t,null):`whip_message_mode must be one of: ${d.join("|")}`,"setFromString")}},mouse_mode_default:{surface:"settings",setting:{key:"mouse_mode_default",label:"Default mouse mode",description:"Initial mouse wheel scrolling for each attached viewer.",valueConstraint:p.join("|"),applies:"Applies on the next attach.",group:"display",order:38,format:n(e=>e.mouse_mode_default==="tmux"?"follow tmux":e.mouse_mode_default,"format"),cycle:n((e,t)=>{e.mouse_mode_default=i(p,e.mouse_mode_default,t)},"cycle"),setFromString:n((e,t)=>p.includes(t)?(e.mouse_mode_default=t,null):`mouse_mode_default must be one of: ${p.join("|")}`,"setFromString")}},live_cycles:{surface:"settings",setting:{key:"live_cycles",label:"Live cycles",description:"Trailing refresh cycles rendered at full fidelity; older cycles condense to text.",valueConstraint:"integer >= 1",applies:"Applies on the next attach.",group:"display",order:50,format:n(e=>String(e.live_cycles),"format"),cycle:n((e,t)=>{e.live_cycles=c(x,e.live_cycles,t)},"cycle"),setFromString:n((e,t)=>{const o=_(t,"live_cycles");return typeof o=="string"?o:(e.live_cycles=o,null)},"setFromString")}},condensed_history:{surface:"settings",setting:{key:"condensed_history",label:"Condensed history",description:"Messages retained from condensed cycles. Tool calls are never kept.",valueConstraint:u.join("|"),applies:"Applies on the next attach.",group:"display",order:60,format:n(e=>e.condensed_history,"format"),cycle:n((e,t)=>{e.condensed_history=i(u,e.condensed_history,t)},"cycle"),setFromString:n((e,t)=>u.includes(t)?(e.condensed_history=t,null):`condensed_history must be one of: ${u.join("|")}`,"setFromString")}},bash_tool_purpose:{surface:"settings",setting:{key:"bash_tool_purpose",label:"Bash purpose field",description:"Expose the optional purpose label to agents in the bash tool schema. Off removes the field without disabling the bash valve.",valueConstraint:"true|false",applies:"Applies on the next node session.",group:"display",order:25,format:n(e=>e.bash_tool_purpose?"on":"off","format"),cycle:n(e=>{e.bash_tool_purpose=!e.bash_tool_purpose},"cycle"),setFromString:n((e,t)=>{const o=r(t,"bash_tool_purpose");return typeof o=="string"?o:(e.bash_tool_purpose=o,null)},"setFromString")}},fold_finished_tools:{surface:"settings",setting:{key:"fold_finished_tools",label:"Fold finished tools",description:"Fold every settled tool call to its call line. Toggle live with /fold-tools.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:30,format:n(e=>e.fold_finished_tools?"on":"off","format"),cycle:n(e=>{e.fold_finished_tools=!e.fold_finished_tools},"cycle"),setFromString:n((e,t)=>{const o=r(t,"fold_finished_tools");return typeof o=="string"?o:(e.fold_finished_tools=o,null)},"setFromString")}},summarize_tool_calls:{surface:"settings",setting:{key:"summarize_tool_calls",label:"Summarize tool calls",description:"Replace completed folded tool-call groups with a one-line broker summary when available.",valueConstraint:"true|false",applies:"Applies when the next visible message closes a tool-call group.",group:"display",order:35,format:n(e=>e.summarize_tool_calls?"on":"off","format"),cycle:n(e=>{e.summarize_tool_calls=!e.summarize_tool_calls},"cycle"),setFromString:n((e,t)=>{const o=r(t,"summarize_tool_calls");return typeof o=="string"?o:(e.summarize_tool_calls=o,null)},"setFromString")}},document_port:{surface:"settings",setting:{key:"document_port",label:"Document browser port",description:"Fixed localhost port where crtrd serves editable document pages.",valueConstraint:"1-65535",applies:"Applies after daemon handover and on the next attach.",group:"display",order:37.5,format:n(e=>String(e.document_port),"format"),cycle:n((e,t)=>{e.document_port=Math.max(1,Math.min(65535,e.document_port+t))},"cycle"),setFromString:n((e,t)=>{const o=Number(t);return!/^\d+$/.test(t)||!Number.isInteger(o)||o<1||o>65535?"document_port must be an integer from 1 to 65535":(e.document_port=o,null)},"setFromString")}},detailed_tool_recaps:{surface:"settings",setting:{key:"detailed_tool_recaps",label:"Detailed tool recaps",description:"Show each document read and edited file in folded tool recaps. Off shows a compact count line instead.",valueConstraint:"true|false",applies:"Applies on the next attach.",group:"display",order:36,format:n(e=>e.detailed_tool_recaps?"on":"off","format"),cycle:n(e=>{e.detailed_tool_recaps=!e.detailed_tool_recaps},"cycle"),setFromString:n((e,t)=>{const o=r(t,"detailed_tool_recaps");return typeof o=="string"?o:(e.detailed_tool_recaps=o,null)},"setFromString")}},consolidate_replies:{surface:"settings",setting:{key:"consolidate_replies",label:"Consolidate replies",description:"Experiment: show one rewritten agent reply per message you type, with the working folded behind it (/show-working).",valueConstraint:"true|false",applies:"Applies on the next attach; the broker reads it per turn.",group:"display",order:36.5,format:n(e=>e.consolidate_replies?"on":"off","format"),cycle:n(e=>{e.consolidate_replies=!e.consolidate_replies},"cycle"),setFromString:n((e,t)=>{const o=r(t,"consolidate_replies");return typeof o=="string"?o:(e.consolidate_replies=o,null)},"setFromString")}},keybindings:{surface:"specialized",owner:"Keybindings tab"},tmux_passthrough:{surface:"specialized",owner:"Keybindings tab"},providerOptions:{surface:"settings",settings:{"openai-codex.fastMode":{key:`providerOptions.${l}.fastMode`,label:"Codex fast mode",description:"Serve Codex turns at the ChatGPT priority tier: about 1.5x faster generation for about 2x the credits. Displayed cost does not reflect the premium.",valueConstraint:"true|false",applies:"Applies on each node's next turn.",group:"providers",order:40,format:n(e=>e.providerOptions[l]?.fastMode?"on":"off","format"),cycle:n(e=>{const t=g(e,l);t.fastMode=!t.fastMode},"cycle"),setFromString:n((e,t)=>{const o=r(t,`providerOptions.${l}.fastMode`);return typeof o=="string"?o:(g(e,l).fastMode=o,null)},"setFromString")}}},modelLadders:{surface:"specialized",owner:"Models tab"},modelRoutes:{surface:"specialized",owner:"Models route declarations"},modelRouting:{surface:"specialized",owner:"Models route declarations"},kinds:{surface:"specialized",owner:"Models tab and kind registry"},page_components:{surface:"specialized",owner:"Page component catalog: product-registered page component kinds"},remoteCanvas:{surface:"specialized",owner:"canvas config commands"},api:{surface:"specialized",owner:"sys connect"},paths:{surface:"specialized",owner:"runtime layout"},ledger:{surface:"specialized",owner:"money ledger (take_pct)"},store:{surface:"specialized",owner:"daemon conversation store"},runtime:{surface:"specialized",owner:"app-facing listener"},spawnEnv:{surface:"specialized",owner:"spawn environment allow-list"},bin:{surface:"specialized",owner:"bare-binary contributions on every node PATH"},humanActions:{surface:"specialized",owner:"scope-configured human completion actions"}},O=Object.keys(h);function S(){const e=[];for(const t of Object.values(h))t.surface==="settings"&&("setting"in t?e.push(t.setting):e.push(...Object.values(t.settings)));return e.sort((t,o)=>t.order-o.order)}n(S,"collectUserSettings");const y=S();function A(e){return y.find(t=>t.key===e)}n(A,"findUserSetting");function z(e){return y.filter(t=>t.group===e)}n(z,"userSettingsInGroup");export{h as CONFIG_SETTINGS_COVERAGE,O as SCOPE_CONFIG_KEYS,y as USER_SETTINGS,A as findUserSetting,z as userSettingsInGroup};
@@ -1,24 +1,24 @@
1
- var Y=Object.defineProperty;var i=(e,n)=>Y(e,"name",{value:n,configurable:!0});import{randomUUID as Q}from"node:crypto";import{createServer as W}from"node:http";import{Router as V}from"./router.js";import{toErrorBody as q}from"./map.js";import{objectRoutes as K}from"./handlers/objects.js";import{customObjectRoutes as Z}from"./handlers/custom-objects.js";import{checkRoutes as ee}from"./handlers/check.js";import{docRoutes as te}from"./handlers/docs.js";import{relationRoutes as re}from"./handlers/relations.js";import{schemaRoutes as ne}from"./handlers/schemas.js";import{OPERATIONS as ae}from"./operations.js";import{runtimeReadiness as oe}from"../readiness.js";import{errorCodes as $}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as ie,RUNTIME_VERSION_HEADER as se,minimumRuntimeRefusal as ue}from"../../api/runtime-version.js";import{CONTRACT_HEADER as ce,CONTRACT_LEVEL as X,REQUIRED_CONTRACT_HEADER as de,contractRefusal as le}from"../../api/contract.js";import{crtrVersion as B}from"../../shared/crtr-version.js";import{newTraceId as me,parseTraceparent as fe}from"../../shared/traceparent.js";import{AppPrincipalResolver as pe}from"./principal.js";import{isDaemonRoute as he,runtimeOwner as we,servePeer as z}from"../peer/ingress.js";import{applySyncNotice as ye}from"./sync-notice.js";import{ownMachineId as _e}from"../../core/peer/directory.js";import{handleRunOperation as ve,integer as ge}from"./handlers/runs.js";import{llmCallerOf as Re,parseLlmRequest as Oe,runLlm as be}from"../../core/llm/run.js";import{parseUsageMonth as Ee,usageFor as Ae}from"../../core/usage/ledger.js";import{capFields as Te}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as Se,MODEL_CONTEXT_BODY_MAX_BYTES as Ne}from"../../core/llm/body-limits.js";import{RunError as m,runIsRunning as Ce}from"../../core/runs/operations.js";import{requireRun as J}from"./router.js";import{deferHead as Ie}from"./deferred-head.js";import{readRunEvents as G,registerGrantStream as Pe,subscribeRunEvents as ke}from"../../core/runs/events.js";import{activeGrant as F,payerOfGrant as He}from"../../core/grants/mirror.js";async function Me(e){if(await He(e)==="app")throw new m(401,"grant_revoked","this app-paid grant is no longer active");return null}i(Me,"appPaidGone");import{releaseGrantWaiters as De}from"../../core/grants/watch.js";import{emitEvent as je}from"../../core/events/emit.js";import{runNotices as xe}from"../run-notices.js";import{handleVendorSignIn as Be,isVendorSignInPath as Je}from"./vendor-signin.js";import{listAppProfiles as Le}from"./handlers/app-profiles.js";import{handleTransferDownload as Ue,handleTransferOperation as Ve,TRANSFER_OPERATIONS as $e}from"./handlers/transfer.js";import{handleQuestionOperation as Xe,QUESTION_OPERATIONS as ze}from"./handlers/questions.js";import{removeVendorAccount as Ge,vendorStatus as Fe}from"./handlers/vendor-status.js";import{handleMemoryOperation as Ye,MEMORY_OPERATIONS as Qe}from"./handlers/memory.js";import{abortOnClose as We,callerFromApp as qe,handleProviderOperation as Ke,PROVIDER_OPERATIONS as Ze,providerFailure as et}from"./handlers/providers.js";function tt(e){return Object.prototype.hasOwnProperty.call($,e)?$[e]:void 0}i(tt,"fixedRow");function rt(e){const n=tt(e);return n?n.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}i(rt,"errorType");function nt(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:n,...o}=e;return o}i(nt,"appDetails");function x(e,n,o){const p=nt(e.details);return{error:{code:e.code,message:e.message,...p===void 0?{}:{details:p},type:rt(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:n,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...Te(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}i(x,"envelope");function at(e,n,o,p,f){const l=n instanceof m?n:new m(500,"server_failure","runtime request failed");if(n instanceof m||console.error("[app-listener]",`trace_id=${p}`,n),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
2
- data: ${JSON.stringify(x(l,o,f))}
1
+ var Y=Object.defineProperty;var i=(e,n)=>Y(e,"name",{value:n,configurable:!0});import{randomUUID as Q}from"node:crypto";import{createServer as W}from"node:http";import{Router as V,causedByOf as q}from"./router.js";import{toErrorBody as K}from"./map.js";import{objectRoutes as Z}from"./handlers/objects.js";import{customObjectRoutes as ee}from"./handlers/custom-objects.js";import{checkRoutes as te}from"./handlers/check.js";import{chargeRoutes as re}from"./handlers/charges.js";import{docRoutes as ne}from"./handlers/docs.js";import{relationRoutes as ae}from"./handlers/relations.js";import{schemaRoutes as oe}from"./handlers/schemas.js";import{OPERATIONS as ie}from"./operations.js";import{runtimeReadiness as se}from"../readiness.js";import{errorCodes as $}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as ue,RUNTIME_VERSION_HEADER as ce,minimumRuntimeRefusal as de}from"../../api/runtime-version.js";import{CONTRACT_HEADER as le,CONTRACT_LEVEL as X,REQUIRED_CONTRACT_HEADER as me,contractRefusal as fe}from"../../api/contract.js";import{crtrVersion as J}from"../../shared/crtr-version.js";import{newTraceId as pe,parseTraceparent as he}from"../../shared/traceparent.js";import{AppPrincipalResolver as we}from"./principal.js";import{isDaemonRoute as ye,runtimeOwner as _e,servePeer as z}from"../peer/ingress.js";import{applySyncNotice as ve}from"./sync-notice.js";import{ownMachineId as ge}from"../../core/peer/directory.js";import{handleRunOperation as Re,integer as Oe}from"./handlers/runs.js";import{llmCallerOf as be,parseLlmRequest as Ee,runLlm as Ae}from"../../core/llm/run.js";import{parseUsageMonth as Te,usageFor as Se}from"../../core/ledger/index.js";import{capFields as Ne}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as Ce,MODEL_CONTEXT_BODY_MAX_BYTES as Ie}from"../../core/llm/body-limits.js";import{RunError as m,runIsRunning as Pe}from"../../core/runs/operations.js";import{requireRun as L}from"./router.js";import{deferHead as ke}from"./deferred-head.js";import{readRunEvents as G,registerGrantStream as He,subscribeRunEvents as Me}from"../../core/runs/events.js";import{activeGrant as F,payerOfGrant as De}from"../../core/grants/mirror.js";async function je(e){if(await De(e)==="app")throw new m(401,"grant_revoked","this app-paid grant is no longer active");return null}i(je,"appPaidGone");import{releaseGrantWaiters as xe}from"../../core/grants/watch.js";import{emitEvent as Be}from"../../core/events/emit.js";import{runNotices as Je}from"../run-notices.js";import{handleVendorSignIn as Le,isVendorSignInPath as Ue}from"./vendor-signin.js";import{listAppProfiles as Ve}from"./handlers/app-profiles.js";import{handleTransferDownload as $e,handleTransferOperation as Xe,TRANSFER_OPERATIONS as ze}from"./handlers/transfer.js";import{handleQuestionOperation as Ge,QUESTION_OPERATIONS as Fe}from"./handlers/questions.js";import{removeVendorAccount as Ye,vendorStatus as Qe}from"./handlers/vendor-status.js";import{handleMemoryOperation as We,MEMORY_OPERATIONS as qe}from"./handlers/memory.js";import{abortOnClose as Ke,callerFromApp as Ze,handleProviderOperation as et,PROVIDER_OPERATIONS as tt,providerFailure as rt}from"./handlers/providers.js";function nt(e){return Object.prototype.hasOwnProperty.call($,e)?$[e]:void 0}i(nt,"fixedRow");function at(e){const n=nt(e);return n?n.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}i(at,"errorType");function ot(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:n,...o}=e;return o}i(ot,"appDetails");function B(e,n,o){const p=ot(e.details);return{error:{code:e.code,message:e.message,...p===void 0?{}:{details:p},type:at(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:n,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...Ne(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}i(B,"envelope");function it(e,n,o,p,f){const d=n instanceof m?n:new m(500,"server_failure","runtime request failed");if(n instanceof m||console.error("[app-listener]",`trace_id=${p}`,n),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
2
+ data: ${JSON.stringify(B(d,o,f))}
3
3
 
4
- `);return}e.writeHead(l.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...l.code==="all_routes_exhausted"?{"Retry-After":String(l.details.retry_after_s)}:{}}),e.end(JSON.stringify(x(l,o,f)))}i(at,"fail");function L(e){return Array.isArray(e)?e[0]:e}i(L,"headerValue");function g(e,n,o){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}i(g,"json");async function C(e,n=Se){const o=[];let p=0;for await(const f of e){if(p+=f.length,p>n)throw new m(400,"invalid_request","request body too large");o.push(f)}if(p)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new m(400,"invalid_request","invalid JSON body")}}i(C,"bodyOf");function ot(e,n){const o=e.headers["last-event-id"]??n.get("after");if(Array.isArray(o))throw new m(400,"invalid_request","invalid cursor","after");return ge(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}i(ot,"cursor");function it(e){return`id: ${e.sequence_number}
4
+ `);return}e.writeHead(d.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...d.code==="all_routes_exhausted"?{"Retry-After":String(d.details.retry_after_s)}:{}}),e.end(JSON.stringify(B(d,o,f)))}i(it,"fail");function U(e){return Array.isArray(e)?e[0]:e}i(U,"headerValue");function g(e,n,o){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}i(g,"json");async function C(e,n=Ce){const o=[];let p=0;for await(const f of e){if(p+=f.length,p>n)throw new m(400,"invalid_request","request body too large");o.push(f)}if(p)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new m(400,"invalid_request","invalid JSON body")}}i(C,"bodyOf");function st(e,n){const o=e.headers["last-event-id"]??n.get("after");if(Array.isArray(o))throw new m(400,"invalid_request","invalid cursor","after");return Oe(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}i(st,"cursor");function ut(e){return`id: ${e.sequence_number}
5
5
  event: ${e.type}
6
6
  data: ${JSON.stringify(e)}
7
7
 
8
- `}i(it,"frame");const st=6e4;async function ut(e,n,o,p,f,l,E,I={},H){await J(p,o);let w=await G(o,f);if(f>w.latest_sequence)throw new m(400,"invalid_request","cursor is beyond the run","after");if(f<w.latest_sequence&&(w.earliest_sequence===null||f<w.earliest_sequence-1))throw new m(409,"stream_gap","events have expired",void 0,{earliest_sequence:w.earliest_sequence,latest_sequence:w.latest_sequence});if(n.destroyed||e.destroyed)return n.destroy(),Promise.resolve();n.writeHead(200,{"Content-Type":E==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),E==="sse"?n.write(`: connected
8
+ `}i(ut,"frame");const ct=6e4;async function dt(e,n,o,p,f,d,E,I={},M){await L(p,o);let w=await G(o,f);if(f>w.latest_sequence)throw new m(400,"invalid_request","cursor is beyond the run","after");if(f<w.latest_sequence&&(w.earliest_sequence===null||f<w.earliest_sequence-1))throw new m(409,"stream_gap","events have expired",void 0,{earliest_sequence:w.earliest_sequence,latest_sequence:w.latest_sequence});if(n.destroyed||e.destroyed)return n.destroy(),Promise.resolve();n.writeHead(200,{"Content-Type":E==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),E==="sse"?n.write(`: connected
9
9
 
10
- `):n.flushHeaders();let T=f;const r=await xe().streamOpened(o);let t=!1,y=!1,O=!1,A;const P=new Promise(c=>{A=c}),_=i(()=>{t||(t=!0,r(T).catch(c=>console.error("[app-listener]",...H===void 0?[]:[`trace_id=${H}`],c)),clearInterval(u),clearInterval(N),k(),D(),n.off("close",_),n.off("drain",h),n.end(),A())},"end"),h=i(()=>{O=!1,a()},"onDrain"),R=i(c=>{t||n.write(E==="sse"?`event: error
11
- data: ${JSON.stringify(x(c,l,o))}
10
+ `):n.flushHeaders();let T=f;const r=await Je().streamOpened(o);let t=!1,y=!1,b=!1,A;const P=new Promise(u=>{A=u}),_=i(()=>{t||(t=!0,r(T).catch(u=>console.error("[app-listener]",...M===void 0?[]:[`trace_id=${M}`],u)),clearInterval(N),clearInterval(O),H(),j(),n.off("close",_),n.off("drain",h),n.end(),A())},"end"),h=i(()=>{b=!1,a()},"onDrain"),R=i(u=>{t||n.write(E==="sse"?`event: error
11
+ data: ${JSON.stringify(B(u,d,o))}
12
12
 
13
- `:`${JSON.stringify({type:"error",...x(c,l,o)})}
14
- `),_()},"error"),a=i(async()=>{if(!(t||y)){y=!0;try{if(!await S()){M();return}if(await J(p,o),w=await G(o,T),w.backlog_count>1e3||w.backlog_bytes>32*1024*1024){R(new m(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:T}));return}for(const c of w.events){if(O)break;O=!n.write(E==="sse"?it(c):`${JSON.stringify(c)}
15
- `),T=c.sequence_number}}catch(c){R(c instanceof m?c:new m(500,"server_failure","stream failed"))}finally{y=!1}}},"flush"),M=i(()=>R(new m(401,"grant_revoked","grant is not active")),"revoked"),S=i(async()=>"class"in p||await F(p.grant)!==null,"grantActive"),k=await ke(o,a),D="class"in p?()=>{}:Pe(p.grant,M),u=setInterval(()=>{!t&&!O&&E==="sse"&&n.write(`: keepalive
13
+ `:`${JSON.stringify({type:"error",...B(u,d,o)})}
14
+ `),_()},"error"),a=i(async()=>{if(!(t||y)){y=!0;try{if(!await S()){D();return}if(await L(p,o),w=await G(o,T),w.backlog_count>1e3||w.backlog_bytes>32*1024*1024){R(new m(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:T}));return}for(const u of w.events){if(b)break;b=!n.write(E==="sse"?ut(u):`${JSON.stringify(u)}
15
+ `),T=u.sequence_number}}catch(u){R(u instanceof m?u:new m(500,"server_failure","stream failed"))}finally{y=!1}}},"flush"),D=i(()=>R(new m(401,"grant_revoked","grant is not active")),"revoked"),S=i(async()=>"class"in p||await F(p.grant)!==null,"grantActive"),H=await Me(o,a),j="class"in p?()=>{}:He(p.grant,D),N=setInterval(()=>{!t&&!b&&E==="sse"&&n.write(`: keepalive
16
16
 
17
- `)},15e3),j=I.idleMs??st,s=I.isRunning??Ce;let v=Date.now(),d=T;const b=i(async()=>{if(t||E!=="sse")return;const c=Date.now();let U=!0;try{U=await s(o)}catch{}if(!t){if(U||T!==d){v=c,d=T;return}c-v<j||O||(n.write(`event: idle
17
+ `)},15e3),c=I.idleMs??ct,x=I.isRunning??Pe;let s=Date.now(),v=T;const l=i(async()=>{if(t||E!=="sse")return;const u=Date.now();let k=!0;try{k=await x(o)}catch{}if(!t){if(k||T!==v){s=u,v=T;return}u-s<c||b||(n.write(`event: idle
18
18
  data: {}
19
19
 
20
- `),_())}},"checkIdle"),N=setInterval(()=>{b().catch(c=>je({level:"error",event:"api.run_stream.idle_check_failed",error:c}))},I.idleCheckMs??1e3);return N.unref(),n.on("drain",h),n.on("close",_),await a(),P}i(ut,"streamRunEvents");async function qt(e,n,o,p={}){const f=e.listener;if(!e.issuer||!e.audience||!f?.address||!Number.isInteger(f.port)||f.port<1||f.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(f.address))throw new Error("runtime listener must bind a specific address");const l=new pe(e.issuer,e.audience,o,e.jwksUrl),E=new V,I=new Map;for(const r of ae.filter(t=>t.stage!==void 0)){const t=i(()=>({status:500}),"handler");E.register({method:r.method,pattern:r.path,handler:t}),I.set(t,r)}const H=new V().registerAll(K).registerAll(Z).registerAll(te).registerAll(ne).registerAll(re).registerAll(ee),w=W((r,t)=>{(async()=>{Ie(r,t,p.deferHead);const y=Q();t.setHeader("Request-Id",y);const O=fe(L(r.headers.traceparent))??me();t.setHeader(se,B()),t.setHeader(ce,X);let A;try{const P=L(r.headers[ie.toLowerCase()]),_=ue(P,B())??le(L(r.headers[de.toLowerCase()]),X,{legacyMinimum:P,runtimeVersion:B()});if(_!==null)throw _.status===400?new m(400,_.code,_.message,_.param):new m(426,_.code,_.message,void 0,_.details);const h=new URL(r.url??"/","http://runtime.local");if(Je(h.pathname)){await Be(r,t,h,l);return}const R=E.match(r.method??"GET",h.pathname),a=R?I.get(R.handler):void 0,M=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status"||a?.name==="runtime.vendor-account-remove";let S,k;if(!M&&r.headers.authorization!==void 0)try{S=await l.verifyCall(r.headers.authorization)}catch(s){k=s}const D={issuer:e.issuer,jwks:l.jwks,audience:i(async()=>e.audience,"audience"),owner:we,self:_e,syncGrants:o,ready:i(async()=>l.isReady()&&await n(),"ready")};if(S?.chain[0]?.sub.startsWith("runtime:")){await z(r,t,D,S);return}if(S===void 0&&a===void 0&&await he(r.method??"GET",h.pathname)){await z(r,t,D,{status:401,code:"unauthorized",message:k===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const s=await n(),v=await oe({jwksReady:l.isReady(),grantsReady:i(()=>s,"grantsReady")});g(t,v.ready?200:503,v);return}if((r.method!=="GET"||h.pathname!=="/v1/health")&&(!l.isReady()||!await n()))throw new m(503,"runtime_starting","runtime_starting");if(!R||!a)throw new m(404,"not_found","unknown operation");if(A=R.params.run_id,a.name==="health"){g(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await ye(await l.verifySyncNotice(r.headers.authorization),o,y),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await l.verifyDirectoryRead(r.headers.authorization,"vendor_status"),g(t,200,Fe());return}if(a.name==="runtime.vendor-account-remove"){await l.verifyDirectoryRead(r.headers.authorization,"vendor_account_remove"),g(t,200,await Ge(await C(r)));return}if(S===void 0)throw k??new m(401,"unauthorized","a directory access token is required");const u=await l.resolveVerified(S,a.scope);if(t.setHeader("Request-Id",y),A&&await J(u,A,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const s=H.match(a.method,h.pathname);if(!s)throw new m(404,"not_found","unknown operation");const v={method:a.method,path:h.pathname,params:s.params,query:h.searchParams,body:await C(r,s.maxBodyBytes),ceiling:u.resolved,principal:{class:"app",app:u.grantee,scopes:u.resolved,sub:u.sub},req:r,res:t};let d;try{d=await s.handler(v)}catch(b){const{status:N,body:c}=q(b);throw N>=500&&console.error("[app-listener]",`trace_id=${O}`,b),new m(N,c.error.code,c.error.message,void 0,c.error.details)}if(t.headersSent)return;if(d.rawBody!==void 0||d.status===204||d.body===void 0){t.writeHead(d.status,d.headers??{}),t.end(d.rawBody);return}t.writeHead(d.status,{"Content-Type":"application/json; charset=utf-8",...d.headers??{}}),t.end(JSON.stringify(d.body));return}if(a.stream==="bytes"){await Ue(r,t,u,h.searchParams);return}if(a.stream){await ut(r,t,A,u,ot(r,h.searchParams),y,"sse",p.stream,O);return}if(a.name==="llm"){const s=Oe(await C(r,Ne)),v=new AbortController,d=i(()=>v.abort(),"abort");t.on("close",d);try{const b=await be(s,v.signal,s.stream?N=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(N)}
20
+ `),_())}},"checkIdle"),O=setInterval(()=>{l().catch(u=>Be({level:"error",event:"api.run_stream.idle_check_failed",error:u}))},I.idleCheckMs??1e3);return O.unref(),n.on("drain",h),n.on("close",_),await a(),P}i(dt,"streamRunEvents");async function er(e,n,o,p={}){const f=e.listener;if(!e.issuer||!e.audience||!f?.address||!Number.isInteger(f.port)||f.port<1||f.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(f.address))throw new Error("runtime listener must bind a specific address");const d=new we(e.issuer,e.audience,o,e.jwksUrl),E=new V,I=new Map;for(const r of ie.filter(t=>t.stage!==void 0)){const t=i(()=>({status:500}),"handler");E.register({method:r.method,pattern:r.path,handler:t}),I.set(t,r)}const M=new V().registerAll(Z).registerAll(ee).registerAll(ne).registerAll(oe).registerAll(ae).registerAll(te).registerAll(re),w=W((r,t)=>{(async()=>{ke(r,t,p.deferHead);const y=Q();t.setHeader("Request-Id",y);const b=he(U(r.headers.traceparent))??pe();t.setHeader(ce,J()),t.setHeader(le,X);let A;try{const P=U(r.headers[ue.toLowerCase()]),_=de(P,J())??fe(U(r.headers[me.toLowerCase()]),X,{legacyMinimum:P,runtimeVersion:J()});if(_!==null)throw _.status===400?new m(400,_.code,_.message,_.param):new m(426,_.code,_.message,void 0,_.details);const h=new URL(r.url??"/","http://runtime.local");if(Ue(h.pathname)){await Le(r,t,h,d);return}const R=E.match(r.method??"GET",h.pathname),a=R?I.get(R.handler):void 0,D=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status"||a?.name==="runtime.vendor-account-remove";let S,H;if(!D&&r.headers.authorization!==void 0)try{S=await d.verifyCall(r.headers.authorization)}catch(s){H=s}const j={issuer:e.issuer,jwks:d.jwks,audience:i(async()=>e.audience,"audience"),owner:_e,self:ge,syncGrants:o,ready:i(async()=>d.isReady()&&await n(),"ready")};if(S?.chain[0]?.sub.startsWith("runtime:")){await z(r,t,j,S);return}if(S===void 0&&a===void 0&&await ye(r.method??"GET",h.pathname)){await z(r,t,j,{status:401,code:"unauthorized",message:H===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const s=await n(),v=await se({jwksReady:d.isReady(),grantsReady:i(()=>s,"grantsReady")});g(t,v.ready?200:503,v);return}if((r.method!=="GET"||h.pathname!=="/v1/health")&&(!d.isReady()||!await n()))throw new m(503,"runtime_starting","runtime_starting");if(!R||!a)throw new m(404,"not_found","unknown operation");A=R.params.run_id;const N=q(r.headers);if(a.name==="health"){g(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await ve(await d.verifySyncNotice(r.headers.authorization),o,y),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_status"),g(t,200,Qe());return}if(a.name==="runtime.vendor-account-remove"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_account_remove"),g(t,200,await Ye(await C(r)));return}if(S===void 0)throw H??new m(401,"unauthorized","a directory access token is required");const c=await d.resolveVerified(S,a.scope);if(t.setHeader("Request-Id",y),A&&await L(c,A,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const s=M.match(a.method,h.pathname);if(!s)throw new m(404,"not_found","unknown operation");const v={...N===void 0?{}:{causedBy:N},method:a.method,path:h.pathname,params:s.params,query:h.searchParams,body:await C(r,s.maxBodyBytes),ceiling:c.resolved,principal:{class:"app",app:c.grantee,scopes:c.resolved,sub:c.sub},req:r,res:t};let l;try{l=await s.handler(v)}catch(O){const{status:u,body:k}=K(O);throw u>=500&&console.error("[app-listener]",`trace_id=${b}`,O),new m(u,k.error.code,k.error.message,void 0,k.error.details)}if(t.headersSent)return;if(l.rawBody!==void 0||l.status===204||l.body===void 0){t.writeHead(l.status,l.headers??{}),t.end(l.rawBody);return}t.writeHead(l.status,{"Content-Type":"application/json; charset=utf-8",...l.headers??{}}),t.end(JSON.stringify(l.body));return}if(a.stream==="bytes"){await $e(r,t,c,h.searchParams);return}if(a.stream){await dt(r,t,A,c,st(r,h.searchParams),y,"sse",p.stream,b);return}if(a.name==="llm"){const s=Ee(await C(r,Ie)),v=new AbortController,l=i(()=>v.abort(),"abort");t.on("close",l);try{const O=await Ae(s,v.signal,s.stream?u=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(u)}
21
21
 
22
- `)}:void 0,void 0,{grantee:u.grantee,spend_cap:u.spend_cap},Re(await F(u.grant)??await Me(u.grant)));s.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
22
+ `)}:void 0,void 0,{grantee:c.grantee,sub:c.sub,spend_cap:c.spend_cap,request:y},be(await F(c.grant)??await je(c.grant)),N);s.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
23
23
 
24
- `)):g(t,200,b.completion)}finally{t.off("close",d)}return}if(a.name==="usage.get"){g(t,200,await Ae(u.grantee,u.spend_cap,Ee(h.searchParams.get("month"))));return}if(a.name==="profile.list"){g(t,200,Le(u));return}if(ze.has(a.name)){const s=await Xe(a.name,u,R.params.question_id,a.method==="POST"?await C(r):void 0);g(t,s.status,s.body);return}if(Ze.has(a.name)){const{signal:s,release:v}=We(t);try{const d=await Ke(a.name,qe(u),{params:R.params,body:a.method==="POST"?await C(r):void 0,query:h.searchParams},{requestId:y,traceId:O,signal:s});g(t,d.status,d.body)}catch(d){const b=et(d,y,!0);t.writeHead(b.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...b.headers}),t.end(JSON.stringify(b.body))}finally{v()}return}if(Qe.has(a.name)){const s=await Ye(a.name,{class:"app",app:u.grantee,scopes:u.resolved},h.searchParams);g(t,s.status,s.body);return}if($e.has(a.name)){const s=await Ve(a,u,R.params,h.searchParams,await C(r));g(t,s.status,s.body);return}const j=await ve(a,u,A,h.searchParams,await C(r),r.headers["idempotency-key"]);g(t,j.status,j.body)}catch(P){at(t,P,y,O,A)}})()});return{ready:new Promise((r,t)=>{w.once("error",t),w.listen(f.port,f.address,()=>{w.off("error",t),r()})}),close:i(async()=>{l.close(),De(),w.closeAllConnections(),await new Promise((r,t)=>w.close(y=>y?t(y):r()))},"close")}}i(qt,"createAppListener");export{st as RUN_STREAM_IDLE_MS,qt as createAppListener,ot as cursor,ut as streamRunEvents};
24
+ `)):g(t,200,O.completion)}finally{t.off("close",l)}return}if(a.name==="usage.get"){g(t,200,await Se(c.grantee,Te(h.searchParams.get("month"))));return}if(a.name==="profile.list"){g(t,200,Ve(c));return}if(Fe.has(a.name)){const s=await Ge(a.name,c,R.params.question_id,a.method==="POST"?await C(r):void 0);g(t,s.status,s.body);return}if(tt.has(a.name)){const{signal:s,release:v}=Ke(t);try{const l=await et(a.name,Ze(c),{params:R.params,body:a.method==="POST"?await C(r):void 0,query:h.searchParams},{requestId:y,traceId:b,signal:s,...N===void 0?{}:{causedBy:N}});g(t,l.status,l.body)}catch(l){const O=rt(l,y,!0);t.writeHead(O.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...O.headers}),t.end(JSON.stringify(O.body))}finally{v()}return}if(qe.has(a.name)){const s=await We(a.name,{class:"app",app:c.grantee,scopes:c.resolved},h.searchParams);g(t,s.status,s.body);return}if(ze.has(a.name)){const s=await Xe(a,c,R.params,h.searchParams,await C(r));g(t,s.status,s.body);return}const x=await Re(a,c,A,h.searchParams,await C(r),r.headers["idempotency-key"],N);g(t,x.status,x.body)}catch(P){it(t,P,y,b,A)}})()});return{ready:new Promise((r,t)=>{w.once("error",t),w.listen(f.port,f.address,()=>{w.off("error",t),r()})}),close:i(async()=>{d.close(),xe(),w.closeAllConnections(),await new Promise((r,t)=>w.close(y=>y?t(y):r()))},"close")}}i(er,"createAppListener");export{ct as RUN_STREAM_IDLE_MS,er as createAppListener,st as cursor,dt as streamRunEvents};
@@ -1 +1 @@
1
- var B=Object.defineProperty;var h=(t,o)=>B(t,"name",{value:o,configurable:!0});import{killBashJobObject as E,recordBashJobObject as J}from"../../../core/spaces/stop.js";import{readerFor as P}from"../reader.js";import{join as $}from"node:path";import{createFileBeneath as w,existsBeneath as m,unlinkBeneath as A}from"../../../core/spaces/open-beneath.js";import{launchAppProcess as q,appProcessSandboxed as O}from"../../../core/spaces/process.js";import{BASH_JOB_SUPERVISOR_SCRIPT as N}from"../../../core/bash-job-supervisor.js";import{resolveAdmittedHostCommand as L}from"../../../core/runtime/spawn-env.js";import{requireCurrentExecution as _}from"./broker-recovery.js";import{isSafeNodeId as T}from"../../../core/canvas/paths.js";import{contextDir as v}from"../../../core/canvas/node-agent-paths.js";import{getNode as j}from"../../../core/canvas/canvas.js";import{isBrokerLive as D}from"../../../core/runtime/model-swap.js";import{assertNotFinalized as R}from"../../../core/runtime/reopen.js";import{reviveNode as C}from"../../../core/runtime/revive.js";import{activeBackgroundBashJobs as z,bashJobPaths as k,isBashJobProcessGroupAlive as F,readJobPgid as M,readJobPgidIdentity as G,isSafeBashJobId as I,readBashNiceness as H,stopBackgroundBashJob as Z}from"../../../core/bash-jobs.js";import{ApiError as i}from"../../../api/index.js";import{notFound as U}from"../../../core/errors.js";import{freshChildNodeExecPath as V}from"../../../core/runtime/branded-host.js";async function f(t){const o=t.params.id;if(o===void 0||!T(o))throw new i(400,"invalid_node_id",`invalid node id: ${JSON.stringify(o)}`);if(await j(o)===null)throw U(`unknown node: ${o}`,{received:o});const d=t.params.jobId;if(d!==void 0){if(!I(d))throw new i(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(d)}`);return{nodeId:o,jobId:d,dir:await v(o)}}return{nodeId:o,dir:await v(o)}}h(f,"requireTarget");async function X(t){const{nodeId:o,dir:e}=await f(t);if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may start a job");const d=t.body;if(!d||typeof d!="object"||Array.isArray(d))throw new i(400,"invalid_request","job.start requires a JSON body");const a=d;await _(o,a.expected_execution_id);const r=a.job_id,s=a.cwd,p=a.env;if(typeof r!="string"||!I(r)||typeof s!="string"||!p||typeof p!="object"||Array.isArray(p)||Object.entries(p).some(([c,b])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(c)||typeof b!="string"))throw new i(400,"invalid_request","invalid job id, cwd or environment");if(!O())throw new i(400,"invalid_request","job.start is only used with the root launcher");const n=k(e,r);if(!(m(n.root,n.jobRun)||m(n.root,n.jobBg))||![n.cmdSh,n.jobLog].every(c=>m(n.root,c)))throw new i(404,"job_not_found","job was not prepared by this node");const g=$(n.dir,"job.starting");try{w(n.root,g,"")}catch(c){throw c.code==="EEXIST"?new i(409,"job_already_started","job was already started"):c}let l;try{const c=p,b=L("bash",c,s),y=await j(o),S=await V();return l=await q({nodeId:o,app:y.grantee??"app:terminal",isolated:y.isolated,cwd:s,env:c,capture:!1,command:[b,"-c",N,"--",n.cmdSh,n.jobLog,n.jobExit,n.jobRun,n.jobDone,b,String(H(e)),S]}),w(n.root,n.jobPgid,String(l.pid),384),w(n.root,n.jobPgidIdentity,`launcher:${l.pid}`,384),{status:201,body:{pid:l.pid}}}catch(c){if(l!==void 0)try{await l.stop()}catch(b){throw new AggregateError([c,b],`job ${r} launched but could not be recorded or stopped`)}try{A(n.root,g)}catch(b){if(b.code!=="ENOENT")throw b}throw c}}h(X,"handleStart");async function x(t){const{nodeId:o,dir:e}=await f(t),d=Date.now();return{status:200,body:z(e).map(r=>{const s=M(e,r.jobId)??null;return{job_id:r.jobId,command:r.command,purpose:r.purpose,started_at:new Date(r.startedAtMs).toISOString(),elapsed_ms:Math.max(0,d-r.startedAtMs),pgid:s,pgid_alive:s!==null&&F(s,G(e,r.jobId))}})}}h(x,"handleList");async function K(t){const{nodeId:o,jobId:e,dir:d}=await f(t);if(e===void 0)throw new i(400,"invalid_request","a job id is required");const a=t.query.get("foreground")==="1";if(a){if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may abort its foreground job");await _(o,t.body?.expected_execution_id)}const r=await Z(d,e,a,o);if(r.kind==="missing")throw new i(404,"job_not_found",`no background job ${e} for ${o}`);if(r.kind==="retired")throw new i(404,"job_not_found",`background job ${e} for ${o} is no longer running`,{log_path:r.logPath});if(r.kind==="not-stoppable")throw new i(409,"job_not_stoppable",`job ${e} recorded no trusted process identity`,{log_path:r.logPath});if(a)return{status:200,body:{node_id:o,job_id:e,signaled:r.signaled}};await R(o),await E(e,async n=>{const u=await P(n,t);return u.class==="person"?u.person:u.class==="app"?u.app:u.node});const s=await j(o);if(s!==null&&!D(s))try{await C(o,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:o,job_id:e,signaled:r.signaled}}}h(K,"handleStop");async function Q(t){const{nodeId:o,jobId:e,dir:d}=await f(t);if(e===void 0)throw new i(400,"invalid_request","a job id is required");if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may record its job");const a=t.body,r=k(d,e);if(typeof a?.command!="string"||a.job_dir!==r.dir||a.log_path!==r.jobLog)throw new i(400,"invalid_request",`job.background requires command, job_dir ${r.dir} and log_path ${r.jobLog}`);if(!m(r.root,r.jobBg))throw new i(404,"job_not_found",`job ${e} of ${o} is not backgrounded`);const s=a.command;return{status:201,body:{id:(await J(o,e,{command:s,jobDir:r.dir,logPath:r.jobLog})).id}}}h(Q,"handleBackground");const jo=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:Q},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:X},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:x},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:K}];export{jo as bashJobRoutes};
1
+ var B=Object.defineProperty;var l=(e,o)=>B(e,"name",{value:o,configurable:!0});import{killBashJobObject as E,recordBashJobObject as J}from"../../../core/spaces/stop.js";import{readerFor as P}from"../reader.js";import{join as $}from"node:path";import{createFileBeneath as g,existsBeneath as m,unlinkBeneath as A}from"../../../core/spaces/open-beneath.js";import{launchAppProcess as q,appProcessSandboxed as O}from"../../../core/spaces/process.js";import{BASH_JOB_SUPERVISOR_SCRIPT as N}from"../../../core/bash-job-supervisor.js";import{resolveAdmittedHostCommand as L}from"../../../core/runtime/spawn-env.js";import{requireCurrentExecution as _}from"./broker-recovery.js";import{isSafeNodeId as T}from"../../../core/canvas/paths.js";import{contextDir as v}from"../../../core/canvas/node-agent-paths.js";import{getNode as f}from"../../../core/canvas/canvas.js";import{isBrokerLive as D}from"../../../core/runtime/model-swap.js";import{assertNotFinalized as R}from"../../../core/runtime/reopen.js";import{reviveNode as C}from"../../../core/runtime/revive.js";import{checkStart as z}from"../../../core/runtime/start-check.js";import{activeBackgroundBashJobs as F,bashJobPaths as k,isBashJobProcessGroupAlive as M,readJobPgid as G,readJobPgidIdentity as H,isSafeBashJobId as I,readBashNiceness as Z,stopBackgroundBashJob as U}from"../../../core/bash-jobs.js";import{ApiError as i}from"../../../api/index.js";import{notFound as V}from"../../../core/errors.js";import{freshChildNodeExecPath as X}from"../../../core/runtime/branded-host.js";async function w(e){const o=e.params.id;if(o===void 0||!T(o))throw new i(400,"invalid_node_id",`invalid node id: ${JSON.stringify(o)}`);if(await f(o)===null)throw V(`unknown node: ${o}`,{received:o});const a=e.params.jobId;if(a!==void 0){if(!I(a))throw new i(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(a)}`);return{nodeId:o,jobId:a,dir:await v(o)}}return{nodeId:o,dir:await v(o)}}l(w,"requireTarget");async function x(e){const{nodeId:o,dir:n}=await w(e);if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may start a job");const a=e.body;if(!a||typeof a!="object"||Array.isArray(a))throw new i(400,"invalid_request","job.start requires a JSON body");const d=a;await _(o,d.expected_execution_id);const r=d.job_id,s=d.cwd,p=d.env;if(typeof r!="string"||!I(r)||typeof s!="string"||!p||typeof p!="object"||Array.isArray(p)||Object.entries(p).some(([c,b])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(c)||typeof b!="string"))throw new i(400,"invalid_request","invalid job id, cwd or environment");const h=await f(o);if(await z({grantee:h.grantee??"app:terminal",sub:h.sub,grant_id:h.grant_id}),!O())throw new i(400,"invalid_request","job.start is only used with the root launcher");const t=k(n,r);if(!(m(t.root,t.jobRun)||m(t.root,t.jobBg))||![t.cmdSh,t.jobLog].every(c=>m(t.root,c)))throw new i(404,"job_not_found","job was not prepared by this node");const j=$(t.dir,"job.starting");try{g(t.root,j,"")}catch(c){throw c.code==="EEXIST"?new i(409,"job_already_started","job was already started"):c}let u;try{const c=p,b=L("bash",c,s),y=await f(o),S=await X();return u=await q({nodeId:o,app:y.grantee??"app:terminal",isolated:y.isolated,cwd:s,env:c,capture:!1,command:[b,"-c",N,"--",t.cmdSh,t.jobLog,t.jobExit,t.jobRun,t.jobDone,b,String(Z(n)),S]}),g(t.root,t.jobPgid,String(u.pid),384),g(t.root,t.jobPgidIdentity,`launcher:${u.pid}`,384),{status:201,body:{pid:u.pid}}}catch(c){if(u!==void 0)try{await u.stop()}catch(b){throw new AggregateError([c,b],`job ${r} launched but could not be recorded or stopped`)}try{A(t.root,j)}catch(b){if(b.code!=="ENOENT")throw b}throw c}}l(x,"handleStart");async function K(e){const{nodeId:o,dir:n}=await w(e),a=Date.now();return{status:200,body:F(n).map(r=>{const s=G(n,r.jobId)??null;return{job_id:r.jobId,command:r.command,purpose:r.purpose,started_at:new Date(r.startedAtMs).toISOString(),elapsed_ms:Math.max(0,a-r.startedAtMs),pgid:s,pgid_alive:s!==null&&M(s,H(n,r.jobId))}})}}l(K,"handleList");async function Q(e){const{nodeId:o,jobId:n,dir:a}=await w(e);if(n===void 0)throw new i(400,"invalid_request","a job id is required");const d=e.query.get("foreground")==="1";if(d){if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may abort its foreground job");await _(o,e.body?.expected_execution_id)}const r=await U(a,n,d,o);if(r.kind==="missing")throw new i(404,"job_not_found",`no background job ${n} for ${o}`);if(r.kind==="retired")throw new i(404,"job_not_found",`background job ${n} for ${o} is no longer running`,{log_path:r.logPath});if(r.kind==="not-stoppable")throw new i(409,"job_not_stoppable",`job ${n} recorded no trusted process identity`,{log_path:r.logPath});if(d)return{status:200,body:{node_id:o,job_id:n,signaled:r.signaled}};await R(o),await E(n,async h=>{const t=await P(h,e);return t.class==="person"?t.person:t.class==="app"?t.app:t.node});const s=await f(o);if(s!==null&&!D(s))try{await C(o,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:o,job_id:n,signaled:r.signaled}}}l(Q,"handleStop");async function W(e){const{nodeId:o,jobId:n,dir:a}=await w(e);if(n===void 0)throw new i(400,"invalid_request","a job id is required");if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may record its job");const d=e.body,r=k(a,n);if(typeof d?.command!="string"||d.job_dir!==r.dir||d.log_path!==r.jobLog)throw new i(400,"invalid_request",`job.background requires command, job_dir ${r.dir} and log_path ${r.jobLog}`);if(!m(r.root,r.jobBg))throw new i(404,"job_not_found",`job ${n} of ${o} is not backgrounded`);const s=d.command;return{status:201,body:{id:(await J(o,n,{command:s,jobDir:r.dir,logPath:r.jobLog})).id}}}l(W,"handleBackground");const _o=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:W},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:x},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:K},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:Q}];export{_o as bashJobRoutes};
@@ -0,0 +1,3 @@
1
+ import { type RouteTable } from '../router.js';
2
+ export declare const chargeRoutes: RouteTable;
3
+ export declare const spendLimitRoutes: RouteTable;
@@ -0,0 +1 @@
1
+ var b=Object.defineProperty;var o=(n,e)=>b(n,"name",{value:e,configurable:!0});import{ApiError as l}from"../../../api/errors.js";import{personIdAsync as w}from"../../../core/canvas/person.js";import{assertReference as v,deleteLimit as _,listCharges as q,listLimits as y,monthTotals as R,parseUsageMonth as E,upsertLimit as L}from"../../../core/ledger/index.js";import{ownerOnly as T}from"../router.js";import{integer as $}from"./runs.js";import{invalidRequest as N,objectBody as O}from"./validate.js";function k(n){const{principal:e}=n;if(e.class==="app"||e.class==="broker")return e.app;if(e.class!=="person")throw new l(403,"owner_only","charges are read by the person, a node or an app")}o(k,"granteeOf");async function F(n){const e=k(n),r=n.query.get("under"),t=n.query.get("after"),s=n.query.get("month"),i=r===null||s!==null?E(s):void 0,{charges:d,next:p}=await q({...i===void 0?{}:{month:i},...e===void 0?{}:{grantee:e},...r===null?{}:{under:v(r)},...t===null?{}:{after:t},limit:$(n.query.get("limit"),"limit",1,1e4,1e3)}),a=e===void 0&&r===null?await R(i):void 0;return{...i===void 0?{}:{month:i},charges:d,next:p,...a===void 0?{}:{totals:a}}}o(F,"listRoute");const h=["bill","subscription","key","endpoint","take","legacy"],f="person:";function g(n){const e=n.params.id??"";if(!e.startsWith(f)||e.length===f.length||e.length>128)throw new l(400,"invalid_request",`a person limit id starts with \`${f}\`; received ${e}`,{violations:[{field:"id",problem:`must start with ${f}`,received:e}]});return e}o(g,"idOf");function c(n,e,r){const t=n[e];if(t==null)return t;if(typeof t!="string"||t===""){r.push({field:e,problem:"must be a non-empty string or null",received:t});return}return t}o(c,"nullableString");async function G(n){const e=g(n),r=[],t=O(n.body,["payer","usd_per_month","funding","grantee","provider","sub"],r),s=t.payer;(typeof s!="string"||!/^(user|app):.+/.test(s))&&r.push({field:"payer",problem:"must be user:<id> or app:<id>",...s===void 0?{}:{received:s}});const i=t.usd_per_month;(typeof i!="number"||!Number.isFinite(i)||i<0)&&r.push({field:"usd_per_month",problem:"must be a number of at least 0",...i===void 0?{}:{received:i}});const d=c(t,"funding",r);typeof d=="string"&&!h.includes(d)&&r.push({field:"funding",problem:`must be one of ${h.join(", ")}`,received:d});const p=c(t,"grantee",r),a=c(t,"provider",r),m=c(t,"sub",r);r.length>0&&N("spend limit request",r);const u=t;if(u.payer.startsWith("user:")&&u.payer!==await w())throw new l(403,"owner_only","a person sets limits only on their own payer or on an app",{payer:u.payer});return await L({id:e,payer:u.payer,usd_per_month:u.usd_per_month,source:"person",...d===void 0?{}:{funding:d},...p===void 0?{}:{grantee:p},...a===void 0?{}:{provider:a},...m===void 0?{}:{sub:m}})}o(G,"setRoute");async function I(n){const e=g(n);if((await y({source:"person"})).find(t=>t.id===e)===void 0||!await _(e))throw new l(404,"not_found",`no person limit ${e}`);return{id:e,removed:!0}}o(I,"removeRoute");const B=[{method:"GET",pattern:"/v1/charges",handler:o(async n=>({status:200,body:await F(n)}),"handler")}],C=T([{method:"GET",pattern:"/v1/spend-limits",handler:o(async()=>({status:200,body:{limits:await y()}}),"handler")},{method:"PUT",pattern:"/v1/spend-limits/:id",handler:o(async n=>({status:200,body:await G(n)}),"handler")},{method:"DELETE",pattern:"/v1/spend-limits/:id",handler:o(async n=>({status:200,body:await I(n)}),"handler")}]);export{B as chargeRoutes,C as spendLimitRoutes};
@@ -1,10 +1,14 @@
1
1
  import type { RouteTable } from '../router.js';
2
+ import { type LlmSpend } from '../../../core/llm/run.js';
2
3
  import { RunError } from '../../../core/runs/operations.js';
3
4
  import { type SocketPrincipal } from '../server.js';
4
- import { type SpendTarget } from '../../../core/usage/ledger.js';
5
- /** Who a socket caller's model call bills: a broker's node bills its grant's app under
6
- * that grant's cap; the person (and a local scoped token) bills the person's own agent, uncapped. */
7
- export declare function spendTarget(principal: SocketPrincipal | undefined): Promise<SpendTarget>;
8
- /** `cap_exhausted` names when the count starts over and what the person can do (contract 2 error table). */
5
+ /** Who a socket caller's model call is attributed to: a broker's node to its grant's app, the person (and a local scoped token
6
+ * on an unjoined runtime) to the person's own agent. Limits are `limits` rows the ledger check reads; nothing here carries a cap. */
7
+ export declare function spendTarget(principal: SocketPrincipal | undefined, node?: {
8
+ node_id: string;
9
+ run_id?: string | null;
10
+ }): Promise<LlmSpend>;
11
+ /** `cap_exhausted` names the limit that refused, what had been spent against it, when the count starts over and what the person can do
12
+ * (the ledger's refusal carries `user_action` only for a limit the person can act on; an operator limit has none). */
9
13
  export declare function capFields(error: RunError): Record<string, unknown>;
10
14
  export declare const llmRoutes: RouteTable;
@@ -1,3 +1,3 @@
1
- var O=Object.defineProperty;var s=(e,t)=>O(e,"name",{value:t,configurable:!0});import{randomUUID as _}from"node:crypto";import{MODEL_CONTEXT_BODY_MAX_BYTES as S}from"../../../core/llm/body-limits.js";import{llmCallerOf as g,parseLlmRequest as E,runLlm as R}from"../../../core/llm/run.js";import{RunError as d}from"../../../core/runs/operations.js";import{errorCodes as T}from"../../../api/error-codes.js";import{getNode as q}from"../../../core/canvas/canvas.js";import{socketPrincipal as i}from"../server.js";import{activeGrant as y,activeGrantForApp as w,grantFor as h,grantsSource as b,payerOfGrant as I}from"../../../core/grants/mirror.js";import{parseUsageMonth as N,UNCAPPED_GRANTEE as D,usageFor as G}from"../../../core/usage/ledger.js";function v(e,t){if(t==="broker"||t==="person"||t===void 0||!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:o,...a}=e;return a}s(v,"operatorDetails");async function A(e){if(e?.class==="broker"){const t=e.grant?await y(e.grant):await h(e.app,e.sub);return{grantee:e.app,spend_cap:t&&t.grantee===e.app?t.spend_cap:null}}if(e?.class==="app"){const t=await b();if(t===null||t==="local")return{grantee:e.app,spend_cap:null};let o;try{o=await w(e.app)}catch{throw new d(401,"grant_revoked",`${e.app} has several active grants; a local token cannot name which user's cap applies`)}if(!o)throw new d(401,"grant_revoked",`${e.app} has no active grant`);return{grantee:e.app,spend_cap:o.spend_cap}}return{grantee:D,spend_cap:null}}s(A,"spendTarget");async function P(e){if(e?.class==="broker"){if(e.app==="app:terminal")return;const t=e.grant?await y(e.grant):await h(e.app,e.sub);if(!t&&await I(e.grant)==="app")throw new d(401,"grant_revoked",`${e.app}'s app-paid grant is no longer active`);return g(t&&t.grantee===e.app?t:null)}if(e?.class==="app"){const t=await b();return t===null||t==="local"?void 0:g(await w(e.app))}}s(P,"llmCaller");function k(e){const t=T[e.code];return t?t.type:e.status===429?"rate_limit_error":e.status<500?"invalid_request_error":"server_error"}s(k,"errorType");function U(e){if(e.code!=="cap_exhausted")return{};const t=e.details?.reset_at;return{...typeof t=="string"?{reset_at:t}:{},user_action:"raise_cap"}}s(U,"capFields");const Y=[{method:"POST",pattern:"/v1/llm",scope:"crtr:llm",maxBodyBytes:S,handler:s(async({body:e,res:t,req:o})=>{const a=_();t.setHeader("Request-Id",a);const m=new AbortController,p=s(()=>m.abort(),"abort");t.on("close",p);let l;try{const r=E(e),n=i(o),u=n?.class==="broker"?await q(n.node):null;if(n?.class==="broker"&&!u)throw new d(401,"unauthorized","node not found");const c=await A(n),x=await R(r,m.signal,r.stream?f=>{typeof f.served_model=="string"&&(l=f.served_model),t.headersSent||t.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),t.write(`${JSON.stringify(f)}
2
- `)}:void 0,u?{cwd:u.cwd,profileId:u.profile_id??null}:void 0,c,await P(n));return r.stream?(t.headersSent||t.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),t.end(),{status:200}):{status:200,body:x.completion}}catch(r){if(t.headersSent){const n=r instanceof d?r:new d(503,"upstream_model_unavailable","model stream failed"),u=n.details&&typeof n.details=="object"&&!Array.isArray(n.details)?n.details:{},c=v(l!==void 0&&typeof u.served_model!="string"?{...u,served_model:l}:n.details,i(o)?.class);return t.end(`${JSON.stringify({error:{code:n.code,message:n.message,...c===void 0?{}:{details:c},type:"server_error",origin:"runtime",retryable:n.retryable,request_id:a}})}
3
- `),{status:200}}if(r instanceof d){const n=v(r.details,i(o)?.class);return r.code==="all_routes_exhausted"&&t.setHeader("Retry-After",String(r.details.retry_after_s)),{status:r.status,body:{error:{code:r.code,message:r.message,...n===void 0?{}:{details:n},type:k(r),...r.param?{param:r.param}:{},origin:"runtime",retryable:r.retryable,request_id:a,...r.code==="all_routes_exhausted"?{retry_after_s:r.details.retry_after_s}:{},...U(r)}}}}throw r}finally{t.off("close",p)}},"handler")},{method:"GET",pattern:"/v1/usage",handler:s(async({req:e})=>{const t=_(),o={"Request-Id":t};try{const a=await A(i(e));return{status:200,headers:o,body:await G(a.grantee,a.spend_cap,N(new URL(e.url??"/","http://runtime.local").searchParams.get("month")))}}catch(a){if(!(a instanceof d))throw a;return{status:a.status,headers:o,body:{error:{code:a.code,message:a.message,type:k(a),...a.param?{param:a.param}:{},origin:"runtime",retryable:!1,request_id:t}}}}},"handler")}];export{U as capFields,Y as llmRoutes,A as spendTarget};
1
+ var k=Object.defineProperty;var s=(t,e)=>k(t,"name",{value:e,configurable:!0});import{randomUUID as y}from"node:crypto";import{MODEL_CONTEXT_BODY_MAX_BYTES as x}from"../../../core/llm/body-limits.js";import{llmCallerOf as g,parseLlmRequest as O,runLlm as R}from"../../../core/llm/run.js";import{RunError as u}from"../../../core/runs/operations.js";import{errorCodes as S}from"../../../api/error-codes.js";import{getNode as T}from"../../../core/canvas/canvas.js";import{socketPrincipal as l}from"../server.js";import{activeGrant as E,activeGrantForApp as h,grantFor as I,grantsSource as w,payerOfGrant as N}from"../../../core/grants/mirror.js";import{parseUsageMonth as G,usageFor as L}from"../../../core/ledger/index.js";function b(t,e){if(e==="broker"||e==="person"||e===void 0||!t||typeof t!="object"||Array.isArray(t)||!("rate_limit"in t))return t;const{rate_limit:o,...a}=t;return a}s(b,"operatorDetails");const M="app:terminal";async function v(t,e){if(t?.class==="broker")return{grantee:t.app,sub:t.sub,node:t.node,run:e?.run_id??t.run};if(t?.class==="app"){const o=await w();if(o===null||o==="local")return{grantee:t.app};let a;try{a=await h(t.app)}catch{throw new u(401,"grant_revoked",`${t.app} has several active grants; a local token cannot name which user's cap applies`)}if(!a)throw new u(401,"grant_revoked",`${t.app} has no active grant`);return{grantee:t.app,sub:a.sub}}return{grantee:M}}s(v,"spendTarget");async function $(t){if(t?.class==="broker"){if(t.app==="app:terminal")return;const e=t.grant?await E(t.grant):await I(t.app,t.sub);if(!e&&await N(t.grant)==="app")throw new u(401,"grant_revoked",`${t.app}'s app-paid grant is no longer active`);return g(e&&e.grantee===t.app?e:null)}if(t?.class==="app"){const e=await w();return e===null||e==="local"?void 0:g(await h(t.app))}}s($,"llmCaller");function q(t){const e=S[t.code];return e?e.type:t.status===429?"rate_limit_error":t.status<500?"invalid_request_error":"server_error"}s(q,"errorType");function j(t){if(t.code!=="cap_exhausted")return{};const e=t.details??{};return{...e.limit!==void 0?{limit:e.limit}:{},...typeof e.usd=="number"?{usd:e.usd}:{},...typeof e.spend_cap=="number"?{spend_cap:e.spend_cap}:{},...typeof e.usd_equivalent=="number"?{usd_equivalent:e.usd_equivalent}:{},...typeof e.reset_at=="string"?{reset_at:e.reset_at}:{},...typeof e.user_action=="string"?{user_action:e.user_action}:{}}}s(j,"capFields");const z=[{method:"POST",pattern:"/v1/llm",scope:"crtr:llm",maxBodyBytes:x,handler:s(async({body:t,res:e,req:o,causedBy:a})=>{const i=y();e.setHeader("Request-Id",i);const p=new AbortController,_=s(()=>p.abort(),"abort");e.on("close",_);let f;try{const r=O(t),n=l(o),d=n?.class==="broker"?await T(n.node):null;if(n?.class==="broker"&&!d)throw new u(401,"unauthorized","node not found");const c={...await v(n,d??void 0),request:i},A=await R(r,p.signal,r.stream?m=>{typeof m.served_model=="string"&&(f=m.served_model),e.headersSent||e.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),e.write(`${JSON.stringify(m)}
2
+ `)}:void 0,d?{cwd:d.cwd,profileId:d.profile_id??null}:void 0,c,await $(n),a);return r.stream?(e.headersSent||e.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),e.end(),{status:200}):{status:200,body:A.completion}}catch(r){if(e.headersSent){const n=r instanceof u?r:new u(503,"upstream_model_unavailable","model stream failed"),d=n.details&&typeof n.details=="object"&&!Array.isArray(n.details)?n.details:{},c=b(f!==void 0&&typeof d.served_model!="string"?{...d,served_model:f}:n.details,l(o)?.class);return e.end(`${JSON.stringify({error:{code:n.code,message:n.message,...c===void 0?{}:{details:c},type:"server_error",origin:"runtime",retryable:n.retryable,request_id:i}})}
3
+ `),{status:200}}if(r instanceof u){const n=b(r.details,l(o)?.class);return r.code==="all_routes_exhausted"&&e.setHeader("Retry-After",String(r.details.retry_after_s)),{status:r.status,body:{error:{code:r.code,message:r.message,...n===void 0?{}:{details:n},type:q(r),...r.param?{param:r.param}:{},origin:"runtime",retryable:r.retryable,request_id:i,...r.code==="all_routes_exhausted"?{retry_after_s:r.details.retry_after_s}:{},...j(r)}}}}throw r}finally{e.off("close",_)}},"handler")},{method:"GET",pattern:"/v1/usage",handler:s(async({req:t})=>{const e=y(),o={"Request-Id":e};try{const a=await v(l(t));return{status:200,headers:o,body:await L(a.grantee,G(new URL(t.url??"/","http://runtime.local").searchParams.get("month")))}}catch(a){if(!(a instanceof u))throw a;return{status:a.status,headers:o,body:{error:{code:a.code,message:a.message,type:q(a),...a.param?{param:a.param}:{},origin:"runtime",retryable:!1,request_id:e}}}}},"handler")}];export{j as capFields,z as llmRoutes,v as spendTarget};