@north-light/cli 0.3.570 → 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.
- package/bin/runtime-selector.mjs +15 -0
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/broker-ops.d.ts +3 -0
- package/dist/api/dto/recovery.d.ts +7 -0
- package/dist/api/errors.d.ts +3 -0
- package/dist/api/errors.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +7 -0
- package/dist/commands/dashboard.js +3 -1
- package/dist/core/auth-file.d.ts +2 -0
- package/dist/core/auth-file.js +1 -1
- package/dist/core/canvas/recovery.d.ts +3 -0
- package/dist/core/canvas/recovery.js +2 -2
- package/dist/core/canvas/schema-pg/008-import.sql +126 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/command.d.ts +2 -3
- package/dist/core/command.js +6 -6
- package/dist/core/llm/run.js +2 -2
- package/dist/core/model-auth/readiness.js +1 -1
- package/dist/core/providers/files.js +1 -1
- package/dist/core/runs/operations.js +6 -6
- package/dist/core/runtime/blaxel-environment.d.ts +2 -0
- package/dist/core/runtime/blaxel-environment.js +1 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +4 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/spaces/process.js +1 -1
- package/dist/core/spaces/space.d.ts +2 -1
- package/dist/core/spaces/space.js +2 -2
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/reconcilers/action-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/launch-failure.d.ts +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/launch-failure.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/node-person.d.ts +9 -0
- package/dist/daemon/reconcilers/node-lifecycle/node-person.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +0 -2
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
- package/docs/sdk/release-notes.md +7 -0
- package/package.json +8 -3
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +17 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
var J=Object.defineProperty;var l=(e,r)=>J(e,"name",{value:r,configurable:!0});import{envHomeOverride as K,envRuntimeHomeOverride as X,INBOX_BETWEEN_TURNS_ENV as z,SCOPES_FILE_ENV as V,scopeAllowed as I}from"../../shared/env.js";import{isOwnMemoryScope as Y,validateScopes as Q}from"../scopes.js";import{activeGrant as F,terminalGrant as k}from"../grants/mirror.js";import{grantSnapshotMissing as Z}from"../../daemon/readiness.js";import{appendRunEvent as ee}from"../runs/events.js";import{personId as ne}from"../canvas/person.js";import{InputError as S}from"../io.js";import{ApiError as g}from"../../api/errors.js";import{assertGranteeRunsHere as re}from"./unsandboxed.js";import{randomBytes as te}from"node:crypto";import{existsSync as B}from"node:fs";import{resolve as ie,relative as oe,isAbsolute as L,join as ae,sep as le}from"node:path";import{appSpace as se}from"../layout.js";import{scopesFilePath as de}from"../canvas/paths.js";import{createNode as ce,assertRunNotDeleting as ue,conversationOwner as fe,getNode as u,getRow as pe}from"../canvas/index.js";import{ensureAppSpace as _e}from"../spaces/space.js";import{LAUNCHER_SOCKET as P}from"../../launcher/spec.js";import{resolveInstallId as me}from"../canvas/install-id.js";import{isAppRun as we}from"../canvas/app-run.js";import{contextDir as ge}from"../canvas/paths.js";import{conversationIdFromPath as he}from"../conversation-store/index.js";import{usage as U}from"../errors.js";import{assertProfileAvailableForBirth as Re}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as ve}from"../profiles/manifest.js";import{admitNodeCreate as ye}from"../command-hooks/lifecycle-create.js";import{getById as Ee,nodeObject as N,ownerForGrantee as Ie}from"../graph/objects.js";import{recordActedOn as Ne}from"../graph/edges.js";import{recordWatch as Ce,copyWatchesForFork as ke}from"../graph/watches.js";import{publish as Se}from"../graph/events.js";import{canvasDatabaseUrl as Te}from"../canvas/db.js";import{someAsync as De}from"../async-array.js";import{admitIntoManagedCheckout as Oe}from"../worktree-mutation-async.js";let T;const H=new Map;function hn(e){T=e}l(hn,"setInstallId");async function xe(){if(T!==void 0)return T;const e=await Te(),r=H.get(e);if(r!==void 0)return r;const o=await me();return H.set(e,o),o}l(xe,"installId");function be(){return`${Date.now().toString(36)}-${te(4).toString("hex")}`}l(be,"newJobId");async function Ae(){return`${await xe()}-${be()}`}l(Ae,"newNodeId");const D=128,Me=/^[a-z0-9-]+$/;class j extends Error{static{l(this,"NodeIdConflictError")}nodeId;constructor(r){super(`node already exists: ${r}`),this.nodeId=r,this.name="NodeIdConflictError"}}function O(e){if(e.length===0||e.length>D)throw U(`invalid --node-id '${e}': must be 1-${D} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${D} characters.`});if(!Me.test(e))throw U(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}l(O,"validateNodeIdFormat");async function Rn(e){if(O(e),await u(e)!==null)throw new j(e)}l(Rn,"preflightNodeId");async function $e(e){if(O(e),await u(e)!==null)throw new j(e);return e}l($e,"validatedExplicitNodeId");async function vn(e){let r=e;const o=new Set;for(;;){if(o.has(r))return r;o.add(r);const s=await pe(r);if(s===null||s.parent==null)return r;r=s.parent}}l(vn,"rootOfSpine");function yn(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}l(yn,"currentNodeContext");function Fe(e){return we(e)}l(Fe,"inboxBetweenTurns");function En(e){const r={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:ge(e.node_id,e.grantee),...e.deadline_at?{CRTR_NODE_DEADLINE_AT:e.deadline_at}:{},CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(r.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(r.CRTR_RUN_ID=e.run_id),Fe(e)&&(r[z]="1"),e.scopes!==null&&e.scopes!==void 0&&(r[V]=de(e.node_id)),r.CRTR_GRANTEE=e.grantee??"app:terminal";const o=K();o!==void 0&&o!==""&&(r.CRTR_HOME=o);const s=X();s!==void 0&&s!==""&&(r.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(r.CRTR_SUBTREE=f),{...r,...e.launch?.env??{}}}l(En,"nodeEnv");async function Be(e){const r=he(e),o=r===null?null:await fe(r);return o===null?null:await u(o)}l(Be,"forkSourceNode");async function In(e){const r=e.nodeId!==void 0?(O(e.nodeId),e.nodeId):await Ae(),o=e.parent??null,s=o===null,f=e.spawnedBy??o,_=e.creator??null,x=e.mode??"base",C=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?await k():null,n={node_id:r,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:x,lifecycle:C,persona_ack:{kind:e.kind,mode:x,lifecycle:C},status:"active",parent:o,spawned_by:f,creator:_,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?r:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,caused_by:e.causedBy??null,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},y=e.scopes===void 0?void 0:Q(e.scopes),R=o===null?null:await u(o);if(o!==null&&R===null)throw new Error(`cannot spawn under unknown parent node: ${o}`);if(R?.run_id&&(await u(R.run_id))?.deleting_at)throw new Error("run is deleting");const c=_===null?null:await u(_);if(_!==null&&c===null)throw new Error(`cannot spawn from unknown creator node: ${_}`);if(c?.run_id&&(await u(c.run_id))?.deleting_at)throw new Error("run is deleting");const b=e.forkSourceFile==null?null:await Be(e.forkSourceFile),A=e.replaces==null?null:await u(e.replaces),m=R??b??A??c??(f===null?null:await u(f)),q=[R,c,b,A,f===null?null:await u(f)],M=await De(q,async t=>t?.isolated===!0||t?.run_id!=null&&(await u(t.run_id))?.isolated===!0);if(M&&e.isolated===!1)throw new g(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=M||e.isolated===!0,m!==null){const t=c??m;if(c&&m.grantee&&c.grantee&&c.grantee!==m.grantee)throw new g(403,"other_app_run","cannot create under another app's node");const i=c&&c!==m?[m,c]:[m],d=[],w=new Set;for(const a of i){a.scopes!==null&&a.scopes!==void 0&&d.push(a.scopes);const p=a.grantee==="app:terminal"?await k():a.grant_id?await F(a.grant_id):null;if(p){const v=[...p.resolved];w.add(v),d.push(v)}else{const v=[];w.add(v),d.push(v)}}const E=l(a=>Y(a,t.grantee??"app:terminal"),"ownMemory"),$=l((a,p)=>E(p)&&w.has(a)||I(a,p),"allowed");if(y!==void 0&&!y.every(a=>d.every(p=>$(p,a))))throw new S({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:y,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=y??(i.every(a=>a.scopes==null)&&i.every(a=>a.grant_id===t.grant_id&&a.sub===t.sub)?null:i.length===1?m.scopes??null:[...new Set(d.flat().filter(a=>d.every(p=>$(p,a))))]),n.scopes?.includes("crtr:act")&&!I(n.scopes,"crtr:llm"))throw new S({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=t.grantee,n.sub=t.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=t.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=t.client_id,n.run_id=s?r:t.run_id??null}if(re(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&h===null)throw await Z()?new g(503,"runtime_starting","the first grant snapshot from the directory has not committed"):new g(403,"scope_missing","terminal grant is not active");if(n.isolated){if(process.platform!=="linux"||!B(P))throw new g(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new g(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const t=ae(se(n.grantee??"app:terminal").nodes,r),i=oe(t,ie(n.cwd));if(!L(n.cwd)||i===".."||i.startsWith(`..${le}`)||L(i))throw new g(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const t=ve(n.profile_id).manifest.grantee??"app:terminal";if(t!==n.grantee){const i=`crtr:memory:rw:${t}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?await k():n.grant_id?await F(n.grant_id):null;if(!d||d.grantee!==n.grantee||!I(d.resolved,i)||!I(n.scopes,i))throw new S({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(Re(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const W=await ye({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:o,requestingNodeId:_,lifecycle:C,replaces:e.replaces??null},n.grantee),G=l(async(t,i)=>{const d=await N(t,i.node_id),w=_??o??e.actor??f??null,E=w!==null&&(await Ee(t,w))?.type==="node"?await N(t,w):await Ie(t,e.run===void 0?ne():i.grantee);await Ne(t,E,d),o!==null&&e.subscribe!==!1&&await Ce(t,await N(t,o),d,"spawn"),e.forkSourceNode&&await ke(t,await N(t,e.forkSourceNode),d),await Se(t,{event:"created",object:d,actor:E,attrs:{name:i.name,kind:i.kind,creator:_??null}})},"recordBirth");try{e.nodeId!==void 0&&await $e(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||B(P))&&await _e(n.grantee??"app:terminal"),await Oe(n.cwd,r,()=>ce(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:l(async(t,i)=>{i.run_id&&i.run_id!==i.node_id&&await ue(t,i.run_id),s&&e.run===void 0&&await ee(t,r,r,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),await e.withinCreate?.(t,i),await G(t,i)},"withinCreate")}))}finally{W()}return n}l(In,"spawnNode");export{j as NodeIdConflictError,yn as currentNodeContext,Be as forkSourceNode,Fe as inboxBetweenTurns,be as newJobId,Ae as newNodeId,En as nodeEnv,Rn as preflightNodeId,vn as rootOfSpine,hn as setInstallId,In as spawnNode};
|
|
1
|
+
var J=Object.defineProperty;var l=(e,r)=>J(e,"name",{value:r,configurable:!0});import{envHomeOverride as K,envRuntimeHomeOverride as X,INBOX_BETWEEN_TURNS_ENV as z,SCOPES_FILE_ENV as V,scopeAllowed as I}from"../../shared/env.js";import{isOwnMemoryScope as Y,validateScopes as Q}from"../scopes.js";import{activeGrant as F,terminalGrant as k}from"../grants/mirror.js";import{grantSnapshotMissing as Z}from"../../daemon/readiness.js";import{appendRunEvent as ee}from"../runs/events.js";import{personId as ne}from"../canvas/person.js";import{InputError as S}from"../io.js";import{ApiError as g}from"../../api/errors.js";import{assertGranteeRunsHere as re}from"./unsandboxed.js";import{randomBytes as te}from"node:crypto";import{existsSync as B}from"node:fs";import{resolve as ie,relative as oe,isAbsolute as L,join as ae,sep as le}from"node:path";import{appSpace as se}from"../layout.js";import{scopesFilePath as de}from"../canvas/paths.js";import{createNode as ce,assertRunNotDeleting as ue,conversationOwner as fe,getNode as u,getRow as pe}from"../canvas/index.js";import{ensureAppSpace as _e}from"../spaces/space.js";import{LAUNCHER_SOCKET as P}from"../../launcher/spec.js";import{blaxelEnvironmentOf as me}from"./blaxel-environment.js";import{resolveInstallId as we}from"../canvas/install-id.js";import{isAppRun as ge}from"../canvas/app-run.js";import{contextDir as he}from"../canvas/paths.js";import{conversationIdFromPath as ve}from"../conversation-store/index.js";import{usage as U}from"../errors.js";import{assertProfileAvailableForBirth as Re}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as ye}from"../profiles/manifest.js";import{admitNodeCreate as Ee}from"../command-hooks/lifecycle-create.js";import{getById as Ie,nodeObject as N,ownerForGrantee as Ne}from"../graph/objects.js";import{recordActedOn as Ce}from"../graph/edges.js";import{recordWatch as ke,copyWatchesForFork as Se}from"../graph/watches.js";import{publish as Te}from"../graph/events.js";import{canvasDatabaseUrl as De}from"../canvas/db.js";import{someAsync as Oe}from"../async-array.js";import{admitIntoManagedCheckout as xe}from"../worktree-mutation-async.js";let T;const H=new Map;function Rn(e){T=e}l(Rn,"setInstallId");async function be(){if(T!==void 0)return T;const e=await De(),r=H.get(e);if(r!==void 0)return r;const o=await we();return H.set(e,o),o}l(be,"installId");function Ae(){return`${Date.now().toString(36)}-${te(4).toString("hex")}`}l(Ae,"newJobId");async function Me(){return`${await be()}-${Ae()}`}l(Me,"newNodeId");const D=128,$e=/^[a-z0-9-]+$/;class j extends Error{static{l(this,"NodeIdConflictError")}nodeId;constructor(r){super(`node already exists: ${r}`),this.nodeId=r,this.name="NodeIdConflictError"}}function O(e){if(e.length===0||e.length>D)throw U(`invalid --node-id '${e}': must be 1-${D} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${D} characters.`});if(!$e.test(e))throw U(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}l(O,"validateNodeIdFormat");async function yn(e){if(O(e),await u(e)!==null)throw new j(e)}l(yn,"preflightNodeId");async function Fe(e){if(O(e),await u(e)!==null)throw new j(e);return e}l(Fe,"validatedExplicitNodeId");async function En(e){let r=e;const o=new Set;for(;;){if(o.has(r))return r;o.add(r);const s=await pe(r);if(s===null||s.parent==null)return r;r=s.parent}}l(En,"rootOfSpine");function In(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}l(In,"currentNodeContext");function Be(e){return ge(e)}l(Be,"inboxBetweenTurns");function Nn(e){const r={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:he(e.node_id,e.grantee),...e.deadline_at?{CRTR_NODE_DEADLINE_AT:e.deadline_at}:{},CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(r.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(r.CRTR_RUN_ID=e.run_id),Be(e)&&(r[z]="1"),e.scopes!==null&&e.scopes!==void 0&&(r[V]=de(e.node_id)),r.CRTR_GRANTEE=e.grantee??"app:terminal";const o=K();o!==void 0&&o!==""&&(r.CRTR_HOME=o);const s=X();s!==void 0&&s!==""&&(r.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(r.CRTR_SUBTREE=f),{...r,...e.launch?.env??{}}}l(Nn,"nodeEnv");async function Le(e){const r=ve(e),o=r===null?null:await fe(r);return o===null?null:await u(o)}l(Le,"forkSourceNode");async function Cn(e){const r=e.nodeId!==void 0?(O(e.nodeId),e.nodeId):await Me(),o=e.parent??null,s=o===null,f=e.spawnedBy??o,_=e.creator??null,x=e.mode??"base",C=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?await k():null,n={node_id:r,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:x,lifecycle:C,persona_ack:{kind:e.kind,mode:x,lifecycle:C},status:"active",parent:o,spawned_by:f,creator:_,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?r:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,caused_by:e.causedBy??null,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},y=e.scopes===void 0?void 0:Q(e.scopes),v=o===null?null:await u(o);if(o!==null&&v===null)throw new Error(`cannot spawn under unknown parent node: ${o}`);if(v?.run_id&&(await u(v.run_id))?.deleting_at)throw new Error("run is deleting");const c=_===null?null:await u(_);if(_!==null&&c===null)throw new Error(`cannot spawn from unknown creator node: ${_}`);if(c?.run_id&&(await u(c.run_id))?.deleting_at)throw new Error("run is deleting");const b=e.forkSourceFile==null?null:await Le(e.forkSourceFile),A=e.replaces==null?null:await u(e.replaces),m=v??b??A??c??(f===null?null:await u(f)),q=[v,c,b,A,f===null?null:await u(f)],M=await Oe(q,async t=>t?.isolated===!0||t?.run_id!=null&&(await u(t.run_id))?.isolated===!0);if(M&&e.isolated===!1)throw new g(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=M||e.isolated===!0,m!==null){const t=c??m;if(c&&m.grantee&&c.grantee&&c.grantee!==m.grantee)throw new g(403,"other_app_run","cannot create under another app's node");const i=c&&c!==m?[m,c]:[m],d=[],w=new Set;for(const a of i){a.scopes!==null&&a.scopes!==void 0&&d.push(a.scopes);const p=a.grantee==="app:terminal"?await k():a.grant_id?await F(a.grant_id):null;if(p){const R=[...p.resolved];w.add(R),d.push(R)}else{const R=[];w.add(R),d.push(R)}}const E=l(a=>Y(a,t.grantee??"app:terminal"),"ownMemory"),$=l((a,p)=>E(p)&&w.has(a)||I(a,p),"allowed");if(y!==void 0&&!y.every(a=>d.every(p=>$(p,a))))throw new S({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:y,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=y??(i.every(a=>a.scopes==null)&&i.every(a=>a.grant_id===t.grant_id&&a.sub===t.sub)?null:i.length===1?m.scopes??null:[...new Set(d.flat().filter(a=>d.every(p=>$(p,a))))]),n.scopes?.includes("crtr:act")&&!I(n.scopes,"crtr:llm"))throw new S({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=t.grantee,n.sub=t.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=t.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=t.client_id,n.run_id=s?r:t.run_id??null}if(re(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&h===null)throw await Z()?new g(503,"runtime_starting","the first grant snapshot from the directory has not committed"):new g(403,"scope_missing","terminal grant is not active");if(n.isolated){if((process.platform!=="linux"||!B(P))&&await me(n.profile_id??null)===null)throw new g(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new g(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const t=ae(se(n.grantee??"app:terminal").nodes,r),i=oe(t,ie(n.cwd));if(!L(n.cwd)||i===".."||i.startsWith(`..${le}`)||L(i))throw new g(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const t=ye(n.profile_id).manifest.grantee??"app:terminal";if(t!==n.grantee){const i=`crtr:memory:rw:${t}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?await k():n.grant_id?await F(n.grant_id):null;if(!d||d.grantee!==n.grantee||!I(d.resolved,i)||!I(n.scopes,i))throw new S({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(Re(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const W=await Ee({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:o,requestingNodeId:_,lifecycle:C,replaces:e.replaces??null},n.grantee),G=l(async(t,i)=>{const d=await N(t,i.node_id),w=_??o??e.actor??f??null,E=w!==null&&(await Ie(t,w))?.type==="node"?await N(t,w):await Ne(t,e.run===void 0?ne():i.grantee);await Ce(t,E,d),o!==null&&e.subscribe!==!1&&await ke(t,await N(t,o),d,"spawn"),e.forkSourceNode&&await Se(t,await N(t,e.forkSourceNode),d),await Te(t,{event:"created",object:d,actor:E,attrs:{name:i.name,kind:i.kind,creator:_??null}})},"recordBirth");try{e.nodeId!==void 0&&await Fe(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||B(P))&&await _e(n.grantee??"app:terminal"),await xe(n.cwd,r,()=>ce(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:l(async(t,i)=>{i.run_id&&i.run_id!==i.node_id&&await ue(t,i.run_id),s&&e.run===void 0&&await ee(t,r,r,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),await e.withinCreate?.(t,i),await G(t,i)},"withinCreate")}))}finally{W()}return n}l(Cn,"spawnNode");export{j as NodeIdConflictError,In as currentNodeContext,Le as forkSourceNode,Be as inboxBetweenTurns,Ae as newJobId,Me as newNodeId,Nn as nodeEnv,yn as preflightNodeId,En as rootOfSpine,Rn as setInstallId,Cn as spawnNode};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var re=Object.defineProperty;var l=(e,r)=>re(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ie}from"./unsandboxed.js";import{existsSync as L}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as te}from"node:path";import{findNodeBySessionFile as ne,getNode as E,updateNode as S,beginExecution as ae,ExecutionAlreadyLive as oe,recordExecutionPid as se,abortExecution as $,endLiveExecution as le,unbindSession as M,recordLaunch as ce,setFrozen as ue,clearFrozen as U,fullName as fe}from"../canvas/index.js";import{emitEvent as we}from"../events/emit.js";import{consumeDeadlineOnWake as de}from"../feed/messages.js";import{isParked as z,transition as N}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as C}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as pe,drainBearings as me,hasRetainedReports as ve,readGoal as g,readYieldMessage as _e,RUNTIME_RESTART_CONTINUATION as ye}from"./kickoff.js";import{readRoadmap as K}from"./roadmap.js";import{encodeKickoffOrigin as ke,KICKOFF_ORIGIN_ENV as ge}from"./stamp/protocol.js";import{headlessBrokerHost as be,brokerLaunchJson as Re}from"./host.js";import{processRunner as xe}from"./runner/process.js";import{runnerForEnvironment as Ee}from"./runner/index.js";import{acceptedRelease as Se,blaxelEnvironmentOf as G,checkBilledWake as $e,EnvironmentImagePending as Ne,imageForWake as Ce}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Fe,liveExecutionForNode as Ae,setExecutionLaunchJson as Pe}from"../canvas/executions.js";import{appMemoryFull as Be,appMemoryTooSmall as Oe,boundFleet as J,brokerCapReached as W,brokerThresholdsForDaemon as F}from"./fleet.js";import{admitBrokerMemory as De}from"./memory-admission.js";import{beginBootFaultAttempt as Te,clearFault as Le,hasAdmittedTurn as He}from"../canvas/recovery.js";import{clearNodeLedger as j,forkNodeLedger as Me,noticeChangedWhileDone as Ue}from"./ledger.js";import{forkSourceNode as ze,rootOfSpine as Ke}from"./nodes.js";import{checkStart as Ge}from"./start-check.js";import{isReviewCompanionBound as Je}from"../review/companion.js";import{assertProfileActive as We}from"../profiles/manifest.js";import{isPidAlive as je}from"../canvas/pid.js";import{crtrHome as Ve,jobDir as Xe}from"../canvas/paths.js";import{contextDir as Ye,ensureNodeDirs as qe,nodeAgentDir as Qe}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Ze}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as Ie}from"../command-hooks/transport/exec-lifecycle.js";async function er(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await p().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}l(er,"resumeArgs");async function V(e){const r=v(e);if(r===null)return!1;try{return await p().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}l(V,"conversationExists");async function rr(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(rr,"sessionHasConversation");async function ir(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||L(i)}l(ir,"sessionCwdExists");async function tr(e,r,i,t){const a=r.pi_session_file;if(!a||!await V(a))return{};const u=await ne(a);return u!==null&&u.node_id!==e&&je(u.pi_pid)?{}:t&&!await ir(a)?{}:await er(r,i)}l(tr,"resumableSessionArgs");async function nr(e){return await K(e)===null&&await _e(e)===null&&!await ve(e)}l(nr,"isUnstartedBirth");async function Ur(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await K(e);return i!==null&&i.trim()!==""}l(Ur,"hasFreshGroundState");async function zr(e,r){const i=await X(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(zr,"reviveNode");async function Kr(e,r,i){return X(e,{...r,viewerAttach:!0},i)}l(Kr,"decideAttachRevive");async function X(e,r,i){let t=await E(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await E(e)??t,t.run_id&&(await E(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);We(t.profile_id),ie(t.grantee);const a=J();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&z(t))&&(await Ge(t),await G(t.profile_id??null)!==null&&await $e(t)),await a.has(e))return await N(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&z(t))return{parked:!0};const u=await a.reserveSlot(e);let o=null;if(u){try{o=await De(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Oe(o);if(!u||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?Be(o):W(F().automaticReviveCap,await a.occupancy());return t.frozen_at==null&&(await ue(e,new Date().toISOString()),await le(e,{reason:"frozen"}),we({level:"info",event:"broker.frozen",node_id:e,fields:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:F().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await ar(e,t,r)}}finally{a.releaseReservation(e)}}l(X,"decideRevive");async function ar(e,r,i){const t=await G(r.profile_id??null);if(t===null&&!L(r.cwd)){const s=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new C({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await S(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Je(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await M(e),r.pi_session_id=null,r.pi_session_file=null);const u=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(u&&(typeof o!="string"||!te(o)))throw new C({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=u&&typeof o=="string";if(w&&!await V(o))throw new C({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:Y}=F();if(t!==null){const s=await Ce(t);if(s.state==="pending")throw new Ne(t,s.error)}const q=t===null?xe:Ee("blaxel");let f;try{f=await ae(e,{daemonEpoch:J().epoch(),cap:Y,...t===null?{}:{runner:"blaxel",release:Se()}})}catch(s){if(s instanceof Fe)throw W(s.cap,s.live);if(s instanceof oe)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await S(e,{cycles:r.cycles});const Q=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=w?{}:await tr(e,r,Q,t===null),y=h.resumeSessionPath!==void 0,A=y&&h.newCycle===!0,m=y&&!A,P=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await nr(e),b=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await rr(h.resumeSessionPath)?(await g(e))?.trim():void 0,B=b!==void 0&&b!=="",Z=w||P||B,O=r.cycle_pending===!0||A;await S(e,{cycle_pending:O}),r.cycle_pending=O,!w&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await M(e),r.pi_session_id=null,r.pi_session_file=null);let c,d=null;const R=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await g(e),x=v(o);if(x===null)throw new Error(`invalid fork source ${o}`);const ee=(await p().header(await p().fork(x,e))).path;c=_(r,{resumeSessionPath:ee,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=R()),await Me(e,(await ze(o))?.node_id??null)}else if(B)c=_(r,{...h,prompt:b}),d=R();else if(m)c=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ye}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(P){const n=(await g(e))?.trim();c=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=R()),await j(e)}else{const n=await me(r,f);c=_(r,{...h,prompt:await pe(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await j(e)}c.env={...c.env,CRTR_SUBTREE:await Ke(e)},d!==null&&(c.env[ge]=ke(d)),r.status==="done"&&r.last_settled_at!=null&&await Ue(e,r.last_settled_at),await N(e,r.intent==="refresh"?"refresh-launch":"revive"),await Le(e,{preserveEpisode:!0});const D=await Te(e);i.recovery!==!0&&i.viewerAttach!==!0&&await de(e),await qe(e,r.grantee);const I=Ze(r.cwd,r.profile_id).plans.get("node:start")??[];await Ie(I,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Qe(e),contextDir:await Ye(e),jobDir:Xe(e)},runtime:{isBirth:Z,canvasHome:Ve(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:f};const T=await Re(e,c,r.cwd);await Pe(f,T);let k;try{const n=await Ae(e);if(k=await q.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:T,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await N(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await he(e,"notice.crash",`Child crashed \u2014 ${fe(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
1
|
+
var ie=Object.defineProperty;var l=(e,r)=>ie(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as te}from"./unsandboxed.js";import{existsSync as H}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as M}from"../conversation-store/index.js";import{isAbsolute as ne}from"node:path";import{findNodeBySessionFile as ae,getNode as S,updateNode as $,beginExecution as oe,ExecutionAlreadyLive as se,recordExecutionPid as le,abortExecution as N,endLiveExecution as ce,unbindSession as U,recordLaunch as ue,setFrozen as fe,clearFrozen as z,fullName as we}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as de}from"../feed/messages.js";import{isParked as G,transition as C}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as F}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as pe,drainBearings as me,hasRetainedReports as ve,readGoal as g,readYieldMessage as _e,RUNTIME_RESTART_CONTINUATION as ye}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ke,KICKOFF_ORIGIN_ENV as ge}from"./stamp/protocol.js";import{headlessBrokerHost as be,brokerLaunchJson as Re}from"./host.js";import{processRunner as xe}from"./runner/process.js";import{runnerForEnvironment as Ee}from"./runner/index.js";import{blaxelEnvironmentOf as W}from"./blaxel-environment.js";import{recordLaunchFailure as Se}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as $e,checkBilledWake as Ne,EnvironmentImagePending as Ce,imageForWake as Fe}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Ae,liveExecutionForNode as Pe,setExecutionLaunchJson as Be}from"../canvas/executions.js";import{appMemoryFull as Oe,appMemoryTooSmall as De,boundFleet as j,brokerCapReached as V,brokerThresholdsForDaemon as A}from"./fleet.js";import{admitBrokerMemory as Te}from"./memory-admission.js";import{beginBootFaultAttempt as Le,clearFault as He,hasAdmittedTurn as Me}from"../canvas/recovery.js";import{clearNodeLedger as X,forkNodeLedger as Ue,noticeChangedWhileDone as ze}from"./ledger.js";import{forkSourceNode as Ke,rootOfSpine as Ge}from"./nodes.js";import{checkStart as Je}from"./start-check.js";import{isReviewCompanionBound as We}from"../review/companion.js";import{assertProfileActive as je}from"../profiles/manifest.js";import{isPidAlive as Ve}from"../canvas/pid.js";import{crtrHome as Xe,jobDir as Ye}from"../canvas/paths.js";import{contextDir as qe,ensureNodeDirs as Qe,nodeAgentDir as Ze}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Ie}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as er}from"../command-hooks/transport/exec-lifecycle.js";async function rr(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await p().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof M)return{};throw a}}l(rr,"resumeArgs");async function Y(e){const r=v(e);if(r===null)return!1;try{return await p().header(r),!0}catch(i){if(i instanceof M)return!1;throw i}}l(Y,"conversationExists");async function ir(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(ir,"sessionHasConversation");async function tr(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||H(i)}l(tr,"sessionCwdExists");async function nr(e,r,i,t){const a=r.pi_session_file;if(!a||!await Y(a))return{};const f=await ae(a);return f!==null&&f.node_id!==e&&Ve(f.pi_pid)?{}:t&&!await tr(a)?{}:await rr(r,i)}l(nr,"resumableSessionArgs");async function ar(e){return await J(e)===null&&await _e(e)===null&&!await ve(e)}l(ar,"isUnstartedBirth");async function Gr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}l(Gr,"hasFreshGroundState");async function Jr(e,r){const i=await q(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(Jr,"reviveNode");async function Wr(e,r,i){return q(e,{...r,viewerAttach:!0},i)}l(Wr,"decideAttachRevive");async function q(e,r,i){let t=await S(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await S(e)??t,t.run_id&&(await S(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);je(t.profile_id),te(t.grantee);const a=j();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&G(t))&&(await Je(t),await W(t.profile_id??null)!==null&&await Ne(t)),await a.has(e))return await C(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&G(t))return{parked:!0};const f=await a.reserveSlot(e);let o=null;if(f){try{o=await Te(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw De(o);if(!f||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?Oe(o):V(A().automaticReviveCap,await a.occupancy());return t.frozen_at==null&&(await fe(e,new Date().toISOString()),await ce(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:A().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await or(e,t,r)}}finally{a.releaseReservation(e)}}l(q,"decideRevive");async function or(e,r,i){const t=await W(r.profile_id??null);if(t===null&&!H(r.cwd)){const s=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new F({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await $(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await We(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);const f=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(f&&(typeof o!="string"||!ne(o)))throw new F({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=f&&typeof o=="string";if(w&&!await Y(o))throw new F({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:Q}=A();if(t!==null){const s=await Fe(t);if(s.state==="pending")throw new Ce(t,s.error)}const Z=t===null?xe:Ee("blaxel");let u;try{u=await oe(e,{daemonEpoch:j().epoch(),cap:Q,...t===null?{}:{runner:"blaxel",release:$e()}})}catch(s){if(s instanceof Ae)throw V(s.cap,s.live);if(s instanceof se)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await $(e,{cycles:r.cycles});const b=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=w?{}:await nr(e,r,b,t===null),y=h.resumeSessionPath!==void 0,P=y&&h.newCycle===!0,m=y&&!P,B=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await ar(e),R=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await Me(e)&&!await ir(h.resumeSessionPath)?(await g(e))?.trim():void 0,O=R!==void 0&&R!=="",I=w||B||O,D=r.cycle_pending===!0||P;await $(e,{cycle_pending:D}),r.cycle_pending=D,!w&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);let c,d=null;const x=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await g(e),E=v(o);if(E===null)throw new Error(`invalid fork source ${o}`);const re=(await p().header(await p().fork(E,e))).path;c=_(r,{resumeSessionPath:re,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=x()),await Ue(e,(await Ke(o))?.node_id??null)}else if(O)c=_(r,{...h,prompt:R}),d=x();else if(m)c=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ye}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(B){const n=(await g(e))?.trim();c=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=x()),await X(e)}else{const n=await me(r,u);c=_(r,{...h,prompt:await pe(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await X(e)}c.env={...c.env,CRTR_SUBTREE:await Ge(e)},d!==null&&(c.env[ge]=ke(d)),r.status==="done"&&r.last_settled_at!=null&&await ze(e,r.last_settled_at),await C(e,r.intent==="refresh"?"refresh-launch":"revive"),await He(e,{preserveEpisode:!0});const T=await Le(e);i.recovery!==!0&&i.viewerAttach!==!0&&await de(e),await Qe(e,r.grantee);const ee=Ie(r.cwd,r.profile_id).plans.get("node:start")??[];await er(ee,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Ze(e),contextDir:await qe(e),jobDir:Ye(e)},runtime:{isBirth:I,canvasHome:Xe(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:u};const L=await Re(e,c,r.cwd);await Be(u,L);let k;try{const n=await Pe(e);if(k=await Z.start({executionId:u,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:L,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await C(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await he(e,"notice.crash",`Child crashed \u2014 ${we(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
2
2
|
|
|
3
|
-
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await
|
|
3
|
+
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await N(u,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await ue(e,new Date().toISOString()),t!==null)return await z(e),{window:null,session:r.tmux_session??null,resumed:m,faultExplanation:T.explanation,outcome:"launched"};if(await le(u,e,k.pid)==="shutdown")throw await N(u,{reason:"superseded"}),be.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await z(e),{window:null,session:r.tmux_session??null,resumed:m,launch:k,faultExplanation:T.explanation,outcome:"launched"}}catch(s){throw await N(u,{reason:"launch_failed"}),await Se(u,s).catch(b=>{K({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:b})}),s}}l(or,"launchRevive");export{Wr as decideAttachRevive,Gr as hasFreshGroundState,rr as resumeArgs,Jr as reviveNode};
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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>;
|