@north-light/cli 0.3.571 → 0.3.572

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 (47) hide show
  1. package/dist/api/contract.d.ts +1 -1
  2. package/dist/api/contract.js +1 -1
  3. package/dist/api/dto/broker-ops.d.ts +3 -0
  4. package/dist/api/dto/recovery.d.ts +7 -0
  5. package/dist/api/errors.d.ts +3 -0
  6. package/dist/api/errors.js +1 -1
  7. package/dist/builtin-memory/crouter-sdk/release-notes.md +7 -0
  8. package/dist/commands/dashboard.js +3 -1
  9. package/dist/core/auth-file.d.ts +2 -0
  10. package/dist/core/auth-file.js +1 -1
  11. package/dist/core/canvas/recovery.d.ts +3 -0
  12. package/dist/core/canvas/recovery.js +2 -2
  13. package/dist/core/command.d.ts +2 -3
  14. package/dist/core/command.js +6 -6
  15. package/dist/core/llm/run.js +2 -2
  16. package/dist/core/model-auth/readiness.js +1 -1
  17. package/dist/core/providers/files.js +1 -1
  18. package/dist/core/runs/operations.js +6 -6
  19. package/dist/core/runtime/blaxel-environment.d.ts +2 -0
  20. package/dist/core/runtime/blaxel-environment.js +1 -0
  21. package/dist/core/runtime/broker/fault-retry.d.ts +4 -0
  22. package/dist/core/runtime/broker/fault-retry.js +1 -1
  23. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  24. package/dist/core/runtime/broker/rebind.js +1 -1
  25. package/dist/core/runtime/nodes.js +1 -1
  26. package/dist/core/runtime/revive.js +2 -2
  27. package/dist/core/runtime/spawn.js +2 -2
  28. package/dist/core/runtime/warm-pool.js +1 -1
  29. package/dist/core/spaces/process.js +1 -1
  30. package/dist/core/spaces/space.d.ts +2 -1
  31. package/dist/core/spaces/space.js +2 -2
  32. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  33. package/dist/daemon/api/handlers/modelauth.js +1 -1
  34. package/dist/daemon/reconcilers/action-lane.js +1 -1
  35. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  36. package/dist/daemon/reconcilers/node-lifecycle/launch-failure.d.ts +1 -0
  37. package/dist/daemon/reconcilers/node-lifecycle/launch-failure.js +1 -0
  38. package/dist/daemon/reconcilers/node-lifecycle/node-person.d.ts +9 -0
  39. package/dist/daemon/reconcilers/node-lifecycle/node-person.js +1 -0
  40. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +0 -2
  41. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -1
  42. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  43. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  44. package/docs/sdk/release-notes.md +7 -0
  45. package/package.json +2 -2
  46. package/packages/crouter-identity/package.json +1 -1
  47. package/runtime.lock.json +13 -13
@@ -1,3 +1,3 @@
1
- var we=Object.defineProperty;var d=(e,o)=>we(e,"name",{value:o,configurable:!0});import{accessSync as me,constants as he}from"node:fs";import{isAbsolute as pe,resolve as ke,join as _e}from"node:path";import{appSpace as ve}from"../layout.js";import{ApiError as Q}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as ge,currentNodeContext as be,rootOfSpine as xe,newNodeId as Ce,preflightNodeId as Ee}from"./nodes.js";import{resolveProfileOperand as Re}from"../profiles/manifest.js";import{selectProfileForCwd as Se,selectProfileForCwdReadOnly as $e}from"../profiles/select.js";import{buildLaunchSpecAsync as Z,buildPiArgv as Fe}from"./launch.js";import{runsOnBlaxel as Oe,sandboxWorktreeRequest as Ie}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as Ne}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as B}from"../errors.js";import{writeGoal as Pe}from"./kickoff.js";import{appendSituationalContext as De,formatSituationalProse as Te}from"./situational-context.js";import{ensureRoadmap as Le}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as Me,KICKOFF_ORIGIN_ENV as We}from"./stamp/protocol.js";import{ExecutionCapReached as je,beginExecution as He,crtrHome as ze,getNode as f,fullName as ee,jobDir as Ke,recordExecutionPid as Ge,abortExecution as M,setFrozen as ne}from"../canvas/index.js";import{contextDir as W,nodeAgentDir as j}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ue}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as E}from"../conversation-store/index.js";import{appMemoryTooSmall as Ve,boundFleet as Xe,brokerThresholdsForDaemon as oe}from"./fleet.js";import{admitBrokerMemory as qe}from"./memory-admission.js";import{emitEvent as re}from"../events/emit.js";import{openViewerWindow as Ye,focusOf as Je,windowOfPane as Qe}from"./placement.js";import{waitForBrokerViewSocket as Ze}from"./placement-tmux.js";import{transition as _}from"./lifecycle.js";import{beginBootFaultAttempt as en}from"../canvas/recovery.js";import{headlessBrokerHost as H}from"./host.js";import{ensureDaemon as nn}from"../../daemon/manage.js";import{readConfig as on}from"../config.js";import{modelRequestFromConfig as rn,unregisteredConcreteModel as tn}from"../model-routes.js";import{openModelRegistry as an}from"./model-registry.js";import{MODEL_SPEC_NEXT as dn}from"./model-selection.js";import{forkNodeLedger as sn}from"./ledger.js";import{appRungForGrant as cn}from"../llm/app-rungs.js";import{APP_FAMILY as z}from"../model-routes.js";import{discoverLifecycleHookRegistry as ln}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as fn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as un}from"../async-array.js";import{checkStart as wn}from"./start-check.js";function v(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(v,"launchFailureOutcome");async function mn(e,o,a){try{return await H.launch(e,o,a)}catch(i){try{await _(e,"crash",{reason:"launch_failed",outcome:v(i)})}catch{}const t=i.message;throw B(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(mn,"launchBrokerOrCrash");async function hn(e,o){try{await _(e,"crash",{reason:"launch_failed",outcome:v(o)})}catch{}try{H.teardown(e)}catch{}}d(hn,"crashAndTearDown");async function pn(e){const o=(await E().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),i=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(i.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(i.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${i.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 i[0].path}d(pn,"resolveSessionUuid");async function ie(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 i=N(pe(o)?o:ke(process.cwd(),o));if(i===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await E().header(i)).path}const a=await f(o);if(a!==null){const i=a.pi_session_file;if(i==null||i==="")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(i);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await E().header(t)).path}return await pn(o)}d(ie,"resolveForkSource");async function kn(e,o,a,i={}){return e===null?null:e!==void 0&&e!==""?Re(e).profileId:o!==null?(await f(o))?.profile_id??null:i.readOnlySelection===!0?$e(a):Se(a)}d(kn,"resolveProfileId");function te(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return rn(e.model,o,e.modelExact===!0)}d(te,"requestFromLaunch");async function ae(e,o,a){const i=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await cn(o,i,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...c}=e.env??{};return{...e,model:t.model,modelIntent:{family:z,strength:t.strength},modelExact:void 0,env:{...c,CRTR_MODEL_INTENT:`${z}/${t.strength}`}}}d(ae,"appPaidLaunch");async function de(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==z)return;const i=await tn(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await an(),o);if(i!==void 0)throw u(`model '${i.request.spec}' is not registered in this daemon.`,{received:i.request.spec,next:dn})}d(de,"assertLaunchModelRegistered");function _n(e,o,a){const i=e??o??null;if(!a&&i===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return i}d(_n,"resolveSpawner");async function se(e,o,a){try{nn()}catch{}const i=be(),t=e.root===!0,s=_n(e.parent,i.nodeId??null,t),c=e.mode??"base",y=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&y==="resident",S=s===null?null:await f(s),K=e.creator===void 0||e.creator===null?null:await f(e.creator);e.nodeId!==void 0&&await Ee(e.nodeId);const g=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,P=g===void 0?null:await ge(g),D=await un([S,K,P],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 R=e.worktree===!0,w=$||R?e.nodeId??await Ce():e.nodeId,F=$?e.run!==void 0&&t&&!D?e.cwd:_e(ve(e.run?.grantee??S?.grantee??"app:terminal").nodes,w):e.cwd,m=await kn(e.profile,s,F),G=e.run?.grant_id??S?.grant_id??null,U=await ae((await Z(e.kind,c,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:m})).launch,G,e.model);await de(te(U),{cwd:F,profileId:m});const T=e.run??K??S??P;await wn({grantee:T?.grantee??"app:terminal",sub:T?.sub,grant_id:T?.grant_id});const V=P?.node_id??null;let b,O=F;const L=R&&await Oe(m)?await Ie(m,e.worktreeCwd??e.cwd,w,e.worktreeBase):void 0;try{R&&L===void 0&&(b=await Be(e.worktreeCwd??e.cwd,w,e.worktreeBase),O=b.path);const l=R?await ae((await Z(e.kind,c,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:m})).launch,G,e.model):U;L!==void 0&&(l.worktree=L),R&&await de(te(l),{cwd:O,profileId:m});const n=await ye({kind:e.kind,mode:c,lifecycle:y,cwd:O,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:V,spawnedBy:t?s??void 0:void 0,profile_id:m,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:$,...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:g,modelOverride:e.model===void 0?void 0:l.model,...b!==void 0?{managedWorktree:b}:{},...w!==void 0?{nodeId:w}:{},...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 sn(n.node_id,V??null)}catch(r){throw await _(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}if(await Pe(n.node_id,e.prompt),e.situationalContext!==void 0&&await De(n.node_id,Te(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(r){throw await _(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}const A=e.prompt!=="",le=`${A&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
1
+ var we=Object.defineProperty;var d=(e,o)=>we(e,"name",{value:o,configurable:!0});import{accessSync as me,constants as he}from"node:fs";import{isAbsolute as pe,resolve as _e,join as ke}from"node:path";import{appSpace as ve}from"../layout.js";import{ApiError as ee}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as ge,currentNodeContext as be,rootOfSpine as xe,newNodeId as Ce,preflightNodeId as Ee}from"./nodes.js";import{resolveProfileOperand as Se}from"../profiles/manifest.js";import{selectProfileForCwd as Oe,selectProfileForCwdReadOnly as Re}from"../profiles/select.js";import{buildLaunchSpecAsync as ne,buildPiArgv as $e}from"./launch.js";import{runsOnBlaxel as Fe,sandboxWorktreeRequest as Ie}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as Ne}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as B}from"../errors.js";import{writeGoal as Pe}from"./kickoff.js";import{appendSituationalContext as De,formatSituationalProse as Te}from"./situational-context.js";import{ensureRoadmap as Le}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as Me,KICKOFF_ORIGIN_ENV as We}from"./stamp/protocol.js";import{ExecutionCapReached as je,beginExecution as ze,crtrHome as He,getNode as l,fullName as oe,jobDir as Ke,recordExecutionPid as Ge,abortExecution as M,setFrozen as W}from"../canvas/index.js";import{contextDir as j,nodeAgentDir as z}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ue}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as E}from"../conversation-store/index.js";import{appMemoryTooSmall as Ve,boundFleet as Xe,brokerThresholdsForDaemon as re}from"./fleet.js";import{admitBrokerMemory as qe}from"./memory-admission.js";import{emitEvent as H}from"../events/emit.js";import{blaxelEnvironmentOf as Ye}from"./blaxel-environment.js";import{openViewerWindow as Je,focusOf as Qe,windowOfPane as Ze}from"./placement.js";import{waitForBrokerViewSocket as en}from"./placement-tmux.js";import{transition as k}from"./lifecycle.js";import{beginBootFaultAttempt as nn}from"../canvas/recovery.js";import{headlessBrokerHost as K}from"./host.js";import{ensureDaemon as on}from"../../daemon/manage.js";import{readConfig as rn}from"../config.js";import{modelRequestFromConfig as tn,unregisteredConcreteModel as an}from"../model-routes.js";import{openModelRegistry as dn}from"./model-registry.js";import{MODEL_SPEC_NEXT as sn}from"./model-selection.js";import{forkNodeLedger as cn}from"./ledger.js";import{appRungForGrant as ln}from"../llm/app-rungs.js";import{APP_FAMILY as G}from"../model-routes.js";import{discoverLifecycleHookRegistry as fn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as un}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as wn}from"../async-array.js";import{checkStart as mn}from"./start-check.js";function v(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(v,"launchFailureOutcome");async function hn(e,o,a){try{return await K.launch(e,o,a)}catch(i){try{await k(e,"crash",{reason:"launch_failed",outcome:v(i)})}catch{}const t=i.message;throw B(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(hn,"launchBrokerOrCrash");async function pn(e,o){try{await k(e,"crash",{reason:"launch_failed",outcome:v(o)})}catch{}try{K.teardown(e)}catch{}}d(pn,"crashAndTearDown");async function _n(e){const o=(await E().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),i=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(i.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(i.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${i.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 i[0].path}d(_n,"resolveSessionUuid");async function ie(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 i=N(pe(o)?o:_e(process.cwd(),o));if(i===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await E().header(i)).path}const a=await l(o);if(a!==null){const i=a.pi_session_file;if(i==null||i==="")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(i);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await E().header(t)).path}return await _n(o)}d(ie,"resolveForkSource");async function kn(e,o,a,i={}){return e===null?null:e!==void 0&&e!==""?Se(e).profileId:o!==null?(await l(o))?.profile_id??null:i.readOnlySelection===!0?Re(a):Oe(a)}d(kn,"resolveProfileId");function te(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return tn(e.model,o,e.modelExact===!0)}d(te,"requestFromLaunch");async function ae(e,o,a){const i=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await ln(o,i,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...c}=e.env??{};return{...e,model:t.model,modelIntent:{family:G,strength:t.strength},modelExact:void 0,env:{...c,CRTR_MODEL_INTENT:`${G}/${t.strength}`}}}d(ae,"appPaidLaunch");async function de(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==G)return;const i=await an(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await dn(),o);if(i!==void 0)throw u(`model '${i.request.spec}' is not registered in this daemon.`,{received:i.request.spec,next:sn})}d(de,"assertLaunchModelRegistered");function vn(e,o,a){const i=e??o??null;if(!a&&i===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return i}d(vn,"resolveSpawner");async function se(e,o,a){try{on()}catch{}const i=be(),t=e.root===!0,s=vn(e.parent,i.nodeId??null,t),c=e.mode??"base",y=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&y==="resident",O=s===null?null:await l(s),U=e.creator===void 0||e.creator===null?null:await l(e.creator);e.nodeId!==void 0&&await Ee(e.nodeId);const g=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,P=g===void 0?null:await ge(g),D=await wn([O,U,P],async f=>f?.isolated===!0||f?.run_id!=null&&(await l(f.run_id))?.isolated===!0);if(D&&e.isolated===!1)throw new ee(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const R=D||e.isolated===!0;if(R&&e.worktree===!0)throw new ee(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const S=e.worktree===!0,w=R||S?e.nodeId??await Ce():e.nodeId,$=R?e.run!==void 0&&t&&!D?e.cwd:ke(ve(e.run?.grantee??O?.grantee??"app:terminal").nodes,w):e.cwd,m=await kn(e.profile,s,$),V=e.run?.grant_id??O?.grant_id??null,X=await ae((await ne(e.kind,c,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:$,profileId:m})).launch,V,e.model);await de(te(X),{cwd:$,profileId:m});const T=e.run??U??O??P;await mn({grantee:T?.grantee??"app:terminal",sub:T?.sub,grant_id:T?.grant_id});const q=P?.node_id??null;let b,F=$;const L=S&&await Fe(m)?await Ie(m,e.worktreeCwd??e.cwd,w,e.worktreeBase):void 0;try{S&&L===void 0&&(b=await Be(e.worktreeCwd??e.cwd,w,e.worktreeBase),F=b.path);const f=S?await ae((await ne(e.kind,c,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:m})).launch,V,e.model):X;L!==void 0&&(f.worktree=L),S&&await de(te(f),{cwd:F,profileId:m});const n=await ye({kind:e.kind,mode:c,lifecycle:y,cwd:F,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:q,spawnedBy:t?s??void 0:void 0,profile_id:m,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:R,...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:g,modelOverride:e.model===void 0?void 0:f.model,...b!==void 0?{managedWorktree:b}:{},...w!==void 0?{nodeId:w}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:f});if(a?.(n.node_id),e.forkFrom!==void 0)try{await cn(n.node_id,q??null)}catch(r){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}if(await Pe(n.node_id,e.prompt),e.situationalContext!==void 0&&await De(n.node_id,Te(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(r){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}const A=e.prompt!=="",le=`${A&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
2
2
 
3
- `:""}${e.prompt}`;c==="orchestrator"&&await Le(n.node_id,{goal:e.prompt.trim()}),await vn(n);let X;if(g!==void 0)try{const r=N(g);if(r===null)throw new Error(`invalid fork source ${g}`);const k=await E().fork(r,n.node_id);X=(await E().header(k)).path}catch(r){throw await _(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}const x=Fe(n,{prompt:le,resumeSessionPath:X});if(x.env={...x.env,CRTR_SUBTREE:await xe(n.node_id)},A){const r=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}:{}};x.env[We]=Me(r)}const h=Xe(),q=await h.reserveSlot(n.node_id),p=q?await qe(n.node_id):null;if(p?.verdict==="too_small"){h.releaseReservation(n.node_id);const r=Ve(p);throw await _(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}if(!q||p?.verdict==="denied")return p?.verdict==="denied"&&h.releaseReservation(n.node_id),await ne(n.node_id,new Date().toISOString()),re({level:"info",event:"broker.frozen",node_id:n.node_id,fields:p?.verdict==="denied"?{reason:"app_memory",free_bytes:p.free_bytes,needed_bytes:p.needed_bytes}:{reason:"broker_cap",live_count:await h.occupancy(),hard_cap:oe().automaticReviveCap}}),{node:await f(n.node_id),frozen:!0,window:null,session:null};const fe=await en(n.node_id),{automaticReviveCap:ue}=oe();let C;try{C=await He(n.node_id,{daemonEpoch:h.epoch(),cap:ue})}catch(r){if(!(r instanceof je))throw r;return h.releaseReservation(n.node_id),await ne(n.node_id,new Date().toISOString()),re({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"broker_cap",live_count:r.live,hard_cap:r.cap}}),{node:await f(n.node_id),frozen:!0,window:null,session:null}}x.env={...x.env,CRTR_EXECUTION_ID:C};let I;try{I=await mn(n.node_id,x,{cwd:n.cwd,name:ee(n),resuming:!1})}catch(r){throw await M(C,{reason:"launch_failed"}),r}finally{h.releaseReservation(n.node_id)}if(I.pid===null){const r=new Error(`broker host returned no pid for ${n.node_id}`);throw await M(C,{reason:"launch_failed"}),await _(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),B(`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 Ge(C,n.node_id,I.pid)==="shutdown")throw await M(C,{reason:"superseded"}),H.teardown(n.node_id),B(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(ce&&e.readiness==="await"&&!await Ze(n.node_id,I.exited)){const r=await fe.explanation();throw await hn(n.node_id,new Error(r??`broker view socket never bound for ${n.node_id}`)),B(r!==null?`the root broker ${n.node_id} could not start \u2014 ${r}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,r!==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 Y=null,J=null;if(!t&&s!==null&&on("user").auto_open_child_viewers)try{const r=await Je(s);if(r!==null&&r.pane!==null&&r.pane!==""){const k=await Ye(n.node_id,r.session??"",{name:ee(n),cwd:e.cwd,besidePane:r.pane,waitForBroker:!0,initialWhip:A});k!==null&&k.pane!==null&&k.pane!==""&&(J=k.session,Y=Qe(k.pane))}}catch{}return{node:await f(n.node_id),frozen:!1,window:Y,session:J}}catch(l){throw b!==void 0&&w!==void 0&&await f(w)===null&&await Ne(b),l}}d(se,"spawnChildPrepared");async function fo(e){return se(e)}d(fo,"spawnChild");async function vn(e){const o=ln(e.cwd,e.profile_id).plans.get("node:start")??[];await fn(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 W(e.node_id),jobDir:Ke(e.node_id)},runtime:{isBirth:!0,canvasHome:ze(),profile:e.profile_id??null}})}d(vn,"invokeBirthLifecycleHooks");const yn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function uo(e,o,a){const i=await f(e);if(i===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 ie(e),s=await W(e);try{await E().header(N(t)),me(s,he.R_OK)}catch(c){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${c.message}`)}return se({kind:i.kind,mode:"base",cwd:i.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:i.profile_id,model:i.model_override??void 0,...o===void 0?{}:{scopes:o}},async c=>{const y=await W(c);Ue(await j(e),s,await j(c),y,yn)})}d(uo,"forkNode");export{ae as appPaidLaunch,de as assertLaunchModelRegistered,uo as forkNode,vn as invokeBirthLifecycleHooks,ie as resolveForkSource,kn as resolveProfileId,_n as resolveSpawner,fo as spawnChild,se as spawnChildPrepared};
3
+ `:""}${e.prompt}`;c==="orchestrator"&&await Le(n.node_id,{goal:e.prompt.trim()}),await yn(n);let Y;if(g!==void 0)try{const r=N(g);if(r===null)throw new Error(`invalid fork source ${g}`);const _=await E().fork(r,n.node_id);Y=(await E().header(_)).path}catch(r){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}const x=$e(n,{prompt:le,resumeSessionPath:Y});if(x.env={...x.env,CRTR_SUBTREE:await xe(n.node_id)},A){const r=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}:{}};x.env[We]=Me(r)}const h=Xe();if(await Ye(n.profile_id??null)!==null)return await W(n.node_id,new Date().toISOString()),H({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"remote_environment"}}),{node:await l(n.node_id),frozen:!0,window:null,session:null};const J=await h.reserveSlot(n.node_id),p=J?await qe(n.node_id):null;if(p?.verdict==="too_small"){h.releaseReservation(n.node_id);const r=Ve(p);throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),r}if(!J||p?.verdict==="denied")return p?.verdict==="denied"&&h.releaseReservation(n.node_id),await W(n.node_id,new Date().toISOString()),H({level:"info",event:"broker.frozen",node_id:n.node_id,fields:p?.verdict==="denied"?{reason:"app_memory",free_bytes:p.free_bytes,needed_bytes:p.needed_bytes}:{reason:"broker_cap",live_count:await h.occupancy(),hard_cap:re().automaticReviveCap}}),{node:await l(n.node_id),frozen:!0,window:null,session:null};const fe=await nn(n.node_id),{automaticReviveCap:ue}=re();let C;try{C=await ze(n.node_id,{daemonEpoch:h.epoch(),cap:ue})}catch(r){if(!(r instanceof je))throw r;return h.releaseReservation(n.node_id),await W(n.node_id,new Date().toISOString()),H({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"broker_cap",live_count:r.live,hard_cap:r.cap}}),{node:await l(n.node_id),frozen:!0,window:null,session:null}}x.env={...x.env,CRTR_EXECUTION_ID:C};let I;try{I=await hn(n.node_id,x,{cwd:n.cwd,name:oe(n),resuming:!1})}catch(r){throw await M(C,{reason:"launch_failed"}),r}finally{h.releaseReservation(n.node_id)}if(I.pid===null){const r=new Error(`broker host returned no pid for ${n.node_id}`);throw await M(C,{reason:"launch_failed"}),await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(r)}),B(`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 Ge(C,n.node_id,I.pid)==="shutdown")throw await M(C,{reason:"superseded"}),K.teardown(n.node_id),B(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(ce&&e.readiness==="await"&&!await en(n.node_id,I.exited)){const r=await fe.explanation();throw await pn(n.node_id,new Error(r??`broker view socket never bound for ${n.node_id}`)),B(r!==null?`the root broker ${n.node_id} could not start \u2014 ${r}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,r!==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,Z=null;if(!t&&s!==null&&rn("user").auto_open_child_viewers)try{const r=await Qe(s);if(r!==null&&r.pane!==null&&r.pane!==""){const _=await Je(n.node_id,r.session??"",{name:oe(n),cwd:e.cwd,besidePane:r.pane,waitForBroker:!0,initialWhip:A});_!==null&&_.pane!==null&&_.pane!==""&&(Z=_.session,Q=Ze(_.pane))}}catch{}return{node:await l(n.node_id),frozen:!1,window:Q,session:Z}}catch(f){throw b!==void 0&&w!==void 0&&await l(w)===null&&await Ne(b),f}}d(se,"spawnChildPrepared");async function wo(e){return se(e)}d(wo,"spawnChild");async function yn(e){const o=fn(e.cwd,e.profile_id).plans.get("node:start")??[];await un(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await z(e.node_id),contextDir:await j(e.node_id),jobDir:Ke(e.node_id)},runtime:{isBirth:!0,canvasHome:He(),profile:e.profile_id??null}})}d(yn,"invokeBirthLifecycleHooks");const gn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function mo(e,o,a){const i=await l(e);if(i===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 ie(e),s=await j(e);try{await E().header(N(t)),me(s,he.R_OK)}catch(c){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${c.message}`)}return se({kind:i.kind,mode:"base",cwd:i.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:i.profile_id,model:i.model_override??void 0,...o===void 0?{}:{scopes:o}},async c=>{const y=await j(c);Ue(await z(e),s,await z(c),y,gn)})}d(mo,"forkNode");export{ae as appPaidLaunch,de as assertLaunchModelRegistered,mo as forkNode,yn as invokeBirthLifecycleHooks,ie as resolveForkSource,kn as resolveProfileId,vn as resolveSpawner,wo as spawnChild,se as spawnChildPrepared};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var n=(e,r)=>k(e,"name",{value:r,configurable:!0});import{createHash as x,randomUUID as N}from"node:crypto";import{openDb as R}from"../canvas/db.js";import{claimReconcilerLease as $,releaseReconcilerLease as L,renewReconcilerLease as C}from"../canvas/reconciler-leases.js";import{claimWarmSpare as b,deleteNode as E,getNode as p,listNodes as W,listWarmSpares as M,registerWarmSpare as P,unregisterWarmSpare as A,updateNode as I,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as D}from"../canvas/pid.js";import{nowIso as u}from"../fs-utils.js";import{admitNodeCreate as O}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as T}from"./spawn.js";import{newNodeId as H}from"./nodes.js";import{checkStart as F}from"./start-check.js";import{buildLaunchSpecAsync as K}from"./launch.js";import{setModelLive as U}from"./model-swap.js";import{setSituationalContextLive as j}from"./situational-live.js";import{deliverBearingsLive as B}from"./deliver-live.js";import{closeNode as y}from"./close.js";function h(){return process.env.CRTR_WARM_POOL!=="0"}n(h,"warmPoolEnabled");function G(e,r,a){const t=Object.entries(a.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,a.tools??[],a.extensions??[],a.systemPrompt??null,t]);return x("sha256").update(o).digest("hex").slice(0,32)}n(G,"warmRecipeKey");async function d(e){const{launch:r}=await K(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId});return{key:G(e.cwd,e.profileId,r),launch:r,request:e}}n(d,"resolveRecipe");async function g(e){const r=e.creator===null?null:await p(e.creator);await F({grantee:r?.grantee??"app:terminal",sub:r?.sub,grant_id:r?.grant_id})}n(g,"checkClaimantStart");async function pe(e,r={},a){await g(e);const t=await d(e);if(await w(t.key)===0)return null;const o=u(),s=await O({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 b(t.key,o,r)}finally{s()}return i===null?null:v(i,t,o,a)}n(pe,"claimWarmNode");async function fe(e,r,a){return await g(e),v(r,await d(e),u(),a)}n(fe,"resumeWarmClaim");async function v(e,r,a,t){const{request:o}=r,i=(await p(e))?.launch?.model;await I(e,{created:a,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{t?.(e)}catch(l){return await m(e,"birth preparation",l)}try{await B(e)}catch(l){return await m(e,"bearings delivery",l)}const c=r.launch.model;if(c!==void 0&&c!==i)try{await U(e,c,r.launch.modelIntent)}catch(l){return await m(e,"model swap",l)}if(o.situationalContext!==null)try{await j(e,o.situationalContext)}catch(l){return await m(e,"situational-context delivery",l)}return e}n(v,"completeWarmClaim");async function m(e,r,a){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${a.message}`);try{await y(e)}catch{}return null}n(m,"abandonSpare");const J=3600*1e3;async function we(){const e=[];let r;try{r=await M()}catch(t){return console.error(`[warm-pool] spare scan failed: ${t.message}`),e}const a=Date.now()-J;for(const t of r){if(await z(t.node_id))continue;const o=Date.parse(t.created),s=Number.isNaN(o)||o<a,i=D(t.pi_pid,t.pi_pid_identity),c=(t.status==="active"||t.status==="idle")&&i==="alive";if(!(c&&!s)&&!(i==="indeterminate"&&!s))try{if(!await A(t.node_id))continue;if(c)try{await y(t.node_id)}catch{}await E(t.node_id),e.push(t.node_id)}catch(l){console.error(`[warm-pool] reap failed for ${t.node_id}: ${l.message}`)}}return e}n(we,"reapStaleSpares");const f=6e4;async function _(e,r){const a=N();if(await $(e,r,a,f)===void 0)return;const t=setInterval(()=>{C(e,r,a,f).catch(()=>{})},f/3);return t.unref(),async()=>{clearInterval(t),await L(e,r,a)}}n(_,"holdMintLease");async function z(e){return await(await R()).prepare("SELECT 1 FROM reconciler_leases WHERE lane = ? AND key = ? AND expires_at > ?").get("warm-pool-mint",e,new Date().toISOString())!==void 0}n(z,"mintLeaseHeld");function ue(e){if(h())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(ue,"refillWarmPool");async function S(e){const{key:r}=e,a=await _("warm-pool",r);if(a!==void 0){if(await w(r)>0){await a();return}Q(e,await H()).finally(()=>a().catch(()=>{}))}}n(S,"mint");async function Q({key:e,request:r},a){const t=await _("warm-pool-mint",a);if(t===void 0){console.error(`[warm-pool] mint refused for ${r.kind}: the mint lease of ${a} is held elsewhere`);return}try{await T({nodeId:a,kind:r.kind,mode:r.mode,cwd:r.cwd,prompt:"",root:!0,readiness:"await",profile:r.profileId},async o=>{await P(o,e)})}catch(o){console.error(`[warm-pool] mint failed for ${r.kind}: ${o.message}`)}finally{await t().catch(()=>{})}}n(Q,"birthSpare");const V=2;async function ye(){if(!h())return;let e;try{const r=new Set;e=[];for(const a of(await W({status:["active","idle"]})).reverse()){if(a.parent!==null||a.kind==="human")continue;const t=a.profile_id??null;if(!r.has(t??"")&&(r.add(t??""),e.push({cwd:a.cwd,profileId:t}),e.length>=V))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(a=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`))}catch(a){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`)}}n(ye,"prewarmRecentRecipes");export{Q as birthSpare,pe as claimWarmNode,_ as holdMintLease,ye as prewarmRecentRecipes,we as reapStaleSpares,ue as refillWarmPool,fe as resumeWarmClaim,h as warmPoolEnabled};
1
+ var k=Object.defineProperty;var n=(e,r)=>k(e,"name",{value:r,configurable:!0});import{createHash as x,randomUUID as N}from"node:crypto";import{openDb as R}from"../canvas/db.js";import{claimReconcilerLease as $,releaseReconcilerLease as L,renewReconcilerLease as b}from"../canvas/reconciler-leases.js";import{claimWarmSpare as C,deleteNode as E,getNode as p,listNodes as W,listWarmSpares as M,registerWarmSpare as I,unregisterWarmSpare as P,updateNode as A,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as O}from"../canvas/pid.js";import{nowIso as u}from"../fs-utils.js";import{admitNodeCreate as D}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as T}from"./spawn.js";import{blaxelEnvironmentOf as H}from"./blaxel-environment.js";import{newNodeId as F}from"./nodes.js";import{checkStart as K}from"./start-check.js";import{buildLaunchSpecAsync as U}from"./launch.js";import{setModelLive as j}from"./model-swap.js";import{setSituationalContextLive as B}from"./situational-live.js";import{deliverBearingsLive as G}from"./deliver-live.js";import{closeNode as y}from"./close.js";function h(){return process.env.CRTR_WARM_POOL!=="0"}n(h,"warmPoolEnabled");function J(e,r,a){const t=Object.entries(a.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,a.tools??[],a.extensions??[],a.systemPrompt??null,t]);return x("sha256").update(o).digest("hex").slice(0,32)}n(J,"warmRecipeKey");async function d(e){const{launch:r}=await U(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 g(e){const r=e.creator===null?null:await p(e.creator);await K({grantee:r?.grantee??"app:terminal",sub:r?.sub,grant_id:r?.grant_id})}n(g,"checkClaimantStart");async function we(e,r={},a){await g(e);const t=await d(e);if(await w(t.key)===0)return null;const o=u(),s=await D({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 C(t.key,o,r)}finally{s()}return i===null?null:v(i,t,o,a)}n(we,"claimWarmNode");async function ue(e,r,a){return await g(e),v(r,await d(e),u(),a)}n(ue,"resumeWarmClaim");async function v(e,r,a,t){const{request:o}=r,i=(await p(e))?.launch?.model;await A(e,{created:a,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{t?.(e)}catch(l){return await m(e,"birth preparation",l)}try{await G(e)}catch(l){return await m(e,"bearings delivery",l)}const c=r.launch.model;if(c!==void 0&&c!==i)try{await j(e,c,r.launch.modelIntent)}catch(l){return await m(e,"model swap",l)}if(o.situationalContext!==null)try{await B(e,o.situationalContext)}catch(l){return await m(e,"situational-context delivery",l)}return e}n(v,"completeWarmClaim");async function m(e,r,a){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${a.message}`);try{await y(e)}catch{}return null}n(m,"abandonSpare");const z=3600*1e3;async function ye(){const e=[];let r;try{r=await M()}catch(t){return console.error(`[warm-pool] spare scan failed: ${t.message}`),e}const a=Date.now()-z;for(const t of r){if(await Q(t.node_id))continue;const o=Date.parse(t.created),s=Number.isNaN(o)||o<a,i=O(t.pi_pid,t.pi_pid_identity),c=(t.status==="active"||t.status==="idle")&&i==="alive";if(!(c&&!s)&&!(i==="indeterminate"&&!s))try{if(!await P(t.node_id))continue;if(c)try{await y(t.node_id)}catch{}await E(t.node_id),e.push(t.node_id)}catch(l){console.error(`[warm-pool] reap failed for ${t.node_id}: ${l.message}`)}}return e}n(ye,"reapStaleSpares");const f=6e4;async function _(e,r){const a=N();if(await $(e,r,a,f)===void 0)return;const t=setInterval(()=>{b(e,r,a,f).catch(()=>{})},f/3);return t.unref(),async()=>{clearInterval(t),await L(e,r,a)}}n(_,"holdMintLease");async function Q(e){return await(await R()).prepare("SELECT 1 FROM reconciler_leases WHERE lane = ? AND key = ? AND expires_at > ?").get("warm-pool-mint",e,new Date().toISOString())!==void 0}n(Q,"mintLeaseHeld");function he(e){if(h())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(he,"refillWarmPool");async function S(e){const{key:r}=e;if(await H(e.request.profileId)!==null)return;const a=await _("warm-pool",r);if(a!==void 0){if(await w(r)>0){await a();return}V(e,await F()).finally(()=>a().catch(()=>{}))}}n(S,"mint");async function V({key:e,request:r},a){const t=await _("warm-pool-mint",a);if(t===void 0){console.error(`[warm-pool] mint refused for ${r.kind}: the mint lease of ${a} is held elsewhere`);return}try{await T({nodeId:a,kind:r.kind,mode:r.mode,cwd:r.cwd,prompt:"",root:!0,readiness:"await",profile:r.profileId},async o=>{await I(o,e)})}catch(o){console.error(`[warm-pool] mint failed for ${r.kind}: ${o.message}`)}finally{await t().catch(()=>{})}}n(V,"birthSpare");const X=2;async function ge(){if(!h())return;let e;try{const r=new Set;e=[];for(const a of(await W({status:["active","idle"]})).reverse()){if(a.parent!==null||a.kind==="human")continue;const t=a.profile_id??null;if(!r.has(t??"")&&(r.add(t??""),e.push({cwd:a.cwd,profileId:t}),e.length>=X))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(a=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`))}catch(a){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${a.message}`)}}n(ge,"prewarmRecentRecipes");export{V as birthSpare,we as claimWarmNode,_ as holdMintLease,ge as prewarmRecentRecipes,ye as reapStaleSpares,he as refillWarmPool,ue as resumeWarmClaim,h as warmPoolEnabled};
@@ -1 +1 @@
1
- var C=Object.defineProperty;var u=(e,r)=>C(e,"name",{value:r,configurable:!0});import{existsSync as R}from"node:fs";import{assertGranteeRunsHere as N}from"../runtime/unsandboxed.js";import{randomUUID as O}from"node:crypto";import{join as h}from"node:path";import{getNode as _}from"../canvas/canvas.js";import{nodeAgentDir as k,nodeHome as H,nodeRunDir as K}from"../canvas/paths.js";import{appSpace as B}from"../layout.js";import{activeGrant as g,activeGrantForApp as S,grantFor as I,grantsGeneration as y}from"../grants/mirror.js";import{emitEvent as G}from"../events/emit.js";import{ensureAppSpace as F}from"./space.js";import{compileLaunch as A,launchStillGranted as M}from"./mounts.js";import{pinSandboxRuntimeHome as j}from"./runtime-home.js";import{sandboxCacheEnv as q}from"./cache-env.js";import{launcherRequest as b}from"../../launcher/client.js";import{LAUNCHER_SOCKET as D}from"../../launcher/spec.js";import{personId as E}from"../canvas/person.js";function U(e){return`cron-${e}`}u(U,"cronLaunchId");function se(){if(process.platform!=="linux")return!1;if(R(D))return!0;throw new Error("root launcher socket is unavailable; refusing an unsandboxed app process")}u(se,"appProcessSandboxed");function fe(){return L??(process.platform==="linux"&&R(D))}u(fe,"appProcessesSandboxed");let L;function le(e){L=e}u(le,"__setAppProcessesSandboxedForTest");async function me(e,r,n,a=!1,t,d){const o=n===void 0?null:await _(n),c=d!==void 0?d.grantId?await g(d.grantId):await I(e,d.sub):o?null:await S(e);if((d!==void 0||!o)&&!c)throw new Error(`no active grant for ${e}`);return(await A({nodeId:n??"proc-cwd-check",app:e,...d!==void 0?{sub:d.sub,grantId:c?.id??null,scopes:d.scopes}:{sub:o?o.sub??E():c.sub,grantId:o?o.grant_id??null:c.id,scopes:o?.scopes??null},command:["true"],env:{},...n===void 0?{withoutNode:!0}:{},...t===void 0?{}:{folder:t},isolated:o?.isolated===!0||a,auditMissing:u(()=>{},"auditMissing")})).mounts.some(({source:s})=>r===s||r.startsWith(s==="/"?"/":`${s}/`))}u(me,"cwdIsMounted");async function P(e,r="SIGKILL",n){if(!("ok"in await b({operation:"stop",pid:e,signal:r,...n===void 0?{}:{nodeId:n}})))throw new Error("launcher did not stop process")}u(P,"stopAppProcess");function W(e,r,n,a,t){return a?t??k(e,r):n}u(W,"appProcessCwd");async function pe(e){if(e.cron!==void 0&&(e.nodeId!==void 0||e.principal===void 0))throw new Error("a cron launch has a stored principal and no node");const r=e.nodeId===void 0?null:await _(e.nodeId);if(e.nodeId!==void 0&&!r)throw new Error(`missing node ${e.nodeId}`);const n=r?.grantee??e.app??"app:terminal";if(N(n),e.app!==void 0&&e.app!==n)throw new Error("app does not match node");const a=e.principal;let t=null;if(a!==void 0){if(t=a.grantId?await g(a.grantId):await I(n,a.sub),!t||t.grantee!==n||t.sub!==a.sub)throw new Error(`no active grant for ${n}`)}else if(r){if(n!=="app:terminal"&&!(r.grant_id?await g(r.grant_id):await I(n,r.sub??E())))throw new Error(`no active grant for ${n}`)}else if(t=await S(n),!t)throw new Error(`no active grant for ${n}`);await F(n);const d=e.cron===void 0?e.nodeId??`proc-${O()}`:U(e.cron.executionId),o=r?.isolated===!0||e.isolated===!0;if(o&&!r&&e.folder===void 0)throw new Error("isolated process requires a live node");const c=B(n),m=W(d,n,e.cwd,o,e.folder),s=r?H(d,n,o):o&&e.folder!==void 0?h(e.folder,"home"):c.home,T=j(Object.fromEntries(Object.entries({...e.env,...process.platform==="linux"?q(n):{},HOME:s,PI_CODING_AGENT_DIR:h(s,".pi","agent"),PWD:m,...e.nodeId===void 0&&e.cron===void 0?{}:{CRTR_API_SOCKET:h(K(d),"cli.sock")}}).filter(i=>i[1]!==void 0))),x=a!==void 0?{nodeId:d,app:n,sub:a.sub,grantId:t?.id??null,scopes:a.scopes}:{nodeId:d,app:n,sub:r?r.sub??E():t.sub,grantId:r?r.grant_id??null:t.id,scopes:r?.scopes??null},$=u(async()=>{const i=await A({...x,command:e.command,env:T,...e.nodeId===void 0?{withoutNode:!0}:{},isolated:o,cwd:m,...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron.anchorDir===void 0?{}:{anchorDir:e.cron.anchorDir}},...e.pluginRoot===void 0?{}:{pluginRoot:e.pluginRoot},auditMissing:u(w=>G({level:"warn",event:"process.mount.missing",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{source:w}}),"auditMissing")});if(e.pluginRoot!==void 0&&(i.pluginRoot=e.pluginRoot),e.capture===!1){if(e.nodeId===void 0||e.stdin!==void 0)throw new Error("uncaptured process requires a node and no stdin")}else i.capture={stdoutBytes:e.stdoutBytes??256*1024,stderrBytes:e.stderrBytes??256*1024,...e.stderrTail?{stderrTail:!0}:{},...e.stdin===void 0?{}:{stdin:e.stdin}};return i},"compile");let f;for(let i=0;i<2&&f===void 0;i++){const w=await y(),v=await $(),l=await b({operation:"launch",spec:v});if(!("pid"in l))throw new Error("launcher did not return a process id");if(await y()===w||await M(x,v)){f=l.pid;break}G({level:"info",event:"process.launch.regranted",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{pid:l.pid}}),await P(l.pid,"SIGKILL").catch(()=>{})}if(f===void 0)throw new Error("grant changed during every launch attempt");const p=f;return{pid:p,get completion(){return b({operation:"wait",pid:p}).then(i=>{if(!("result"in i))throw new Error("launcher did not return process completion");return i.result})},stop:u((i="SIGKILL")=>P(p,i,e.cron===void 0?e.nodeId:d),"stop")}}u(pe,"launchAppProcess");export{le as __setAppProcessesSandboxedForTest,W as appProcessCwd,se as appProcessSandboxed,fe as appProcessesSandboxed,U as cronLaunchId,me as cwdIsMounted,pe as launchAppProcess,P as stopAppProcess};
1
+ var $=Object.defineProperty;var u=(e,r)=>$(e,"name",{value:r,configurable:!0});import{existsSync as R}from"node:fs";import{assertGranteeRunsHere as N}from"../runtime/unsandboxed.js";import{randomUUID as O}from"node:crypto";import{join as h}from"node:path";import{getNode as _}from"../canvas/canvas.js";import{nodeAgentDir as k,nodeHome as H,nodeRunDir as K}from"../canvas/paths.js";import{appSpace as B}from"../layout.js";import{activeGrant as g,activeGrantForApp as S,grantFor as I,grantsGeneration as y}from"../grants/mirror.js";import{emitEvent as G}from"../events/emit.js";import{ensureAppSpace as F}from"./space.js";import{compileLaunch as A,launchStillGranted as M}from"./mounts.js";import{pinSandboxRuntimeHome as j}from"./runtime-home.js";import{sandboxCacheEnv as q}from"./cache-env.js";import{launcherRequest as b}from"../../launcher/client.js";import{LAUNCHER_SOCKET as D}from"../../launcher/spec.js";import{isCloudRole as U,personId as E}from"../canvas/person.js";function W(e){return`cron-${e}`}u(W,"cronLaunchId");function fe(){if(process.platform!=="linux")return!1;if(R(D))return!0;throw new Error("root launcher socket is unavailable; refusing an unsandboxed app process")}u(fe,"appProcessSandboxed");function le(){return L??(process.platform==="linux"&&R(D))}u(le,"appProcessesSandboxed");let L;function pe(e){L=e}u(pe,"__setAppProcessesSandboxedForTest");async function me(e,r,n,a=!1,t,d){const o=n===void 0?null:await _(n),s=d!==void 0?d.grantId?await g(d.grantId):await I(e,d.sub):o?null:await S(e);if((d!==void 0||!o)&&!s)throw new Error(`no active grant for ${e}`);return(await A({nodeId:n??"proc-cwd-check",app:e,...d!==void 0?{sub:d.sub,grantId:s?.id??null,scopes:d.scopes}:{sub:o?o.sub??E():s.sub,grantId:o?o.grant_id??null:s.id,scopes:o?.scopes??null},command:["true"],env:{},...n===void 0?{withoutNode:!0}:{},...t===void 0?{}:{folder:t},isolated:o?.isolated===!0||a,auditMissing:u(()=>{},"auditMissing")})).mounts.some(({source:c})=>r===c||r.startsWith(c==="/"?"/":`${c}/`))}u(me,"cwdIsMounted");async function P(e,r="SIGKILL",n){if(!("ok"in await b({operation:"stop",pid:e,signal:r,...n===void 0?{}:{nodeId:n}})))throw new Error("launcher did not stop process")}u(P,"stopAppProcess");function z(e,r,n,a,t){return a?t??k(e,r):n}u(z,"appProcessCwd");async function we(e){if(U())throw new Error("a cloud role launches no app process; the node runs in its sandbox");if(e.cron!==void 0&&(e.nodeId!==void 0||e.principal===void 0))throw new Error("a cron launch has a stored principal and no node");const r=e.nodeId===void 0?null:await _(e.nodeId);if(e.nodeId!==void 0&&!r)throw new Error(`missing node ${e.nodeId}`);const n=r?.grantee??e.app??"app:terminal";if(N(n),e.app!==void 0&&e.app!==n)throw new Error("app does not match node");const a=e.principal;let t=null;if(a!==void 0){if(t=a.grantId?await g(a.grantId):await I(n,a.sub),!t||t.grantee!==n||t.sub!==a.sub)throw new Error(`no active grant for ${n}`)}else if(r){if(n!=="app:terminal"&&!(r.grant_id?await g(r.grant_id):await I(n,r.sub??E())))throw new Error(`no active grant for ${n}`)}else if(t=await S(n),!t)throw new Error(`no active grant for ${n}`);await F(n);const d=e.cron===void 0?e.nodeId??`proc-${O()}`:W(e.cron.executionId),o=r?.isolated===!0||e.isolated===!0;if(o&&!r&&e.folder===void 0)throw new Error("isolated process requires a live node");const s=B(n),p=z(d,n,e.cwd,o,e.folder),c=r?H(d,n,o):o&&e.folder!==void 0?h(e.folder,"home"):s.home,C=j(Object.fromEntries(Object.entries({...e.env,...process.platform==="linux"?q(n):{},HOME:c,PI_CODING_AGENT_DIR:h(c,".pi","agent"),PWD:p,...e.nodeId===void 0&&e.cron===void 0?{}:{CRTR_API_SOCKET:h(K(d),"cli.sock")}}).filter(i=>i[1]!==void 0))),x=a!==void 0?{nodeId:d,app:n,sub:a.sub,grantId:t?.id??null,scopes:a.scopes}:{nodeId:d,app:n,sub:r?r.sub??E():t.sub,grantId:r?r.grant_id??null:t.id,scopes:r?.scopes??null},T=u(async()=>{const i=await A({...x,command:e.command,env:C,...e.nodeId===void 0?{withoutNode:!0}:{},isolated:o,cwd:p,...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron.anchorDir===void 0?{}:{anchorDir:e.cron.anchorDir}},...e.pluginRoot===void 0?{}:{pluginRoot:e.pluginRoot},auditMissing:u(w=>G({level:"warn",event:"process.mount.missing",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{source:w}}),"auditMissing")});if(e.pluginRoot!==void 0&&(i.pluginRoot=e.pluginRoot),e.capture===!1){if(e.nodeId===void 0||e.stdin!==void 0)throw new Error("uncaptured process requires a node and no stdin")}else i.capture={stdoutBytes:e.stdoutBytes??256*1024,stderrBytes:e.stderrBytes??256*1024,...e.stderrTail?{stderrTail:!0}:{},...e.stdin===void 0?{}:{stdin:e.stdin}};return i},"compile");let f;for(let i=0;i<2&&f===void 0;i++){const w=await y(),v=await T(),l=await b({operation:"launch",spec:v});if(!("pid"in l))throw new Error("launcher did not return a process id");if(await y()===w||await M(x,v)){f=l.pid;break}G({level:"info",event:"process.launch.regranted",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{pid:l.pid}}),await P(l.pid,"SIGKILL").catch(()=>{})}if(f===void 0)throw new Error("grant changed during every launch attempt");const m=f;return{pid:m,get completion(){return b({operation:"wait",pid:m}).then(i=>{if(!("result"in i))throw new Error("launcher did not return process completion");return i.result})},stop:u((i="SIGKILL")=>P(m,i,e.cron===void 0?e.nodeId:d),"stop")}}u(we,"launchAppProcess");export{pe as __setAppProcessesSandboxedForTest,z as appProcessCwd,fe as appProcessSandboxed,le as appProcessesSandboxed,W as cronLaunchId,me as cwdIsMounted,we as launchAppProcess,P as stopAppProcess};
@@ -1,6 +1,7 @@
1
1
  /** App sandboxes bind the person's files through crtr-data group access. */
2
2
  export declare function ensureUserFiles(): void;
3
- /** On macOS no launcher or crtr-data group exists; directories stay owned by the Mac user. */
3
+ /** On macOS no launcher or crtr-data group exists; directories stay owned by the Mac user. A cloud role has no per-app OS user
4
+ * or directory to prepare: a node's files live in its sandbox and in rows, so it answers the process's own ids and touches nothing. */
4
5
  export declare function ensureAppSpace(app: string): Promise<{
5
6
  uid: number;
6
7
  gid: number;
@@ -1,2 +1,2 @@
1
- var f=Object.defineProperty;var n=(o,r)=>f(o,"name",{value:r,configurable:!0});import{chownSync as a,chmodSync as d,existsSync as l,mkdirSync as c,readFileSync as h,statSync as m}from"node:fs";import{appSpace as g,appsRoot as w,userFilesRoot as y}from"../layout.js";import{launcherRequest as S}from"../../launcher/client.js";import{LAUNCHER_SOCKET as x}from"../../launcher/spec.js";import{allocateAppUser as E,uidForApp as v}from"./users.js";function p(){const o=h("/etc/group","utf8").split(`
2
- `).find(e=>e.startsWith("crtr-data:"));if(!o)throw new Error("crtr-data group is required on sandboxed Linux");const r=Number(o.split(":")[2]);if(!Number.isInteger(r))throw new Error("invalid crtr-data group id");return r}n(p,"dataGroup");function L(){const o=y(),r=p();c(o,{recursive:!0,mode:1528});const e=m(o),t=e.mode&4095;if(!e.isDirectory()||e.gid!==r||t!==1528){if(!e.isDirectory()||e.uid!==process.getuid())throw new Error(`${o} has owner ${e.uid}, group ${e.gid}, mode ${t.toString(8).padStart(4,"0")}; requires an crtr-data (${r}) directory with mode 2770; only its owner can repair it`);e.gid!==r&&a(o,e.uid,r),t!==1528&&d(o,1528)}}n(L,"ensureUserFiles");async function N(o){const r=g(o);if(!(process.platform==="linux"&&l(x))){if(process.platform==="linux")throw new Error("app space requires the root launcher on Linux");for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0});return{uid:await v(o),gid:process.getgid(),root:r.root}}const t=p(),s=await E(o),u=await S({operation:"user.create",app:r.root.slice(w().length+1),uid:s.uid});if(!("uid"in u)||u.uid!==s.uid)throw new Error(`launcher did not create OS user for ${o}`);for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0,mode:1528}),a(i,process.getuid(),t),d(i,1528);return{uid:s.uid,gid:t,root:r.root}}n(N,"ensureAppSpace");export{N as ensureAppSpace,L as ensureUserFiles};
1
+ var f=Object.defineProperty;var s=(o,r)=>f(o,"name",{value:r,configurable:!0});import{chownSync as a,chmodSync as d,existsSync as l,mkdirSync as c,readFileSync as m,statSync as h}from"node:fs";import{appSpace as g,appsRoot as w,userFilesRoot as y}from"../layout.js";import{launcherRequest as S}from"../../launcher/client.js";import{LAUNCHER_SOCKET as x}from"../../launcher/spec.js";import{allocateAppUser as E,uidForApp as v}from"./users.js";import{isCloudRole as $}from"../canvas/person-state.js";function p(){const o=m("/etc/group","utf8").split(`
2
+ `).find(e=>e.startsWith("crtr-data:"));if(!o)throw new Error("crtr-data group is required on sandboxed Linux");const r=Number(o.split(":")[2]);if(!Number.isInteger(r))throw new Error("invalid crtr-data group id");return r}s(p,"dataGroup");function N(){const o=y(),r=p();c(o,{recursive:!0,mode:1528});const e=h(o),t=e.mode&4095;if(!e.isDirectory()||e.gid!==r||t!==1528){if(!e.isDirectory()||e.uid!==process.getuid())throw new Error(`${o} has owner ${e.uid}, group ${e.gid}, mode ${t.toString(8).padStart(4,"0")}; requires an crtr-data (${r}) directory with mode 2770; only its owner can repair it`);e.gid!==r&&a(o,e.uid,r),t!==1528&&d(o,1528)}}s(N,"ensureUserFiles");async function U(o){const r=g(o);if($())return{uid:process.getuid(),gid:process.getgid(),root:r.root};if(!(process.platform==="linux"&&l(x))){if(process.platform==="linux")throw new Error("app space requires the root launcher on Linux");for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0});return{uid:await v(o),gid:process.getgid(),root:r.root}}const t=p(),n=await E(o),u=await S({operation:"user.create",app:r.root.slice(w().length+1),uid:n.uid});if(!("uid"in u)||u.uid!==n.uid)throw new Error(`launcher did not create OS user for ${o}`);for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0,mode:1528}),a(i,process.getuid(),t),d(i,1528);return{uid:n.uid,gid:t,root:r.root}}s(U,"ensureAppSpace");export{U as ensureAppSpace,N as ensureUserFiles};
@@ -1 +1 @@
1
- var N=Object.defineProperty;var a=(t,e)=>N(t,"name",{value:e,configurable:!0});import{canonicalSessionFile as B,findNodeBySessionFile as I,getNode as h,isWarmSpare as C,recordRespawnAttempt as q,recordSettledTurn as M,setPresence as k,subscriptionsOf as $,updateNode as v,updateNodeTelemetry as j}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as D,recordExecutionIdle as L,recordExecutionPid as U}from"../../../core/canvas/executions.js";import{bindSession as W,readLiveSession as G,transferSession as H}from"../../../core/canvas/sessions.js";import{isSafeNodeId as V}from"../../../core/canvas/paths.js";import{appForNode as J}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as Y}from"../../../core/canvas/pid.js";import{editorLabel as x}from"../../../core/canvas/labels.js";import{assembleNodeSubject as z}from"../../../core/substrate/subject.js";import{openDb as K,withCanvasWrite as p}from"../../../core/canvas/db.js";import{runningJobs as Q}from"../../../core/graph/jobs.js";import{notFound as g,usage as u}from"../../../core/errors.js";import{hasUnseenWakeMail as S}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as X}from"../../../core/runtime/kickoff.js";import{readRoadmap as Z}from"../../../core/runtime/roadmap.js";import{forkSourceNode as ee}from"../../../core/runtime/nodes.js";import{transition as _}from"../../../core/runtime/lifecycle.js";import{confirmViewer as P,probeViewer as R,tearDownNode as O}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as te}from"../viewer-presence.js";import{evaluateStop as ne}from"../../../core/runtime/stop-guard.js";import{clearFault as w,recordFault as ie}from"../../../core/canvas/recovery.js";import{updateModelRecipe as oe}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as re}from"../../review/finish.js";import{emitEvent as F}from"../../../core/events/emit.js";import{consumePendingPark as ae,recordPendingParkActivity as se}from"../../park-pending.js";import{shouldParkAfterSummary as de}from"../../park-activity.js";import{ownerOnly as ce}from"../router.js";import{situationalContextEnvelope as ue}from"../../../core/runtime/situational-context.js";import{requireCurrentExecution as f}from"./broker-recovery.js";import{ensureRunObserver as le}from"../../runs/observer.js";import{parseNodeTelemetryRecord as pe,writeNodeTelemetryRecord as fe}from"./telemetry-record.js";import{mapAsync as E}from"../../../core/async-array.js";function l(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw u(`${e} requires a JSON body`);return t}a(l,"objectBody");function me(t){const e=l(t,"broker session-bound");if(typeof e.executionId!="string"||e.executionId==="")throw u("executionId must be a non-empty string");if(typeof e.piSessionId!="string"||e.piSessionId==="")throw u("piSessionId must be a non-empty string");if(e.sessionFile!==null&&typeof e.sessionFile!="string")throw u("sessionFile must be a string or null");if(!Number.isSafeInteger(e.pid)||e.pid<=0)throw u("pid must be a positive safe integer");if(e.reason!==null&&typeof e.reason!="string")throw u("reason must be a string or null");if(!Array.isArray(e.reviewBoundaryIds)||!e.reviewBoundaryIds.every(n=>typeof n=="string"))throw u("reviewBoundaryIds must be an array of strings");return e}a(me,"parseSessionBoundBody");function we(t){const e=l(t,"broker settle");if(typeof e.stopReason!="string")throw u("stopReason must be a string");for(const n of["pushedFinal"])if(typeof e[n]!="boolean")throw u(`${n} must be a boolean`);return e}a(we,"parseSettleBody");function ye(t){const e=l(t,"broker park-complete");if(e.outcome!=="completed"&&e.outcome!=="failed")throw u("outcome must be completed or failed");return e}a(ye,"parseParkCompleteBody");function he(t){const e=l(t,"broker telemetry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw u("expected_execution_id must be a non-empty string");const n=pe(e);return{...n,expected_execution_id:e.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}a(he,"parseTelemetryBody");function _e(t){const e=l(t,"broker model");if(typeof e.spec!="string"||e.spec.trim()==="")throw u("spec must be a non-empty string");const n=e.intent;if(n!==void 0){const i=n!==null&&typeof n=="object"?n:void 0;if(i===void 0||typeof i.family!="string"||i.family===""||!["ultra","strong","medium","light"].includes(i.strength))throw u("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof e.userSelected!="boolean")throw u("userSelected must be a boolean");return e}a(_e,"parseModelCommitBody");async function m(t){const e=await h(t);if(e===null)throw g(`unknown node: ${t}`,{received:t});return e}a(m,"requireNode");async function b(t){return{node_id:t.node_id,grantee:await J(t.node_id),name:t.name,...t.description===void 0?{}:{description:t.description},...t.title===void 0?{}:{title:t.title},...t.icon===void 0?{}:{icon:t.icon},kind:t.kind,mode:t.mode,lifecycle:t.lifecycle,status:t.status,cwd:t.cwd,parent:t.parent??null,fork_from:t.fork_from??null,profile_id:t.profile_id??null,...t.managed_worktree===void 0?{}:{managed_worktree:t.managed_worktree===null?null:{state:t.managed_worktree.state,...t.managed_worktree.cleanup===void 0?{}:{cleanup:t.managed_worktree.cleanup},path:t.managed_worktree.path,branch:t.managed_worktree.branch,base_ref:t.managed_worktree.base_ref,base_sha:t.managed_worktree.base_sha}},...t.review_binding===void 0?{}:{review_binding:t.review_binding??null},intent:t.intent??null,...t.persona_ack===void 0?{}:{persona_ack:t.persona_ack},created:t.created}}a(b,"extensionNode");async function be(t){const e=await m(t),n=[],i=new Set([t]);let o=e.parent??null;for(;o!==null&&o!==""&&!i.has(o);){i.add(o);const s=await h(o);if(s===null)break;n.unshift(await b(s)),o=s.parent??null}const r=await E((await E(await $(t),async s=>await h(s.node_id))).filter(s=>s!==null&&s.kind!=="human").sort((s,y)=>s.status===y.status?0:s.status==="active"?-1:y.status==="active"?1:0),b),d=typeof e.fork_source_file=="string"?await ee(e.fork_source_file):null,c=await z(t);if(c===null)throw g(`unknown node: ${t}`,{received:t});return{node:await b(e),warm_spare:await C(t),situational_card:await ue(t),ancestors:n,children:r,fork_source:d===null?null:await b(d),subject:c,roadmap:await Z(t)}}a(be,"extensionState");function T(t,e){return t?.kind===e.kind&&t?.mode===e.mode&&t?.lifecycle===e.lifecycle}a(T,"samePersona");function ke(t){const e=l(t,"broker generated-name");if(e.kind!=="initial"&&e.kind!=="recap")throw u("kind must be initial or recap");if(typeof e.description!="string"||typeof e.title!="string"||typeof e.icon!="string")throw u("description, title, and icon must be strings");if(e.kind==="initial")return e;const n=e.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(i=>typeof n[i]!="string"))throw u("recap expected must contain name, description, title, icon, and kind strings");return e}a(ke,"parseGeneratedNameBody");function ve(t){const e=l(t,"broker persona-ack"),n=a(i=>{const o=e[i];if(typeof o!="object"||o===null||Array.isArray(o)||typeof o.kind!="string"||o.mode!=="base"&&o.mode!=="orchestrator"||o.lifecycle!=="terminal"&&o.lifecycle!=="resident")throw u(`${i} must be a persona state`);return o},"parse");return{expected_execution_id:e.expected_execution_id,from:n("from"),to:n("to")}}a(ve,"parsePersonaAckBody");async function ge(t){const e=t.params.id,n=me(t.body),i=n.sessionFile===null?null:B(n.sessionFile);return{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const d=await m(e);if(await U(n.executionId,e,n.pid)==="shutdown")return{action:"shutdown"};const c=d.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&d.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&d.fork_from!=null&&d.pi_session_id==null&&i===null)return{action:"shutdown"};const s=i===null?null:await I(i);if(s!==null&&s.node_id!==e){if(Y(s.pi_pid))return await ie(e,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${i}: it is owned by live node ${s.node_id}`}),{action:"shutdown"};const y=await G(s.node_id);if(y===null||await H({fromNodeId:s.node_id,fromBindingId:y.bindingId,toNodeId:e,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})!=="transferred")return{action:"shutdown"}}else if(await W(e,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await X(e),d.intent==="refresh"&&await _(e,"revive")),{action:"none"}})}}a(ge,"handleSessionBound");async function xe(t,e,n){const i=await h(t);if(i===null){if(e.pushedFinal)return{directive:{action:"shutdown"},closePane:!1};throw g(`unknown node: ${t}`,{received:t})}if(await M(t,new Date().toISOString()),(e.stopReason==="stop"||e.stopReason==="length")&&await q(t,{failures:0,notBefore:null}),e.stopReason==="quit"){let c=!1;return(i.status==="active"||i.status==="idle")&&i.intent===null&&(await _(t,"finish"),await w(t),await k(t,{pane:null,tmux_session:null,window:null}),c=!0),{directive:{action:"shutdown"},closePane:c}}if(e.stopReason!=="stop"&&e.stopReason!=="length")return await w(t,{link:"daemon\u2192node"}),{directive:i.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"},closePane:!1};const o={pushedFinal:e.pushedFinal};if(o.pushedFinal||i.status==="done")return await w(t),await k(t,{pane:null,tmux_session:null,window:null}),{directive:{action:"shutdown"},closePane:!0};if(i.intent==="refresh")return await w(t),{directive:{action:"shutdown"},closePane:!1};const r=await ne(t,o);if(await w(t),r.action==="reprompt")return{directive:{action:"reprompt",prompt:r.message},closePane:!1};if(r.reason==="finished")return{directive:await S(t)?{action:"stay_dormant"}:{action:"shutdown"},closePane:!1};const d=n.live!==null||await te(t)||await S(t);return(await D(t))?.runner==="blaxel"?{directive:!d&&(await Q(await K(),t)).length===0?{action:"stay_resident"}:{action:"stay_dormant"},closePane:!1}:r.reason!=="awaiting"&&r.reason!=="scheduled"?{directive:{action:"stay_dormant"},closePane:!1}:d?{directive:{action:"stay_dormant"},closePane:!1}:(await _(t,"release"),{directive:{action:"shutdown"},closePane:!1})}a(xe,"settleBroker");async function Se(t){const e=t.params.id,n=l(t.body,"broker idle");return await f(e,n.expected_execution_id),await L(n.expected_execution_id),{status:204}}a(Se,"handleIdle");async function Pe(t){const e=t.params.id,n=we(t.body);await f(e,n.expected_execution_id);const i=await R(e),{directive:o,closePane:r}=await p(async()=>await xe(e,n,await P(i)));return r&&await O(e),o.action!=="reprompt"&&re(e).catch(d=>F({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:e,error:d})),{status:200,body:o}}a(Pe,"handleSettle");async function Re(t){const e=t.params.id,n=ye(t.body);await f(e,n.expected_execution_id);const i=await R(e),o=await p(async()=>{const r=await ae(e);if(r===void 0)return{action:"stay_dormant"};const d=await m(e);return await de(e,d,r,await P(i))?(await w(e),await _(e,"park"),await k(e,{pane:null,tmux_session:null,window:null}),F({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...V(e)?{node_id:e}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}});return o.action==="shutdown"&&await O(e),{status:200,body:o}}a(Re,"handleParkComplete");async function Oe(t){const e=t.params.id;return await f(e,l(t.body,"broker park-activity").expected_execution_id),{status:200,body:await p(async()=>({activity:await se(e)?"recorded":"none"}))}}a(Oe,"handleParkActivity");async function Fe(t){const e=t.params.id,n=he(t.body);return await f(e,n.expected_execution_id),await p(async()=>{await j(e,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),fe(e,n)}),{status:204}}a(Fe,"handleTelemetry");async function Ee(t){const e=t.params.id,n=_e(t.body);return await f(e,n.expected_execution_id),{status:200,body:{modelOverride:(await p(async()=>await oe(await m(e),n.spec,n.intent,n.userSelected))).model_override}}}a(Ee,"handleModelCommit");let A=!0;function lt(t){A=t}a(lt,"setRequestsStartRunObservers");async function Te(t){const e=t.params.id,n=await m(e);return n.run_id&&A&&await le(e,n.run_id),{status:200,body:await be(e)}}a(Te,"handleExtensionState");async function Ae(t){const e=t.params.id,n=ke(t.body);return await f(e,n.expected_execution_id),{status:200,body:await p(async o=>{await o.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const r=await m(e);if(n.kind==="initial"){if((r.description??"").trim()!=="")return{applied:!1};const s=await v(e,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:x(s),description:s.description??"",title:s.title??"",icon:s.icon??""}}const d=n.expected;if(r.name!==d.name||(r.description??"")!==d.description||(r.title??"")!==d.title||(r.icon??"")!==d.icon||r.kind!==d.kind)return{applied:!1};const c=await v(e,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:x(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}a(Ae,"handleGeneratedName");async function Ne(t){const e=t.params.id,n=ve(t.body);return await f(e,n.expected_execution_id),{status:200,body:await p(async o=>{await o.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const r=await m(e),d={kind:r.kind,mode:r.mode,lifecycle:r.lifecycle},c=r.persona_ack,s=c===void 0?d:{kind:c.kind??r.kind,mode:c.mode,lifecycle:c.lifecycle};return!T(d,n.to)||!T(s,n.from)?{applied:!1}:(await v(e,{persona_ack:n.to}),{applied:!0})})}}a(Ne,"handlePersonaAck");const pt=ce([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:ge},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Pe},{method:"POST",pattern:"/v1/nodes/:id/broker/idle",handler:Se},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:Re},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:Oe},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Fe},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:Ee},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Te},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Ae},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:Ne}]);export{pt as brokerOperationRoutes,b as extensionNode,lt as setRequestsStartRunObservers};
1
+ var I=Object.defineProperty;var o=(e,t)=>I(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as q,findNodeBySessionFile as M,getNode as h,isWarmSpare as $,recordRespawnAttempt as j,recordSettledTurn as D,setPresence as k,subscriptionsOf as L,updateNode as v,updateNodeTelemetry as U}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as x,recordExecutionIdle as W,recordExecutionPid as H}from"../../../core/canvas/executions.js";import{bindSession as G,readLiveSession as V,transferSession as J}from"../../../core/canvas/sessions.js";import{isSafeNodeId as Y}from"../../../core/canvas/paths.js";import{appForNode as z}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as K}from"../../../core/canvas/pid.js";import{editorLabel as S}from"../../../core/canvas/labels.js";import{assembleNodeSubject as Q}from"../../../core/substrate/subject.js";import{openDb as X,withCanvasWrite as p}from"../../../core/canvas/db.js";import{runningJobs as Z}from"../../../core/graph/jobs.js";import{notFound as g,usage as u}from"../../../core/errors.js";import{hasUnseenWakeMail as P}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as ee}from"../../../core/runtime/kickoff.js";import{readRoadmap as te}from"../../../core/runtime/roadmap.js";import{forkSourceNode as ne}from"../../../core/runtime/nodes.js";import{transition as _}from"../../../core/runtime/lifecycle.js";import{confirmViewer as R,probeViewer as O,tearDownNode as F}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as ie}from"../viewer-presence.js";import{evaluateStop as re}from"../../../core/runtime/stop-guard.js";import{readOutputRequest as oe}from"../../../core/runtime/output-result.js";import{clearFault as w,readFault as ae,recordFault as se}from"../../../core/canvas/recovery.js";import{updateModelRecipe as de}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as ce}from"../../review/finish.js";import{emitEvent as A}from"../../../core/events/emit.js";import{consumePendingPark as ue,recordPendingParkActivity as le}from"../../park-pending.js";import{shouldParkAfterSummary as pe}from"../../park-activity.js";import{ownerOnly as fe}from"../router.js";import{situationalContextEnvelope as me}from"../../../core/runtime/situational-context.js";import{requireCurrentExecution as f}from"./broker-recovery.js";import{ensureRunObserver as we}from"../../runs/observer.js";import{parseNodeTelemetryRecord as ye,writeNodeTelemetryRecord as he}from"./telemetry-record.js";import{mapAsync as E}from"../../../core/async-array.js";function l(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw u(`${t} requires a JSON body`);return e}o(l,"objectBody");function _e(e){const t=l(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw u("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw u("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw u("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw u("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw u("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw u("reviewBoundaryIds must be an array of strings");return t}o(_e,"parseSessionBoundBody");function be(e){const t=l(e,"broker settle");if(typeof t.stopReason!="string")throw u("stopReason must be a string");for(const n of["pushedFinal"])if(typeof t[n]!="boolean")throw u(`${n} must be a boolean`);return t}o(be,"parseSettleBody");function ke(e){const t=l(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw u("outcome must be completed or failed");return t}o(ke,"parseParkCompleteBody");function ve(e){const t=l(e,"broker telemetry");if(typeof t.expected_execution_id!="string"||t.expected_execution_id==="")throw u("expected_execution_id must be a non-empty string");const n=ye(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}o(ve,"parseTelemetryBody");function ge(e){const t=l(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw u("spec must be a non-empty string");const n=t.intent;if(n!==void 0){const i=n!==null&&typeof n=="object"?n:void 0;if(i===void 0||typeof i.family!="string"||i.family===""||!["ultra","strong","medium","light"].includes(i.strength))throw u("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof t.userSelected!="boolean")throw u("userSelected must be a boolean");return t}o(ge,"parseModelCommitBody");async function m(e){const t=await h(e);if(t===null)throw g(`unknown node: ${e}`,{received:e});return t}o(m,"requireNode");async function b(e){return{node_id:e.node_id,grantee:await z(e.node_id),name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}o(b,"extensionNode");async function xe(e){const t=await m(e),n=[],i=new Set([e]);let r=t.parent??null;for(;r!==null&&r!==""&&!i.has(r);){i.add(r);const s=await h(r);if(s===null)break;n.unshift(await b(s)),r=s.parent??null}const a=await E((await E(await L(e),async s=>await h(s.node_id))).filter(s=>s!==null&&s.kind!=="human").sort((s,y)=>s.status===y.status?0:s.status==="active"?-1:y.status==="active"?1:0),b),d=typeof t.fork_source_file=="string"?await ne(t.fork_source_file):null,c=await Q(e);if(c===null)throw g(`unknown node: ${e}`,{received:e});return{node:await b(t),warm_spare:await $(e),situational_card:await me(e),ancestors:n,children:a,fork_source:d===null?null:await b(d),subject:c,roadmap:await te(e)}}o(xe,"extensionState");function T(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}o(T,"samePersona");function Se(e){const t=l(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw u("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw u("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(i=>typeof n[i]!="string"))throw u("recap expected must contain name, description, title, icon, and kind strings");return t}o(Se,"parseGeneratedNameBody");function Pe(e){const t=l(e,"broker persona-ack"),n=o(i=>{const r=t[i];if(typeof r!="object"||r===null||Array.isArray(r)||typeof r.kind!="string"||r.mode!=="base"&&r.mode!=="orchestrator"||r.lifecycle!=="terminal"&&r.lifecycle!=="resident")throw u(`${i} must be a persona state`);return r},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}o(Pe,"parsePersonaAckBody");async function Re(e){const t=e.params.id,n=_e(e.body),i=n.sessionFile===null?null:q(n.sessionFile);return{status:200,body:await p(async a=>{await a.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const d=await m(t);if(await H(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const c=d.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&d.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&d.fork_from!=null&&d.pi_session_id==null&&i===null)return{action:"shutdown"};const s=i===null?null:await M(i);if(s!==null&&s.node_id!==t){if(K(s.pi_pid))return await se(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${i}: it is owned by live node ${s.node_id}`}),{action:"shutdown"};const y=await V(s.node_id);if(y===null||await J({fromNodeId:s.node_id,fromBindingId:y.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})!=="transferred")return{action:"shutdown"}}else if(await G(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await ee(t),d.intent==="refresh"&&await _(t,"revive")),{action:"none"}})}}o(Re,"handleSessionBound");async function B(e,t){return t.live!==null||await ie(e)||await P(e)}o(B,"isHeldAwake");async function N(e,t){return(await x(e))?.runner==="blaxel"&&!await B(e,t)&&(await Z(await X(),e)).length===0}o(N,"residentBlaxelCanIdle");async function Oe(e,t,n){const i=await h(e);if(i===null){if(t.pushedFinal)return{directive:{action:"shutdown"},closePane:!1};throw g(`unknown node: ${e}`,{received:e})}if(await D(e,new Date().toISOString()),(t.stopReason==="stop"||t.stopReason==="length")&&await j(e,{failures:0,notBefore:null}),t.stopReason==="quit"){let c=!1;return(i.status==="active"||i.status==="idle")&&i.intent===null&&(await _(e,"finish"),await w(e),await k(e,{pane:null,tmux_session:null,window:null}),c=!0),{directive:{action:"shutdown"},closePane:c}}if(t.stopReason!=="stop"&&t.stopReason!=="length")return await w(e,{link:"daemon\u2192node"}),i.intent==="refresh"?{directive:{action:"shutdown"},closePane:!1}:t.stopReason==="error"&&t.faultSettled===!0&&(await ae(e))?.retry.disposition==="fatal"&&await oe(e)===null&&await N(e,n)?{directive:{action:"stay_resident"},closePane:!1}:{directive:{action:"stay_dormant"},closePane:!1};const r={pushedFinal:t.pushedFinal};if(r.pushedFinal||i.status==="done")return await w(e),await k(e,{pane:null,tmux_session:null,window:null}),{directive:{action:"shutdown"},closePane:!0};if(i.intent==="refresh")return await w(e),{directive:{action:"shutdown"},closePane:!1};const a=await re(e,r);if(await w(e),a.action==="reprompt")return{directive:{action:"reprompt",prompt:a.message},closePane:!1};if(a.reason==="finished")return{directive:await P(e)?{action:"stay_dormant"}:{action:"shutdown"},closePane:!1};const d=await B(e,n);return(await x(e))?.runner==="blaxel"?{directive:await N(e,n)?{action:"stay_resident"}:{action:"stay_dormant"},closePane:!1}:a.reason!=="awaiting"&&a.reason!=="scheduled"?{directive:{action:"stay_dormant"},closePane:!1}:d?{directive:{action:"stay_dormant"},closePane:!1}:(await _(e,"release"),{directive:{action:"shutdown"},closePane:!1})}o(Oe,"settleBroker");async function Fe(e){const t=e.params.id,n=l(e.body,"broker idle");return await f(t,n.expected_execution_id),await W(n.expected_execution_id),{status:204}}o(Fe,"handleIdle");async function Ae(e){const t=e.params.id,n=be(e.body);await f(t,n.expected_execution_id);const i=await O(t),{directive:r,closePane:a}=await p(async()=>await Oe(t,n,await R(i)));return a&&await F(t),r.action!=="reprompt"&&ce(t).catch(d=>A({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:t,error:d})),{status:200,body:r}}o(Ae,"handleSettle");async function Ee(e){const t=e.params.id,n=ke(e.body);await f(t,n.expected_execution_id);const i=await O(t),r=await p(async()=>{const a=await ue(t);if(a===void 0)return{action:"stay_dormant"};const d=await m(t);return await pe(t,d,a,await R(i))?(await w(t),await _(t,"park"),await k(t,{pane:null,tmux_session:null,window:null}),A({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...Y(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}});return r.action==="shutdown"&&await F(t),{status:200,body:r}}o(Ee,"handleParkComplete");async function Te(e){const t=e.params.id;return await f(t,l(e.body,"broker park-activity").expected_execution_id),{status:200,body:await p(async()=>({activity:await le(t)?"recorded":"none"}))}}o(Te,"handleParkActivity");async function Be(e){const t=e.params.id,n=ve(e.body);return await f(t,n.expected_execution_id),await p(async()=>{await U(t,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),he(t,n)}),{status:204}}o(Be,"handleTelemetry");async function Ne(e){const t=e.params.id,n=ge(e.body);return await f(t,n.expected_execution_id),{status:200,body:{modelOverride:(await p(async()=>await de(await m(t),n.spec,n.intent,n.userSelected))).model_override}}}o(Ne,"handleModelCommit");let C=!0;function yt(e){C=e}o(yt,"setRequestsStartRunObservers");async function Ce(e){const t=e.params.id,n=await m(t);return n.run_id&&C&&await we(t,n.run_id),{status:200,body:await xe(t)}}o(Ce,"handleExtensionState");async function Ie(e){const t=e.params.id,n=Se(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t);if(n.kind==="initial"){if((a.description??"").trim()!=="")return{applied:!1};const s=await v(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:S(s),description:s.description??"",title:s.title??"",icon:s.icon??""}}const d=n.expected;if(a.name!==d.name||(a.description??"")!==d.description||(a.title??"")!==d.title||(a.icon??"")!==d.icon||a.kind!==d.kind)return{applied:!1};const c=await v(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:S(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}o(Ie,"handleGeneratedName");async function qe(e){const t=e.params.id,n=Pe(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t),d={kind:a.kind,mode:a.mode,lifecycle:a.lifecycle},c=a.persona_ack,s=c===void 0?d:{kind:c.kind??a.kind,mode:c.mode,lifecycle:c.lifecycle};return!T(d,n.to)||!T(s,n.from)?{applied:!1}:(await v(t,{persona_ack:n.to}),{applied:!0})})}}o(qe,"handlePersonaAck");const ht=fe([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:Re},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Ae},{method:"POST",pattern:"/v1/nodes/:id/broker/idle",handler:Fe},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:Ee},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:Te},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Be},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:Ne},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Ce},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Ie},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:qe}]);export{ht as brokerOperationRoutes,b as extensionNode,yt as setRequestsStartRunObservers};
@@ -1 +1 @@
1
- var O=Object.defineProperty;var a=(n,e)=>O(n,"name",{value:e,configurable:!0});import{deleteAuthCredential as y,readAuthCredentials as S,setAuthCredential as b}from"../../../core/auth-file.js";import{ApiError as i}from"../../../api/index.js";import{RunError as g}from"../../../core/runs/operations.js";import{usage as u}from"../../../core/errors.js";import{modelAuthReadiness as E}from"../../../core/model-auth/readiness.js";import{MANAGED_PROVIDER_IDS as v,OPENAI_CHATGPT_PROVIDER_ID as D,DuplicateSubscriptionError as I,commitManagedLogin as P,isManagedProvider as l,promoteSubscription as $,readSubscriptionPool as m,removeAllManagedAccounts as T,removeManagedAccount as j,renameSubscription as F}from"../../../core/subscription-state.js";import{cancelModelAuthFlow as M,completeModelAuthFlow as C,startModelAuthFlow as R,waitModelAuthFlow as L}from"../../../core/model-auth/flows.js";import{waitSeconds as G}from"../long-poll-wait.js";function k(n,e){if(typeof e!="string"||e==="")throw new i(400,"invalid_request",`oauth credential requires \`${n}\``);const t=Date.parse(e);if(Number.isNaN(t))throw new i(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return t}a(k,"parseExpiry");function c(n,e,t){if(typeof t!="string"||t==="")throw new i(400,"invalid_request",`${n} credential requires \`${e}\``);return t}a(c,"requireField");function N(n,e=Date.now()){const t=Object.entries(n.modelCooldowns??{}).filter(([,o])=>o>e).map(([o,r])=>({family:o,rate_limited_until:new Date(r).toISOString()}));return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...t.length?{model_cooldowns:t}:{},...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}a(N,"toManagedAccountStatus");async function p(n){const e=(await m(n)).map(t=>N(t));return{provider:n,managed:!0,configured:e.length>0,accounts:e}}a(p,"managedStatus");function f(n,e){const t=n.query.getAll(e);if(t.length>1)throw u(`${e} must appear at most once`);return t[0]}a(f,"singleQueryValue");async function U(){const n=await S(),e=new Set;for(const r of v)r===D&&n[r]!==void 0&&(await m(r)).length===0&&e.add(r);const t=a(r=>e.has(r),"legacyApiKey"),o=await Promise.all(v.filter(r=>!t(r)).map(p));for(const[r,s]of Object.entries(n))l(r)&&!t(r)||s.type!=="api_key"&&s.type!=="oauth"||o.push({provider:r,managed:!1,configured:!0,kind:s.type});return{status:200,body:{providers:o}}}a(U,"handleList");async function K(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw u(`unknown model-auth readiness query parameter: ${s}`);const e=f(n,"profile"),t=f(n,"cwd"),o=f(n,"kind"),r=f(n,"model");if(o!==void 0&&o.trim()==="")throw u("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw u("model must be a non-empty string when provided");return{status:200,body:await E({...e!==void 0?{profile:e}:{},...t!==void 0?{cwd:t}:{},...o!==void 0?{kind:o}:{},...r!==void 0?{model:r}:{}})}}a(K,"handleReadiness");async function V(n){const e=n.params.provider,t=n.body;if(t===void 0||typeof t!="object"||typeof t.kind!="string")throw new i(400,"invalid_request","a credential `kind` is required");switch(t.kind){case"api_key":{const o=c("api_key","api_key",t.api_key);return await b(e,{type:"api_key",key:o}),{status:200,body:{provider:e,installed:!0,managed:!1}}}case"oauth":{if(l(e))throw new i(422,"unprocessable",`provider ${e} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const o=c("oauth","access_token",t.access_token),r=c("oauth","refresh_token",t.refresh_token),s=k("expires_at",t.expires_at),d=t.extra??{};await b(e,{type:"oauth",...d,access:o,refresh:r,expires:s});const w={provider:e,installed:!0,managed:!1};return typeof t.account_id=="string"&&t.account_id!==""&&(w.account_id=t.account_id),{status:200,body:w}}case"managed_account":{if(!l(e))throw new i(422,"unprocessable",`provider ${e} does not support managed accounts`);const o=typeof t.label=="string"&&t.label.trim()?t.label.trim():void 0;if(!o&&t.auto_label!==!0)throw new i(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof t.account_id=="string"&&t.account_id!==""?t.account_id:void 0,s=c("managed_account","access_token",t.access_token),d=c("managed_account","refresh_token",t.refresh_token),w=k("expires_at",t.expires_at),A=typeof t.last_rate_limited_at=="number"?t.last_rate_limited_at:Math.max(0,...(await m(e)).map(q=>q.lastRateLimitedAt));await P(e,o,{refresh:d,access:s,expires:w,...r?{accountId:r}:{},lastRateLimitedAt:A,autoLabel:t.auto_label===!0});const _={provider:e,installed:!0,managed:!0};return r&&(_.account_id=r),{status:200,body:_}}default:throw new i(400,"invalid_request",`unknown credential kind: ${String(t.kind)}`)}}a(V,"handleInstall");async function H(n){const e=n.params.provider;if(l(e)){const o=await T(e),r=await y(e);return{status:200,body:{provider:e,removed_accounts:o+(r?1:0)}}}const t=await y(e)?1:0;return{status:200,body:{provider:e,removed_accounts:t}}}a(H,"handleDelete");async function x(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);const t=h(n);for(const r of Object.keys(t))if(r!=="label"&&r!=="preferred")throw new i(400,"invalid_request",`unknown account field: ${r}`);if(t.label!==void 0&&typeof t.label!="string")throw new i(400,"invalid_request","`label` must be a string");if(t.preferred!==void 0&&t.preferred!==!0)throw new i(400,"invalid_request","`preferred` can only be true");if(t.label===void 0&&t.preferred===void 0)throw new i(400,"invalid_request","send `label` and/or `preferred`");let o=n.params.label;try{t.label!==void 0&&(await F(e,o,t.label),o=t.label.trim()),t.preferred&&await $(e,o)}catch(r){throw r instanceof Error&&/^Unknown .* subscription:/.test(r.message)?new i(404,"not_found",r.message):r instanceof I?new i(409,"conflict",r.message):r}return{status:200,body:await p(e)}}a(x,"handlePatchAccount");async function J(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);try{await j(e,n.params.label)}catch(t){throw t instanceof Error&&/^Unknown .* subscription:/.test(t.message)?new i(404,"not_found",t.message):t}return{status:200,body:await p(e)}}a(J,"handleDeleteAccount");function h(n){const e=n.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw new i(400,"invalid_request","request body must be a JSON object");return e}a(h,"bodyObject");async function Q(n){const e=h(n);return{status:200,body:await R({provider:e.provider,...e.redirect!==void 0?{redirect:e.redirect}:{},...e.label!==void 0?{label:e.label}:{}})}}a(Q,"handleFlowStart");async function z(n){const e=h(n);return{status:200,body:await C(n.params.flow_id,e.input)}}a(z,"handleFlowComplete");async function B(n){const e=await M(n.params.flow_id);if(!e)throw new g(400,"invalid_request","no sign-in has this flow_id","flow_id");const{jti:t,...o}=e;return{status:200,body:o}}a(B,"handleFlowCancel");async function W(n){for(const[d]of n.query)if(d!=="wait")throw u(`unknown model-auth flow query parameter: ${d}`);f(n,"wait");const e=G("model_auth.get",n.query),t=new AbortController;n.res.once("close",()=>t.abort());const o=await L(n.params.flow_id,e*1e3,t.signal);if(!o)throw new g(404,"not_found","no sign-in has this flow_id","flow_id");const{jti:r,...s}=o;return{status:200,body:s}}a(W,"handleFlowGet");const ie=[{method:"POST",pattern:"/v1/model-auth/flows",ownerOnly:!0,handler:Q},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/complete",ownerOnly:!0,handler:z},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/cancel",ownerOnly:!0,handler:B},{method:"GET",pattern:"/v1/model-auth/flows/:flow_id",ownerOnly:!0,handler:W},{method:"GET",pattern:"/v1/model-auth",handler:U},{method:"GET",pattern:"/v1/model-auth/readiness",handler:K},{method:"PUT",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:V},{method:"DELETE",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:H},{method:"DELETE",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:J},{method:"PATCH",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:x}];export{p as managedStatus,ie as modelAuthRoutes};
1
+ var O=Object.defineProperty;var o=(n,e)=>O(n,"name",{value:e,configurable:!0});import{deleteAuthCredential as y,readAuthCredentials as S,setAuthCredential as b,storedApiKey as E}from"../../../core/auth-file.js";import{ApiError as i}from"../../../api/index.js";import{RunError as g}from"../../../core/runs/operations.js";import{usage as u}from"../../../core/errors.js";import{modelAuthReadiness as D}from"../../../core/model-auth/readiness.js";import{MANAGED_PROVIDER_IDS as v,OPENAI_CHATGPT_PROVIDER_ID as I,DuplicateSubscriptionError as P,commitManagedLogin as $,isManagedProvider as l,promoteSubscription as T,readSubscriptionPool as m,removeAllManagedAccounts as j,removeManagedAccount as F,renameSubscription as M}from"../../../core/subscription-state.js";import{cancelModelAuthFlow as C,completeModelAuthFlow as R,startModelAuthFlow as L,waitModelAuthFlow as G}from"../../../core/model-auth/flows.js";import{waitSeconds as N}from"../long-poll-wait.js";function k(n,e){if(typeof e!="string"||e==="")throw new i(400,"invalid_request",`oauth credential requires \`${n}\``);const t=Date.parse(e);if(Number.isNaN(t))throw new i(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return t}o(k,"parseExpiry");function c(n,e,t){if(typeof t!="string"||t==="")throw new i(400,"invalid_request",`${n} credential requires \`${e}\``);return t}o(c,"requireField");function K(n,e=Date.now()){const t=Object.entries(n.modelCooldowns??{}).filter(([,a])=>a>e).map(([a,r])=>({family:a,rate_limited_until:new Date(r).toISOString()}));return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...t.length?{model_cooldowns:t}:{},...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}o(K,"toManagedAccountStatus");async function p(n){const e=(await m(n)).map(t=>K(t));return{provider:n,managed:!0,configured:e.length>0,accounts:e}}o(p,"managedStatus");function f(n,e){const t=n.query.getAll(e);if(t.length>1)throw u(`${e} must appear at most once`);return t[0]}o(f,"singleQueryValue");async function U(){const n=await S(),e=new Set;for(const r of v)r===I&&n[r]!==void 0&&(await m(r)).length===0&&e.add(r);const t=o(r=>e.has(r),"legacyApiKey"),a=await Promise.all(v.filter(r=>!t(r)).map(p));for(const[r,d]of Object.entries(n))l(r)&&!t(r)&&(d.type!=="api_key"||await E(r)===void 0)||d.type!=="api_key"&&d.type!=="oauth"||a.push({provider:r,managed:!1,configured:!0,kind:d.type});return{status:200,body:{providers:a}}}o(U,"handleList");async function V(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw u(`unknown model-auth readiness query parameter: ${s}`);const e=f(n,"profile"),t=f(n,"cwd"),a=f(n,"kind"),r=f(n,"model");if(a!==void 0&&a.trim()==="")throw u("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw u("model must be a non-empty string when provided");return{status:200,body:await D({...e!==void 0?{profile:e}:{},...t!==void 0?{cwd:t}:{},...a!==void 0?{kind:a}:{},...r!==void 0?{model:r}:{}})}}o(V,"handleReadiness");async function H(n){const e=n.params.provider,t=n.body;if(t===void 0||typeof t!="object"||typeof t.kind!="string")throw new i(400,"invalid_request","a credential `kind` is required");switch(t.kind){case"api_key":{const a=c("api_key","api_key",t.api_key);return await b(e,{type:"api_key",key:a}),{status:200,body:{provider:e,installed:!0,managed:!1}}}case"oauth":{if(l(e))throw new i(422,"unprocessable",`provider ${e} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const a=c("oauth","access_token",t.access_token),r=c("oauth","refresh_token",t.refresh_token),d=k("expires_at",t.expires_at),s=t.extra??{};await b(e,{type:"oauth",...s,access:a,refresh:r,expires:d});const w={provider:e,installed:!0,managed:!1};return typeof t.account_id=="string"&&t.account_id!==""&&(w.account_id=t.account_id),{status:200,body:w}}case"managed_account":{if(!l(e))throw new i(422,"unprocessable",`provider ${e} does not support managed accounts`);const a=typeof t.label=="string"&&t.label.trim()?t.label.trim():void 0;if(!a&&t.auto_label!==!0)throw new i(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof t.account_id=="string"&&t.account_id!==""?t.account_id:void 0,d=c("managed_account","access_token",t.access_token),s=c("managed_account","refresh_token",t.refresh_token),w=k("expires_at",t.expires_at),A=typeof t.last_rate_limited_at=="number"?t.last_rate_limited_at:Math.max(0,...(await m(e)).map(q=>q.lastRateLimitedAt));await $(e,a,{refresh:s,access:d,expires:w,...r?{accountId:r}:{},lastRateLimitedAt:A,autoLabel:t.auto_label===!0});const _={provider:e,installed:!0,managed:!0};return r&&(_.account_id=r),{status:200,body:_}}default:throw new i(400,"invalid_request",`unknown credential kind: ${String(t.kind)}`)}}o(H,"handleInstall");async function x(n){const e=n.params.provider;if(l(e)){const a=await j(e),r=await y(e);return{status:200,body:{provider:e,removed_accounts:a+(r?1:0)}}}const t=await y(e)?1:0;return{status:200,body:{provider:e,removed_accounts:t}}}o(x,"handleDelete");async function J(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);const t=h(n);for(const r of Object.keys(t))if(r!=="label"&&r!=="preferred")throw new i(400,"invalid_request",`unknown account field: ${r}`);if(t.label!==void 0&&typeof t.label!="string")throw new i(400,"invalid_request","`label` must be a string");if(t.preferred!==void 0&&t.preferred!==!0)throw new i(400,"invalid_request","`preferred` can only be true");if(t.label===void 0&&t.preferred===void 0)throw new i(400,"invalid_request","send `label` and/or `preferred`");let a=n.params.label;try{t.label!==void 0&&(await M(e,a,t.label),a=t.label.trim()),t.preferred&&await T(e,a)}catch(r){throw r instanceof Error&&/^Unknown .* subscription:/.test(r.message)?new i(404,"not_found",r.message):r instanceof P?new i(409,"conflict",r.message):r}return{status:200,body:await p(e)}}o(J,"handlePatchAccount");async function Q(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);try{await F(e,n.params.label)}catch(t){throw t instanceof Error&&/^Unknown .* subscription:/.test(t.message)?new i(404,"not_found",t.message):t}return{status:200,body:await p(e)}}o(Q,"handleDeleteAccount");function h(n){const e=n.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw new i(400,"invalid_request","request body must be a JSON object");return e}o(h,"bodyObject");async function z(n){const e=h(n);return{status:200,body:await L({provider:e.provider,...e.redirect!==void 0?{redirect:e.redirect}:{},...e.label!==void 0?{label:e.label}:{}})}}o(z,"handleFlowStart");async function B(n){const e=h(n);return{status:200,body:await R(n.params.flow_id,e.input)}}o(B,"handleFlowComplete");async function W(n){const e=await C(n.params.flow_id);if(!e)throw new g(400,"invalid_request","no sign-in has this flow_id","flow_id");const{jti:t,...a}=e;return{status:200,body:a}}o(W,"handleFlowCancel");async function X(n){for(const[s]of n.query)if(s!=="wait")throw u(`unknown model-auth flow query parameter: ${s}`);f(n,"wait");const e=N("model_auth.get",n.query),t=new AbortController;n.res.once("close",()=>t.abort());const a=await G(n.params.flow_id,e*1e3,t.signal);if(!a)throw new g(404,"not_found","no sign-in has this flow_id","flow_id");const{jti:r,...d}=a;return{status:200,body:d}}o(X,"handleFlowGet");const se=[{method:"POST",pattern:"/v1/model-auth/flows",ownerOnly:!0,handler:z},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/complete",ownerOnly:!0,handler:B},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/cancel",ownerOnly:!0,handler:W},{method:"GET",pattern:"/v1/model-auth/flows/:flow_id",ownerOnly:!0,handler:X},{method:"GET",pattern:"/v1/model-auth",handler:U},{method:"GET",pattern:"/v1/model-auth/readiness",handler:V},{method:"PUT",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:H},{method:"DELETE",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:x},{method:"DELETE",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:Q},{method:"PATCH",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:J}];export{p as managedStatus,se as modelAuthRoutes};
@@ -1 +1 @@
1
- var p=Object.defineProperty;var d=(n,r)=>p(n,"name",{value:r,configurable:!0});import{rmSync as g}from"node:fs";import{claimDaemonAction as h,dueDaemonActions as w,settleDaemonAction as _}from"../../core/canvas/daemon-actions.js";import{getNode as y}from"../../core/canvas/canvas.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{createPageRequest as I,getRequest as u}from"../../core/human/requests.js";import{synthesizedPageDocument as v,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as b}from"../../core/config.js";import{spawnChild as q}from"../../core/runtime/spawn.js";import{isStartRefusal as D}from"../../core/runtime/start-check.js";import{runDelivery as P}from"../delivery/run-delivery.js";import{deliveryDaemonInstanceId as m}from"./delivery-lane.js";import{cronBirthPlacement as S}from"../cron/armed-context.js";import{checkCronBirth as N}from"../cron/authority.js";async function o(n,r,e){await _(n.actionId,n.attempts,r,e,Date.now())}d(o,"settle");async function f(n,r,e){await o(n,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:e}})}d(f,"failed");async function z(n,r,e){const i=await y(e.nodeId);if(i!==null){if(i.frozen_at!==null||i.pi_session_id!==null||i.status==="idle"||i.status==="done"||i.status==="canceled"){await o(n,r,{state:"acknowledged"});return}await f(n,r,i.status==="dead"?`cron spawn ${e.nodeId} recorded a failed birth`:`cron spawn ${e.nodeId} found an incomplete birth`);return}const t=e.principal;if(t===void 0){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:e.cronId??null,action_id:n.actionId,reason:"grant_missing",stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:"grant_missing: the queued birth carries no cron principal"}});return}const a=await N(t,{kind:e.kind,cwd:e.cwd,profile:e.profile});if(!a.allowed){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:t.cron_id,action_id:n.actionId,grant_id:t.grant_id,reason:a.reason,stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:`${a.reason}: ${a.message}`}});return}try{await q({nodeId:e.nodeId,kind:e.kind,cwd:e.cwd,prompt:e.prompt,...await S(t,e.nodeId),readiness:"launch",profile:e.profile,isolated:e.isolated===!0,wakeOrigin:e.wakeOrigin}),await o(n,r,{state:"acknowledged"})}catch(s){if(D(s)){await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:s.message}});return}await f(n,r,`cron spawn ${e.nodeId} failed: ${s instanceof Error?s.message:String(s)}`),c.fresh(()=>l({level:"error",event:"delivery.cron_spawn_failed",node_id:e.nodeId,error:s,fields:{action_id:n.actionId}}))}}d(z,"deliverSpawn");function A(n,r){const e=k(v(n.title,n.summary,r,!1));try{return $({sourceFile:e.path,source:{sessionName:n.sessionName,...n.profileName===null?{}:{profileName:n.profileName}},productKinds:b(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(e.dir,{recursive:!0,force:!0})}}d(A,"preparedCronPage");async function C(n,r,e){if(await u(e.requestId)!==null){await o(n,r,{state:"acknowledged"});return}const i=n.body,t=typeof i?.stdout=="string"?i.stdout:null;if(t===null){await f(n,r,`cron human ${e.requestId} has no frozen stdout`);return}try{await I({request_id:e.requestId,prepared:A(e,t)}),await o(n,r,{state:"acknowledged"})}catch(a){await f(n,r,`cron human ${e.requestId} failed: ${a instanceof Error?a.message:String(a)}`)}}d(C,"deliverHuman");async function E(n,r){const e=n.adapter;if(n.body===null){await f(n,r,`daemon action ${n.actionId} has no body`);return}if(e.adapter==="subprocess"){let i=e.node_id;if(i===void 0){const t=n.idempotencyKey;if(!t.startsWith("human-action:"))throw new Error(`daemon action ${n.actionId} has no originating app`);const a=await u(t.slice(13));if(!a)throw new Error(`daemon action ${n.actionId} has no originating human request`);i=a.requester_node_id}await P({argv:e.argv,cwd:e.cwd,document:n.body,attempt:n.attempts,nodeId:i,...e.app?{app:e.app}:{}},async t=>await o(n,r,t));return}if(e.adapter==="cron_spawn"){await z(n,r,e);return}if(e.adapter==="cron_human"){await C(n,r,e);return}await f(n,r,`daemon action ${n.actionId} has unknown adapter ${String(e.adapter)}`)}d(E,"deliverAction");class V{static{d(this,"ActionLaneReconciler")}async run(r,e){if(!e.lifecycle.acceptsDetachedWork())return;let i;try{i=await w(r)}catch(t){c.fresh(()=>l({level:"error",event:"daemon_action.scan_failed",error:t}));return}for(const t of i)try{const a=await h(t.actionId,r,m);if(a===null)continue;e.lifecycle.registerDetached(E(a,m).catch(s=>{c.fresh(()=>l({level:"error",event:"daemon_action.failed",error:s,fields:{action_id:a.actionId}}))}))}catch(a){c.fresh(()=>l({level:"error",event:"daemon_action.claim_failed",error:a,fields:{action_id:t.actionId}}))}}}export{V as ActionLaneReconciler};
1
+ var p=Object.defineProperty;var d=(n,r)=>p(n,"name",{value:r,configurable:!0});import{rmSync as g}from"node:fs";import{claimDaemonAction as w,dueDaemonActions as h,settleDaemonAction as _}from"../../core/canvas/daemon-actions.js";import{getNode as y}from"../../core/canvas/canvas.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{createPageRequest as I,getRequest as u}from"../../core/human/requests.js";import{synthesizedPageDocument as v,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as b}from"../../core/config.js";import{spawnChild as q}from"../../core/runtime/spawn.js";import{isStartRefusal as D}from"../../core/runtime/start-check.js";import{runDelivery as P}from"../delivery/run-delivery.js";import{deliveryDaemonInstanceId as m}from"./delivery-lane.js";import{cronBirthPlacement as S}from"../cron/armed-context.js";import{asPerson as N}from"./node-lifecycle/node-person.js";import{checkCronBirth as z}from"../cron/authority.js";async function o(n,r,e){await _(n.actionId,n.attempts,r,e,Date.now())}d(o,"settle");async function f(n,r,e){await o(n,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:e}})}d(f,"failed");async function A(n,r,e){const i=await y(e.nodeId);if(i!==null){if(i.frozen_at!==null||i.pi_session_id!==null||i.status==="idle"||i.status==="done"||i.status==="canceled"){await o(n,r,{state:"acknowledged"});return}await f(n,r,i.status==="dead"?`cron spawn ${e.nodeId} recorded a failed birth`:`cron spawn ${e.nodeId} found an incomplete birth`);return}const t=e.principal;if(t===void 0){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:e.cronId??null,action_id:n.actionId,reason:"grant_missing",stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:"grant_missing: the queued birth carries no cron principal"}});return}const a=await z(t,{kind:e.kind,cwd:e.cwd,profile:e.profile});if(!a.allowed){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:t.cron_id,action_id:n.actionId,grant_id:t.grant_id,reason:a.reason,stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:`${a.reason}: ${a.message}`}});return}try{await N(t.sub,async()=>await q({nodeId:e.nodeId,kind:e.kind,cwd:e.cwd,prompt:e.prompt,...await S(t,e.nodeId),readiness:"launch",profile:e.profile,isolated:e.isolated===!0,wakeOrigin:e.wakeOrigin})),await o(n,r,{state:"acknowledged"})}catch(s){if(D(s)){await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:s.message}});return}await f(n,r,`cron spawn ${e.nodeId} failed: ${s instanceof Error?s.message:String(s)}`),c.fresh(()=>l({level:"error",event:"delivery.cron_spawn_failed",node_id:e.nodeId,error:s,fields:{action_id:n.actionId}}))}}d(A,"deliverSpawn");function C(n,r){const e=k(v(n.title,n.summary,r,!1));try{return $({sourceFile:e.path,source:{sessionName:n.sessionName,...n.profileName===null?{}:{profileName:n.profileName}},productKinds:b(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(e.dir,{recursive:!0,force:!0})}}d(C,"preparedCronPage");async function E(n,r,e){if(await u(e.requestId)!==null){await o(n,r,{state:"acknowledged"});return}const i=n.body,t=typeof i?.stdout=="string"?i.stdout:null;if(t===null){await f(n,r,`cron human ${e.requestId} has no frozen stdout`);return}try{await I({request_id:e.requestId,prepared:C(e,t)}),await o(n,r,{state:"acknowledged"})}catch(a){await f(n,r,`cron human ${e.requestId} failed: ${a instanceof Error?a.message:String(a)}`)}}d(E,"deliverHuman");async function R(n,r){const e=n.adapter;if(n.body===null){await f(n,r,`daemon action ${n.actionId} has no body`);return}if(e.adapter==="subprocess"){let i=e.node_id;if(i===void 0){const t=n.idempotencyKey;if(!t.startsWith("human-action:"))throw new Error(`daemon action ${n.actionId} has no originating app`);const a=await u(t.slice(13));if(!a)throw new Error(`daemon action ${n.actionId} has no originating human request`);i=a.requester_node_id}await P({argv:e.argv,cwd:e.cwd,document:n.body,attempt:n.attempts,nodeId:i,...e.app?{app:e.app}:{}},async t=>await o(n,r,t));return}if(e.adapter==="cron_spawn"){await A(n,r,e);return}if(e.adapter==="cron_human"){await E(n,r,e);return}await f(n,r,`daemon action ${n.actionId} has unknown adapter ${String(e.adapter)}`)}d(R,"deliverAction");class Y{static{d(this,"ActionLaneReconciler")}async run(r,e){if(!e.lifecycle.acceptsDetachedWork())return;let i;try{i=await h(r)}catch(t){c.fresh(()=>l({level:"error",event:"daemon_action.scan_failed",error:t}));return}for(const t of i)try{const a=await w(t.actionId,r,m);if(a===null)continue;e.lifecycle.registerDetached(R(a,m).catch(s=>{c.fresh(()=>l({level:"error",event:"daemon_action.failed",error:s,fields:{action_id:a.actionId}}))}))}catch(a){c.fresh(()=>l({level:"error",event:"daemon_action.claim_failed",error:a,fields:{action_id:t.actionId}}))}}}export{Y as ActionLaneReconciler};
@@ -1 +1 @@
1
- var g=Object.defineProperty;var s=(i,e)=>g(i,"name",{value:e,configurable:!0});import{clearFrozen as p,getNode as h,getRow as y}from"../../../core/canvas/index.js";import{openDb as c}from"../../../core/canvas/db.js";import{fullName as k}from"../../../core/canvas/labels.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as S}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as D}from"../../../core/canvas/deliveries.js";import{publishNotice as N}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{isStartRefusal as E}from"../../../core/runtime/start-check.js";import{EnvironmentImagePending as R}from"./remote-wake.js";import{commitReopenResident as z}from"../../../core/runtime/reopen.js";import{reviveNode as m}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as T}from"../../../core/canvas/recovery.js";import{mapAsync as L}from"../../../core/async-array.js";const f=6,C=10*6e4,b=2e4;async function I(i){const e=await(await c()).prepare("SELECT idle_release_attempts, idle_release_last_attempt_at, idle_release_acked_count FROM nodes WHERE node_id = ?").get(i);return{attempts:Number(e?.idle_release_attempts??0),acknowledgedCount:Number(e?.idle_release_acked_count??0),lastAttempt:e?.idle_release_last_attempt_at==null?void 0:Date.parse(e.idle_release_last_attempt_at)}}s(I,"readEpisode");async function M(i,e,a,t,r){const n=await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ? AND idle_release_attempts = ?").run(a,new Date(r).toISOString(),t,i,e);return Number(n.changes)===1}s(M,"claimAttempt");async function O(i,e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ?").run(e.attempts,e.lastAttempt===void 0?null:new Date(e.lastAttempt).toISOString(),e.acknowledgedCount,i)}s(O,"writeEpisode");function P(i,e){if(e)return 2;const a=i.launched_at;if(a==null)return 1;const t=i.last_settled_at;return t==null?2:Date.parse(t)>Date.parse(a)?1:2}s(P,"thawTier");function U(i,e){const a=i.row.frozen_at,t=e.row.frozen_at;return a==null?t==null?0:1:t==null?-1:Date.parse(a)-Date.parse(t)}s(U,"compareThaw");class te{static{s(this,"FreezeLaneReconciler")}async endEpisode(e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = 0, idle_release_last_attempt_at = NULL, idle_release_acked_count = 0 WHERE node_id = ? AND (idle_release_attempts <> 0 OR idle_release_last_attempt_at IS NOT NULL OR idle_release_acked_count <> 0)").run(e)}async run(e,a){const t=await L(a.candidates,async n=>({...n,tier:P(n.row,await v(n.row.node_id))}));t.sort(U);const r={stalled:0,waitingOnMail:0};for(const n of t)await S.fresh(()=>this.enact(e,n,a.fleet))==="frozen"&&(n.tier===1?r.stalled+=1:r.waitingOnMail+=1);return r}async enact(e,a,t){const r=a.row.node_id;try{return a.enact==="thaw"?await this.enactThaw(a.row):a.enact==="reopen"?await this.enactReopen(a.row):a.enact==="idle-release"?await this.enactIdleRelease(e,a.row):(await t.applyDeadRowPolicy(r),await t.has(r)?"launched":(await y(r))?.frozen_at!=null?"frozen":"skipped")}catch(n){return _({level:"error",event:"node.lifecycle.enact_failed",...d(r)?{node_id:r}:{},error:n,fields:{...d(r)?{}:{affected_node_id:r},enact:a.enact}}),"skipped"}}async enactReopen(e){await z(e.node_id);try{return(await m(e.node_id,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":"launched"}catch(a){if(E(a)||a instanceof R)return await this.settleRefusedStart(e.node_id,a,"reopen");throw a}}async settleRefusedStart(e,a,t){return await u(e,"release"),await p(e),_({level:"warn",event:"node.start.refused",node_id:e,error:a,fields:{enact:t}}),"skipped"}async enactThaw(e){const a=(await T(e.node_id))?.interrupted===!0;if(!a&&e.lifecycle==="resident"&&(await h(e.node_id))?.pi_session_id!=null&&!await v(e.node_id))return await u(e.node_id,"release"),await p(e.node_id),"skipped";try{return(await m(e.node_id,{resume:!0,capacity:"freeze",recovery:!0,...a?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(t){if(E(t)||t instanceof R)return await this.settleRefusedStart(e.node_id,t,"thaw");const r=await h(e.node_id);throw r!==null&&(r.status==="active"||r.status==="idle")&&(await u(e.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t instanceof Error?t.message:String(t)}}}),await p(e.node_id)),t}}async enactIdleRelease(e,a){const t=a.node_id,r=await D(t),n=await I(t),l=n.attempts===0||n.acknowledgedCount!==r,o=l?0:n.attempts;if(o>=f)return await this.endEpisode(t),_({level:"warn",event:"broker.idle_release.exhausted",...d(t)?{node_id:t}:{},fields:{...d(t)?{}:{affected_node_id:t},attempts:o,max_attempts:f}}),await u(t,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:o}}}),await N(t,"notice.crash",`Child crashed \u2014 ${k(a)} (${t}) failed to relaunch after ${o} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${t}\`.`,{reason:"child-crashed",child:t}),"skipped";const w=l?void 0:n.lastAttempt,A=Math.min(b*2**o,C);return w!==void 0&&e-w<A||!await M(t,n.attempts,o+1,r,e)?"skipped":(await m(t,{resume:!0,capacity:"freeze"})).outcome==="frozen"?(await O(t,{attempts:l?0:o,lastAttempt:l?void 0:n.lastAttempt,acknowledgedCount:r}),"frozen"):(_({level:"info",event:"broker.revive.idle_release",...d(t)?{node_id:t}:{},attempt:o+1,fields:{...d(t)?{}:{affected_node_id:t},attempts:o+1,max_attempts:f}}),"launched")}}export{te as FreezeLaneReconciler,U as compareThaw,P as thawTier};
1
+ var g=Object.defineProperty;var s=(i,e)=>g(i,"name",{value:e,configurable:!0});import{clearFrozen as p,getNode as h,getRow as y}from"../../../core/canvas/index.js";import{openDb as c}from"../../../core/canvas/db.js";import{fullName as k}from"../../../core/canvas/labels.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as S}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as N}from"../../../core/canvas/deliveries.js";import{publishNotice as D}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{isStartRefusal as E}from"../../../core/runtime/start-check.js";import{EnvironmentImagePending as R}from"./remote-wake.js";import{asNodePerson as z}from"./node-person.js";import{commitReopenResident as T}from"../../../core/runtime/reopen.js";import{reviveNode as m}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as L}from"../../../core/canvas/recovery.js";import{mapAsync as C}from"../../../core/async-array.js";const f=6,b=10*6e4,I=2e4;async function M(i){const e=await(await c()).prepare("SELECT idle_release_attempts, idle_release_last_attempt_at, idle_release_acked_count FROM nodes WHERE node_id = ?").get(i);return{attempts:Number(e?.idle_release_attempts??0),acknowledgedCount:Number(e?.idle_release_acked_count??0),lastAttempt:e?.idle_release_last_attempt_at==null?void 0:Date.parse(e.idle_release_last_attempt_at)}}s(M,"readEpisode");async function O(i,e,a,t,r){const n=await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ? AND idle_release_attempts = ?").run(a,new Date(r).toISOString(),t,i,e);return Number(n.changes)===1}s(O,"claimAttempt");async function P(i,e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ?").run(e.attempts,e.lastAttempt===void 0?null:new Date(e.lastAttempt).toISOString(),e.acknowledgedCount,i)}s(P,"writeEpisode");function U(i,e){if(e)return 2;const a=i.launched_at;if(a==null)return 1;const t=i.last_settled_at;return t==null?2:Date.parse(t)>Date.parse(a)?1:2}s(U,"thawTier");function x(i,e){const a=i.row.frozen_at,t=e.row.frozen_at;return a==null?t==null?0:1:t==null?-1:Date.parse(a)-Date.parse(t)}s(x,"compareThaw");class re{static{s(this,"FreezeLaneReconciler")}async endEpisode(e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = 0, idle_release_last_attempt_at = NULL, idle_release_acked_count = 0 WHERE node_id = ? AND (idle_release_attempts <> 0 OR idle_release_last_attempt_at IS NOT NULL OR idle_release_acked_count <> 0)").run(e)}async run(e,a){const t=await C(a.candidates,async n=>({...n,tier:U(n.row,await v(n.row.node_id))}));t.sort(x);const r={stalled:0,waitingOnMail:0};for(const n of t)await S.fresh(()=>z(n.row,()=>this.enact(e,n,a.fleet)))==="frozen"&&(n.tier===1?r.stalled+=1:r.waitingOnMail+=1);return r}async enact(e,a,t){const r=a.row.node_id;try{return a.enact==="thaw"?await this.enactThaw(a.row):a.enact==="reopen"?await this.enactReopen(a.row):a.enact==="idle-release"?await this.enactIdleRelease(e,a.row):(await t.applyDeadRowPolicy(r),await t.has(r)?"launched":(await y(r))?.frozen_at!=null?"frozen":"skipped")}catch(n){return _({level:"error",event:"node.lifecycle.enact_failed",...d(r)?{node_id:r}:{},error:n,fields:{...d(r)?{}:{affected_node_id:r},enact:a.enact}}),"skipped"}}async enactReopen(e){await T(e.node_id);try{return(await m(e.node_id,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":"launched"}catch(a){if(E(a)||a instanceof R)return await this.settleRefusedStart(e.node_id,a,"reopen");throw a}}async settleRefusedStart(e,a,t){return await u(e,"release"),await p(e),_({level:"warn",event:"node.start.refused",node_id:e,error:a,fields:{enact:t}}),"skipped"}async enactThaw(e){const a=(await L(e.node_id))?.interrupted===!0;if(!a&&e.lifecycle==="resident"&&(await h(e.node_id))?.pi_session_id!=null&&!await v(e.node_id))return await u(e.node_id,"release"),await p(e.node_id),"skipped";try{return(await m(e.node_id,{resume:!0,capacity:"freeze",recovery:!0,...a?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(t){if(E(t)||t instanceof R)return await this.settleRefusedStart(e.node_id,t,"thaw");const r=await h(e.node_id);throw r!==null&&(r.status==="active"||r.status==="idle")&&(await u(e.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t instanceof Error?t.message:String(t)}}}),await p(e.node_id)),t}}async enactIdleRelease(e,a){const t=a.node_id,r=await N(t),n=await M(t),l=n.attempts===0||n.acknowledgedCount!==r,o=l?0:n.attempts;if(o>=f)return await this.endEpisode(t),_({level:"warn",event:"broker.idle_release.exhausted",...d(t)?{node_id:t}:{},fields:{...d(t)?{}:{affected_node_id:t},attempts:o,max_attempts:f}}),await u(t,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:o}}}),await D(t,"notice.crash",`Child crashed \u2014 ${k(a)} (${t}) failed to relaunch after ${o} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${t}\`.`,{reason:"child-crashed",child:t}),"skipped";const w=l?void 0:n.lastAttempt,A=Math.min(I*2**o,b);return w!==void 0&&e-w<A||!await O(t,n.attempts,o+1,r,e)?"skipped":(await m(t,{resume:!0,capacity:"freeze"})).outcome==="frozen"?(await P(t,{attempts:l?0:o,lastAttempt:l?void 0:n.lastAttempt,acknowledgedCount:r}),"frozen"):(_({level:"info",event:"broker.revive.idle_release",...d(t)?{node_id:t}:{},attempt:o+1,fields:{...d(t)?{}:{affected_node_id:t},attempts:o+1,max_attempts:f}}),"launched")}}export{re as FreezeLaneReconciler,x as compareThaw,U as thawTier};
@@ -0,0 +1 @@
1
+ export declare function recordLaunchFailure(executionId: string, error: unknown): Promise<void>;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var n=(i,e)=>s(i,"name",{value:e,configurable:!0});import{openDb as t}from"../../../core/canvas/db.js";import{exitDiagnosticJson as o}from"../../../core/canvas/recovery.js";async function r(i,e){const a=e instanceof Error?`${e.name}: ${e.message}`:String(e);await(await t()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(o({launch_failure:{message:a.slice(0,2e3)}}),i)}n(r,"recordLaunchFailure");export{r as recordLaunchFailure};
@@ -0,0 +1,9 @@
1
+ import type { NodeRow } from '../../../core/canvas/types.js';
2
+ /** A cloud-role node with no `sub` whose profile names no person: no one may be borrowed for it, so the lane leaves it untouched. */
3
+ export declare class NodePersonUnresolvedError extends Error {
4
+ readonly code = "node_person_unresolved";
5
+ constructor(nodeId: string);
6
+ }
7
+ /** Run `fn` as `sub` with that person's settings loaded, as an API request does from its token. */
8
+ export declare function asPerson<T>(sub: string, fn: () => Promise<T>): Promise<T>;
9
+ export declare function asNodePerson<T>(row: Pick<NodeRow, 'node_id' | 'sub' | 'profile_id'>, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var r=(e,n)=>i(e,"name",{value:n,configurable:!0});import{openDb as s}from"../../../core/canvas/db.js";import{isCloudRole as t,runAsPerson as a}from"../../../core/canvas/person.js";import{loadPersonSettings as u}from"../../../core/scoped-state/person-rows.js";import{personHasSnapshot as d}from"../../../core/scoped-state/person-store.js";class p extends Error{static{r(this,"NodePersonUnresolvedError")}code="node_person_unresolved";constructor(n){super(`node ${n} has no person: its row carries no sub and its profile names none`),this.name="NodePersonUnresolvedError"}}async function l(e){if(e.sub!=null&&e.sub!=="")return e.sub;if(!t())return null;const n=e.profile_id==null?void 0:await(await s()).prepare("SELECT person FROM profiles WHERE id = ?").get(e.profile_id);if(n===void 0||n.person==="")throw new p(e.node_id);return await(await s()).prepare("UPDATE nodes SET sub = ? WHERE node_id = ? AND (sub IS NULL OR sub = '')").run(n.person,e.node_id),n.person}r(l,"personOf");async function f(e,n){return await a(e,async()=>(d()||await u(e),await n()))}r(f,"asPerson");async function P(e,n){const o=await l(e);return o===null?await n():await f(o,n)}r(P,"asNodePerson");export{p as NodePersonUnresolvedError,P as asNodePerson,f as asPerson};
@@ -7,8 +7,6 @@ export declare const LAUNCH_DEADLINE_MS: number;
7
7
  export declare const LAUNCH_LOST_GRACE_MS = 120000;
8
8
  /** The release the control plane runs, which is the release a wake names. */
9
9
  export declare const acceptedRelease: () => string;
10
- /** The Blaxel environment the node's profile points at, or null when it runs on a machine. Reads rows only, so it is safe before any environment is registered. */
11
- export declare function blaxelEnvironmentOf(profileId: string | null): Promise<string | null>;
12
10
  /** Step 2: the `funding bill` check. A refusal writes `nodes.spend_refusal` and one refused `sandbox` row per node, limit and month,
13
11
  * then throws `402 cap_exhausted`; no execution row is written and no runner is called. A pass clears `spend_refusal`. */
14
12
  export declare function checkBilledWake(meta: NodeMeta): Promise<void>;
@@ -1 +1 @@
1
- var p=Object.defineProperty;var a=(e,t)=>p(e,"name",{value:t,configurable:!0});import{liveExecutionForNode as m,endExecution as d,recordExecutionAwake as w,endLaunchingExecution as s,requestExecutionStop as h}from"../../../core/canvas/executions.js";import{openDb as c}from"../../../core/canvas/db.js";import{emitEvent as u}from"../../../core/events/emit.js";import{findRefusal as _,refusalError as x,refusedMark as E,writeCharge as g}from"../../../core/ledger/index.js";import{transition as f}from"../../../core/runtime/lifecycle.js";import{runnerForExecution as l}from"../../../core/runtime/runner/index.js";import{startCandidateOf as b}from"../../../core/runtime/start-check.js";import{settleSandboxBeforeWake as v}from"../ledger-sandbox.js";import{crtrVersion as k}from"../../../shared/crtr-version.js";import{resolveEnvironmentImage as I}from"../recipe-image.js";const S=45*6e4,y=12e4,N=a(()=>k(),"acceptedRelease");async function j(e){return e===null?null:(await(await c()).prepare("SELECT e.object AS object FROM profiles p JOIN environments e ON e.object = p.environment_id WHERE p.id = ? AND e.kind = 'blaxel'").get(e))?.object??null}a(j,"blaxelEnvironmentOf");async function F(e){const t=await b(e);if(t===null)return;const n={scope:"call",payer:t.payer,funding:"bill",sub:t.sub,grantee:t.grantee,provider:"blaxel"},r=await _(n),o=await c();if(r===null){await o.prepare("UPDATE nodes SET spend_refusal = NULL WHERE node_id = ? AND spend_refusal IS NOT NULL").run(e.node_id);return}throw await o.prepare("UPDATE nodes SET spend_refusal = ? WHERE node_id = ?").run(JSON.stringify({limit:r.limit.id,usd:r.usd,reset_at:r.reset_at,at:new Date().toISOString()}),e.node_id),await g({id:`refused:sandbox:${e.node_id}:${r.limit.id}:${r.month}`,kind:"sandbox",what:"wake",usd:null,payer:n.payer,funding:"bill",sub:n.sub,grantee:n.grantee,node:e.node_id,run:e.run_id??null,provider:"blaxel",refused:E(r)}),x(r)}a(F,"checkBilledWake");class M extends Error{static{a(this,"EnvironmentImagePending")}environmentId;imageError;constructor(t,n){super(`environment ${t} has no built image yet${n===null?"":` (${n})`}; the wake waits for the build.`),this.environmentId=t,this.imageError=n,this.name="EnvironmentImagePending"}}async function P(e){return await I(e)}a(P,"imageForWake");async function B(e){return e.release!==N()&&await h(e.nodeId,{afterTurn:!1,reason:"release"}),await l(e.runner).wake(e)==="no_broker"?(await d(e.executionId,{reason:"lost"}),"lost"):(await v(e.executionId,Date.now()),await w(e.executionId),"woken")}a(B,"wakeResident");async function G(e){const t=await l(e.runner).status(e);if(t.state!=="gone"&&t.state!=="failed")return!1;const n=await d(e.executionId,{reason:"lost"});return n&&u({level:"warn",event:"execution.lost",node_id:e.nodeId}),n}a(G,"endRemoteExecutionIfGone");async function J(e,t){const n=await m(e);if(n===null||n.state!=="launching"||n.runner==="process")return;const r=l(n.runner),o=t-Date.parse(n.startedAt),i=await r.status(n);if(i.state!=="unknown"){if(i.state==="running"){if(o<=S||!await s(n.executionId,{reason:"launch_timeout"}))return;await r.stop(n,{reason:"launch_timeout"}),await f(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:"the sandbox launch did not report within the launch deadline"}}}),u({level:"warn",event:"execution.launch_timeout",node_id:e});return}if(i.state==="failed"){if(!await s(n.executionId,{reason:"launch_failed"}))return;await f(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:`the sandbox start script failed: ${i.reason}`}}});return}if(o>y){if(!await s(n.executionId,{reason:"launch_lost"}))return;u({level:"warn",event:"execution.launch_lost",node_id:e})}}}a(J,"recoverLaunching");export{M as EnvironmentImagePending,S as LAUNCH_DEADLINE_MS,y as LAUNCH_LOST_GRACE_MS,N as acceptedRelease,j as blaxelEnvironmentOf,F as checkBilledWake,G as endRemoteExecutionIfGone,P as imageForWake,J as recoverLaunching,B as wakeResident};
1
+ var f=Object.defineProperty;var a=(e,n)=>f(e,"name",{value:n,configurable:!0});import{liveExecutionForNode as m,endExecution as l,recordExecutionAwake as p,endLaunchingExecution as s,requestExecutionStop as w}from"../../../core/canvas/executions.js";import{openDb as h}from"../../../core/canvas/db.js";import{emitEvent as u}from"../../../core/events/emit.js";import{findRefusal as _,refusalError as x,refusedMark as g,writeCharge as E}from"../../../core/ledger/index.js";import{transition as c}from"../../../core/runtime/lifecycle.js";import{runnerForExecution as d}from"../../../core/runtime/runner/index.js";import{startCandidateOf as v}from"../../../core/runtime/start-check.js";import{settleSandboxBeforeWake as b}from"../ledger-sandbox.js";import{crtrVersion as k}from"../../../shared/crtr-version.js";import{resolveEnvironmentImage as I}from"../recipe-image.js";const y=45*6e4,S=12e4,L=a(()=>k(),"acceptedRelease");async function P(e){const n=await v(e);if(n===null)return;const t={scope:"call",payer:n.payer,funding:"bill",sub:n.sub,grantee:n.grantee,provider:"blaxel"},r=await _(t),o=await h();if(r===null){await o.prepare("UPDATE nodes SET spend_refusal = NULL WHERE node_id = ? AND spend_refusal IS NOT NULL").run(e.node_id);return}throw await o.prepare("UPDATE nodes SET spend_refusal = ? WHERE node_id = ?").run(JSON.stringify({limit:r.limit.id,usd:r.usd,reset_at:r.reset_at,at:new Date().toISOString()}),e.node_id),await E({id:`refused:sandbox:${e.node_id}:${r.limit.id}:${r.month}`,kind:"sandbox",what:"wake",usd:null,payer:t.payer,funding:"bill",sub:t.sub,grantee:t.grantee,node:e.node_id,run:e.run_id??null,provider:"blaxel",refused:g(r)}),x(r)}a(P,"checkBilledWake");class F extends Error{static{a(this,"EnvironmentImagePending")}environmentId;imageError;constructor(n,t){super(`environment ${n} has no built image yet${t===null?"":` (${t})`}; the wake waits for the build.`),this.environmentId=n,this.imageError=t,this.name="EnvironmentImagePending"}}async function M(e){return await I(e)}a(M,"imageForWake");async function B(e){return e.release!==L()&&await w(e.nodeId,{afterTurn:!1,reason:"release"}),await d(e.runner).wake(e)==="no_broker"?(await l(e.executionId,{reason:"lost"}),"lost"):(await b(e.executionId,Date.now()),await p(e.executionId),"woken")}a(B,"wakeResident");async function G(e){const n=await d(e.runner).status(e);if(n.state!=="gone"&&n.state!=="failed")return!1;const t=await l(e.executionId,{reason:"lost"});return t&&u({level:"warn",event:"execution.lost",node_id:e.nodeId}),t}a(G,"endRemoteExecutionIfGone");async function q(e,n){const t=await m(e);if(t===null||t.state!=="launching"||t.runner==="process")return;const r=d(t.runner),o=n-Date.parse(t.startedAt),i=await r.status(t);if(i.state!=="unknown"){if(i.state==="running"){if(o<=y||!await s(t.executionId,{reason:"launch_timeout"}))return;await r.stop(t,{reason:"launch_timeout"}),await c(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:"the sandbox launch did not report within the launch deadline"}}}),u({level:"warn",event:"execution.launch_timeout",node_id:e});return}if(i.state==="failed"){if(!await s(t.executionId,{reason:"launch_failed"}))return;await c(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:`the sandbox start script failed: ${i.reason}`}}});return}if(o>S){if(!await s(t.executionId,{reason:"launch_lost"}))return;u({level:"warn",event:"execution.launch_lost",node_id:e})}}}a(q,"recoverLaunching");export{F as EnvironmentImagePending,y as LAUNCH_DEADLINE_MS,S as LAUNCH_LOST_GRACE_MS,L as acceptedRelease,P as checkBilledWake,G as endRemoteExecutionIfGone,M as imageForWake,q as recoverLaunching,B as wakeResident};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var l=(r,t)=>k(r,"name",{value:t,configurable:!0});import{clearFrozen as m,endLiveExecution as h,getNode as R}from"../../../core/canvas/index.js";import{isSafeNodeId as b}from"../../../core/canvas/paths.js";import{recordedPidLiveness as _}from"../../../core/canvas/pid.js";import{hasObservedExit as E,hasAbsorbedProfilePauseStop as L}from"../../../core/canvas/executions.js";import{emitEvent as y}from"../../../core/events/emit.js";import{operationIdContext as z}from"../../../core/events/operation-id.js";import{readInterruptedTurn as I}from"../../../core/canvas/recovery.js";import{isProfilePaused as d}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as v}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as p}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as g,isParkedResident as w}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as M}from"../../fleet.js";import{applyParkEvent as N,hasPendingWake as F,parkEvent as x}from"../live-obligation.js";import{FreezeLaneReconciler as A}from"./freeze-lane.js";import{isInBackoff as P}from"./respawn-policy.js";import{handleTerminatingRow as C}from"./terminating.js";import{wantsExecution as D}from"./wants-execution.js";import{enactRequestedStops as S}from"./requested-stops.js";import{endRemoteExecutionIfGone as T,recoverLaunching as G,wakeResident as H}from"./remote-wake.js";import{liveExecutionForNode as U}from"../../../core/canvas/executions.js";function W(r){return r.status==="done"||r.status==="canceled"||r.status==="dead"}l(W,"isTerminal");const q=12e4;function B(r,t){const e=Math.max(...[r.created,r.launched_at].map(a=>a==null?0:Date.parse(a)||0));return e>0&&t-e<q}l(B,"isLaunchInFlight");class pe{static{l(this,"NodeLifecycleReconciler")}freezeLane=new A;async run(t,e){const a=[];await S(t);for(const n of e.rows)await z.fresh(async()=>{try{await this.classifyRow(t,n,e,a)}catch(i){const s=n.node_id;y({level:"error",event:"node.lifecycle.classify_failed",...b(s)?{node_id:s}:{fields:{affected_node_id:s}},error:i})}});return this.freezeLane.run(t,{fleet:e.fleet,candidates:a})}async classifyRow(t,e,a,n){const i=e.node_id;if(W(e)){if(C(e,await a.fleet.has(i)))return;if(w(e)&&!await a.fleet.has(i)&&!d(e.profile_id)&&!await v(i)&&!P(e,t)&&await p(i)){n.push({row:e,enact:"reopen"});return}e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead"&&await h(i,{reason:"observed-dead"}),e.frozen_at!=null&&(e.final_report!=null||e.status==="dead"?await m(i):n.push({row:e,enact:"thaw"}));return}if(await a.fleet.has(i)){const f=await U(i);if(f?.runner==="blaxel"&&f.state==="running"&&!d(e.profile_id)&&await p(i)){if(await H(f)==="lost")return}else f?.runner==="blaxel"&&f.state==="running"&&await T(f);if(await a.fleet.has(i)){d(e.profile_id)?await a.fleet.interruptForProfilePause(i):await this.thawMark(e);return}}if(await G(i,t),d(e.profile_id)){await this.freezeLane.endEpisode(i);return}if(await v(i))return;const s=e.pi_pid==null&&await E(i),u=e.pi_pid==null&&!s&&await L(i),c=s||u||e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead";if(c&&!await a.fleet.hasProfilePauseInterruption(i)&&await h(i,{reason:"observed-dead"}),!await D(e)){await this.thawMark(e),await this.settleParked(e);return}if(P(e,t))return;if(e.status==="idle"&&g(e)&&await p(i)){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null&&(!s||e.frozen_at!=null)&&!u){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){n.push({row:e,enact:"thaw"});return}if(await a.fleet.isClaimed(i)||B(e,t))return;y({level:"warn",event:"node.lifecycle.stranded_launch",node_id:i}),n.push({row:e,enact:"thaw"});return}if(!c)return;const o=M(await R(i),(await I(i))?.interrupted===!0,await F(i));if(o==="respawn-fresh"||o==="respawn-cycle"||o==="respawn-resume"){n.push({row:e,enact:"policy"});return}await a.fleet.applyDeadRowPolicy(i),await this.thawMark(e)}async thawMark(t){t.frozen_at!=null&&await m(t.node_id)}async settleParked(t){if(t.status!=="idle")return;await this.freezeLane.endEpisode(t.node_id);const e=await x(t.node_id,t.lifecycle);e!=="release"&&await N(t.node_id,e)}}export{q as LAUNCH_GRACE_MS,pe as NodeLifecycleReconciler,B as isLaunchInFlight};
1
+ var E=Object.defineProperty;var l=(r,t)=>E(r,"name",{value:t,configurable:!0});import{clearFrozen as m,endLiveExecution as h,getNode as R}from"../../../core/canvas/index.js";import{isSafeNodeId as b}from"../../../core/canvas/paths.js";import{recordedPidLiveness as _}from"../../../core/canvas/pid.js";import{hasObservedExit as L,hasAbsorbedProfilePauseStop as z}from"../../../core/canvas/executions.js";import{emitEvent as y}from"../../../core/events/emit.js";import{operationIdContext as I}from"../../../core/events/operation-id.js";import{readInterruptedTurn as g}from"../../../core/canvas/recovery.js";import{isProfilePaused as d}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as v}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as p}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as w,isParkedResident as N}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as M}from"../../fleet.js";import{applyParkEvent as F,hasPendingWake as x,parkEvent as A}from"../live-obligation.js";import{FreezeLaneReconciler as C}from"./freeze-lane.js";import{isInBackoff as P}from"./respawn-policy.js";import{asNodePerson as D,NodePersonUnresolvedError as k}from"./node-person.js";import{handleTerminatingRow as S}from"./terminating.js";import{wantsExecution as T}from"./wants-execution.js";import{enactRequestedStops as U}from"./requested-stops.js";import{endRemoteExecutionIfGone as G,recoverLaunching as H,wakeResident as W}from"./remote-wake.js";import{liveExecutionForNode as q}from"../../../core/canvas/executions.js";function B(r){return r.status==="done"||r.status==="canceled"||r.status==="dead"}l(B,"isTerminal");const O=12e4;function j(r,t){const e=Math.max(...[r.created,r.launched_at].map(a=>a==null?0:Date.parse(a)||0));return e>0&&t-e<O}l(j,"isLaunchInFlight");class me{static{l(this,"NodeLifecycleReconciler")}freezeLane=new C;async run(t,e){const a=[];await U(t);for(const n of e.rows)await I.fresh(async()=>{try{await D(n,()=>this.classifyRow(t,n,e,a))}catch(i){const s=n.node_id;y({level:i instanceof k?"warn":"error",event:i instanceof k?"node.lifecycle.person_unresolved":"node.lifecycle.classify_failed",...b(s)?{node_id:s}:{fields:{affected_node_id:s}},error:i})}});return this.freezeLane.run(t,{fleet:e.fleet,candidates:a})}async classifyRow(t,e,a,n){const i=e.node_id;if(B(e)){if(S(e,await a.fleet.has(i)))return;if(N(e)&&!await a.fleet.has(i)&&!d(e.profile_id)&&!await v(i)&&!P(e,t)&&await p(i)){n.push({row:e,enact:"reopen"});return}e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead"&&await h(i,{reason:"observed-dead"}),e.frozen_at!=null&&(e.final_report!=null||e.status==="dead"?await m(i):n.push({row:e,enact:"thaw"}));return}if(await a.fleet.has(i)){const f=await q(i);if(f?.runner==="blaxel"&&f.state==="running"&&!d(e.profile_id)&&await p(i)){if(await W(f)==="lost")return}else f?.runner==="blaxel"&&f.state==="running"&&await G(f);if(await a.fleet.has(i)){d(e.profile_id)?await a.fleet.interruptForProfilePause(i):await this.thawMark(e);return}}if(await H(i,t),d(e.profile_id)){await this.freezeLane.endEpisode(i);return}if(await v(i))return;const s=e.pi_pid==null&&await L(i),u=e.pi_pid==null&&!s&&await z(i),c=s||u||e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead";if(c&&!await a.fleet.hasProfilePauseInterruption(i)&&await h(i,{reason:"observed-dead"}),!await T(e)){await this.thawMark(e),await this.settleParked(e);return}if(P(e,t))return;if(e.status==="idle"&&w(e)&&await p(i)){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null&&(!s||e.frozen_at!=null)&&!u){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){n.push({row:e,enact:"thaw"});return}if(await a.fleet.isClaimed(i)||j(e,t))return;y({level:"warn",event:"node.lifecycle.stranded_launch",node_id:i}),n.push({row:e,enact:"thaw"});return}if(!c)return;const o=M(await R(i),(await g(i))?.interrupted===!0,await x(i));if(o==="respawn-fresh"||o==="respawn-cycle"||o==="respawn-resume"){n.push({row:e,enact:"policy"});return}await a.fleet.applyDeadRowPolicy(i),await this.thawMark(e)}async thawMark(t){t.frozen_at!=null&&await m(t.node_id)}async settleParked(t){if(t.status!=="idle")return;await this.freezeLane.endEpisode(t.node_id);const e=await A(t.node_id,t.lifecycle);e!=="release"&&await F(t.node_id,e)}}export{O as LAUNCH_GRACE_MS,me as NodeLifecycleReconciler,j as isLaunchInFlight};