@north-light/cli 0.3.575 → 0.3.577

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/api/contract.d.ts +1 -1
  2. package/dist/api/contract.js +1 -1
  3. package/dist/builtin-memory/crouter-sdk/release-notes.md +8 -0
  4. package/dist/clients/attach/viewer.js +212 -212
  5. package/dist/core/canvas/executions.d.ts +4 -4
  6. package/dist/core/canvas/executions.js +1 -1
  7. package/dist/core/command-plugins/bundle.d.ts +6 -3
  8. package/dist/core/command-plugins/bundle.js +1 -1
  9. package/dist/core/io.js +4 -4
  10. package/dist/core/llm/run.js +2 -2
  11. package/dist/core/model-routes.d.ts +11 -0
  12. package/dist/core/model-routes.js +1 -1
  13. package/dist/core/peer/envelope.d.ts +2 -0
  14. package/dist/core/peer/envelope.js +1 -1
  15. package/dist/core/provider-error-recognition.d.ts +3 -0
  16. package/dist/core/provider-error-recognition.js +1 -1
  17. package/dist/core/providers/bundles.js +2 -2
  18. package/dist/core/providers/call.js +1 -1
  19. package/dist/core/providers/roots.d.ts +4 -0
  20. package/dist/core/providers/roots.js +1 -1
  21. package/dist/core/runtime/broker/daemon-ops.d.ts +4 -0
  22. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  23. package/dist/core/runtime/broker-request.js +1 -1
  24. package/dist/core/runtime/broker.js +1 -1
  25. package/dist/core/runtime/revive.d.ts +6 -0
  26. package/dist/core/runtime/revive.js +2 -2
  27. package/dist/core/runtime/run-command.js +1 -1
  28. package/dist/core/runtime/runner/blaxel/client.d.ts +2 -0
  29. package/dist/core/runtime/runner/blaxel/client.js +1 -1
  30. package/dist/core/runtime/runner/blaxel/runner.js +2 -2
  31. package/dist/core/runtime/spawn.js +2 -2
  32. package/dist/core/runtime/view-socket.d.ts +1 -1
  33. package/dist/core/subscription-state.d.ts +4 -0
  34. package/dist/core/subscription-state.js +1 -1
  35. package/dist/daemon/api/handlers/messages.js +2 -2
  36. package/dist/daemon/api/handlers/nodes.js +1 -1
  37. package/dist/daemon/api/handlers/providers.js +1 -1
  38. package/dist/daemon/crtrd.js +11 -11
  39. package/dist/daemon/peer/forward.js +1 -1
  40. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  41. package/dist/daemon/reconcilers/live-obligation.d.ts +11 -0
  42. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  43. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  44. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  45. package/dist/pi-extensions/canvas-stophook.js +1 -1
  46. package/docs/sdk/release-notes.md +8 -0
  47. package/package.json +2 -2
  48. package/packages/crouter-identity/package.json +1 -1
  49. package/runtime.lock.json +13 -13
  50. package/scripts/sandbox-start.mjs +8 -1
@@ -1,2 +1,2 @@
1
- var se=Object.defineProperty;var a=(e,n)=>se(e,"name",{value:n,configurable:!0});import{existsSync as $,readdirSync as U,readFileSync as P,rmSync as y,statSync as T}from"node:fs";import{join as d}from"node:path";import{validateCommandManifest as ue}from"../../api/command-manifest/manifest.js";import{crtrHome as W}from"../canvas/paths.js";import{withCanvasWrite as z}from"../canvas/db.js";import{bundleVersion as de,isInstalledGeneration as ce,recordCheckedGeneration as le}from"../command-plugins/bundle.js";import{readState as fe,updateConfig as pe,updateState as me}from"../config.js";import{directoryIssuer as G}from"../directory/issuer.js";import{emitEvent as m}from"../events/emit.js";import{describeOutboundFailure as ve,outboundFetch as he,outboundRefusal as L,OutboundError as ge}from"../events/outbound.js";import{withExclusiveDirectoryLockAsync as q}from"../exclusive-lock.js";import{atomicWriteText as A,ensureDir as x,pathExists as we}from"../fs-utils.js";import{reconcilePackages as Z}from"../graph/package-reconcile.js";import{readPluginManifest as j}from"../manifest.js";import{bundleSwapLockPath as V}from"../plugin-swap-lock.js";import{pluginsDir as $e,userScopeRoot as J}from"../scope.js";import{listInstalledPlugins as ye}from"../resolver.js";import{localGrants as C,providerIdsFromGrants as K}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const be="[A-Za-z0-9_-]{1,64}",Q=new RegExp(`^${be}$`),_e=3e4,X=3e4;function v(e){return d($e("user"),e)}a(v,"pluginRoot");function D(){return d(W(),"providers")}a(D,"providersRoot");function Y(e,n){return d(D(),e,`v${n}`)}a(Y,"majorDir");function B(e){if(!Q.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}a(B,"assertId");function M(){const e=G();if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e}a(M,"directoryBase");async function ee(e,n){const r=`${M()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await he("bundle_fetch",r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout(_e)})}catch(i){return{status:"failed",message:`could not reach ${r}: ${i instanceof Error?i.message:String(i)}`,cause:i}}if(t.status===304){if(n.ifNoneMatch===void 0){const i=`HTTP 304 from ${r} without a conditional request`;return{status:"failed",message:i,cause:L("bundle_fetch",r,i)}}return{status:304}}if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300){await t.body?.cancel().catch(()=>{});{const i=`HTTP ${t.status} from ${r}`;return{status:"failed",message:i,cause:L("bundle_fetch",r,i)}}}let o;try{o=new Uint8Array(await t.arrayBuffer())}catch(i){return{status:"failed",message:`reading ${r} failed: ${i instanceof Error?i.message:String(i)}`,cause:new ge("bundle_fetch",r,i)}}const s=t.headers.get("etag");return{status:200,raw:o,...s!==null?{etag:s}:{}}}a(ee,"fetchProviderBundle");const E=new WeakSet;class I extends Error{static{a(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function ne(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(o=>r[o]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}a(ne,"wrongBundle");function N(e,n,r){m({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof I?{issues:r.issues}:{}},error:r})}a(N,"logInvalid");function re(e,n,r){m({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r instanceof Error?r.message:String(r),...ve(r instanceof Error?r.cause:void 0)}})}a(re,"logFailure");async function te(){return import("../../commands/pkg/plugin-manage.js")}a(te,"pluginManage");const b=new Map,_=a(e=>`${W()}\0${e}`,"installKey");function Se(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}a(Se,"publicInstallCause");function Pe(e){if(h(e)===void 0)return b.get(_(e))??{status:"installing"}}a(Pe,"providerInstallState");function Me(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${Pe(e)?.error??"bundle installation pending"}`)}a(Me,"unavailableProviderError");function h(e){const n=j(v(e));if(!(n?.provider===void 0||n.transport?.kind!=="http"&&n.transport?.kind!=="machine")&&we(d(v(e),"commands.json"))){try{if(T(d(v(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:n.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:n.transport.endpoint}}}}a(h,"installedManifest");async function R(e,n,r=!1){const t=J();h(e)===void 0&&b.set(_(e),{status:"installing"});try{return x(d(t,"tmp")),await q(V(t,e),async()=>{const o=v(e),s=j(o);if(s!==null&&s.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const i=h(e)!==void 0;if(i&&r)return"unchanged";const l=i&&n?fe("user").plugins[e]?.etag:void 0,u=await ee(e,l!==void 0?{ifNoneMatch:l}:{});if(u.status===304)return"unchanged";if(u.status===404||u.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${u.message})`,{param:"provider"});if(u.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${u.message}`,{cause:u.cause});const f=de(u.raw);if(i&&ce(e,"user",o,f))return await le("user",e,u.etag,{swapped:!1}),"unchanged";const{installPluginArchive:w}=await te();try{await w(e,u.raw,{scope:"user",scopeRootPath:t,root:o,version:f,etag:u.etag,enable:!i,bundle:{endpoint:`${M()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:M()},accept:a(p=>ne(e,void 0,p),"accept")})}catch(p){N(e,void 0,p);const F=new c("not_found",`provider "${e}" served an invalid bundle: ${p instanceof Error?p.message:String(p)}`,{param:"provider"});throw E.add(F),F}try{await z(async p=>await Z(p))}catch(p){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:p})}return m({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:f,replaced:i}}),b.delete(_(e)),i?"updated":"installed"},{timeoutMs:X,timeoutError:a(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(o){throw h(e)===void 0&&b.set(_(e),{status:"install_failed",error:Se(o)}),o instanceof c?o:(m({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:o}),Me(e))}}a(R,"refreshInstalled");async function nn(e){B(e),h(e)===void 0&&await R(e,!1,!0)}a(nn,"ensureProviderBundle");async function rn(e,n){return B(e),n.version!==void 0&&h(e)?.provider.major!==n.version?H(e,n.version,n.conditional):R(e,n.conditional)}a(rn,"refreshProviderBundle");async function oe(e,n,r){const{validatePluginArchive:t}=await te(),o=await t(r);if(o.bundle===void 0)throw new I(`provider "${e}" major ${n} bundle is invalid: ${o.issues.map(i=>i.message).join("; ")}`,o.issues);const s=ne(e,n,o.bundle);if(s!==void 0)throw new I(`provider "${e}" major ${n} bundle is invalid: ${s}`,[]);if(o.bundle.transport===void 0)throw new I(`provider "${e}" major ${n} bundle declares no transport`,[]);return o.bundle}a(oe,"validateArchive");function Ee(e){x(e),A(d(e,"retired"),`${new Date().toISOString()}
2
- `),y(d(e,"bundle.tar"),{force:!0}),y(d(e,"etag"),{force:!0})}a(Ee,"retire");function ae(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}a(ae,"retiredError");async function H(e,n,r){const t=Y(e,n),o=d(t,"bundle.tar"),s=$(o),i=s&&r&&$(d(t,"etag"))?P(d(t,"etag"),"utf8"):void 0,l=await ee(e,{version:n,...i!==void 0?{ifNoneMatch:i}:{}});if(l.status===304)return"unchanged";if(l.status===410)throw Ee(t),m({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),ae(e,n);if(l.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(l.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${l.message}`,{cause:l.cause});try{await oe(e,n,l.raw)}catch(f){N(e,n,f);const w=new c(s?"provider_unavailable":"not_found",f instanceof Error?f.message:String(f),{param:"version"});throw E.add(w),w}x(t),y(d(t,"retired"),{force:!0});const u=s&&Buffer.from(l.raw).equals(P(o));return u||A(o,l.raw),l.etag!==void 0?A(d(t,"etag"),l.etag):y(d(t,"etag"),{force:!0}),u?"unchanged":s?"updated":"installed"}a(H,"refreshPinned");function Ie(){const e=[],n=D();if(!$(n))return e;for(const r of U(n)){if(!Q.test(r))continue;let t;try{t=U(d(n,r))}catch{continue}for(const o of t){const s=/^v([1-9][0-9]*)$/.exec(o);s&&$(d(n,r,o,"bundle.tar"))&&e.push([r,Number(s[1])])}}return e}a(Ie,"cachedMajors");function ke(e){const n=ue(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}a(ke,"readCommands");const S=new Map,O=new Map;function Te(e,n){const r=T(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,o=O.get(e);if(o?.stamp===t)return o.commands;const s=ke(JSON.parse(P(n,"utf8")));return O.set(e,{stamp:t,commands:s}),s}a(Te,"installedCommands");async function tn(e,n){B(e);const r=h(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const f=v(e),w=Te(e,d(f,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:w,transport:r.transport,source:"installed",root:f}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=Y(e,n);if($(d(t,"retired")))throw ae(e,n);const o=d(t,"bundle.tar");$(o)||await H(e,n,!1);const s=`${e}/${n}`,i=T(o),l=`${i.mtimeMs}:${i.size}`;let u=S.get(s)?.stamp===l?S.get(s).bundle:void 0;if(u===void 0){try{u=await oe(e,n,new Uint8Array(P(o)))}catch(f){throw N(e,n,f),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}S.set(s,{stamp:l,bundle:u})}return{id:e,major:n,provider:u.provider,commands:u.commands,transport:u.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:u.transport.endpoint},source:"pinned"}}a(tn,"resolveProviderBundle");let g=null;const Ae=4*6e4;function k(e,n){e.stage=n,e.stageAt=Date.now()}a(k,"enter");function xe(e,n){return e?.provider?.id===n&&e.bundle?.endpoint===`${M()}/providers/${encodeURIComponent(n)}/plugin`}a(xe,"isDirectoryBundle");async function ie(e){return K(await C()).includes(e)}a(ie,"grantNames");async function je(e){await q(V(J(),e),async()=>{if(!(await ie(e)||!xe(j(v(e)),e))){y(v(e),{recursive:!0,force:!0}),await pe("user",n=>{delete n.plugins[e]}),await me("user",n=>{delete n.plugins[e]}),y(d(D(),e),{recursive:!0,force:!0}),O.delete(e),b.delete(_(e));for(const n of[...S.keys()])n.startsWith(`${e}/`)&&S.delete(n);try{await z(async n=>await Z(n))}catch(n){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:n})}m({level:"info",event:"daemon.providers.bundle_uninstalled",fields:{provider:e}})}},{timeoutMs:X,timeoutError:a(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}a(je,"uninstallProvider");async function Ce(){if(!(await C()).every(e=>e.status!=="active")){for(const e of ye("user"))if(!(e.manifest.provider===void 0||await ie(e.name)))try{await je(e.name)}catch(n){m({level:"error",event:"daemon.providers.bundle_uninstall_failed",fields:{provider:e.name},error:n})}}}a(Ce,"uninstallDisconnected");async function De(e){if(!G())return;k(e,"reading grants");const n=K(await C());for(const r of n){k(e,`refreshing installed bundle ${r}`);try{await R(r,!0)}catch(t){t instanceof Object&&E.has(t)||re(r,void 0,t)}}k(e,"uninstalling disconnected bundles"),await Ce();for(const[r,t]of Ie()){k(e,`refreshing pinned bundle ${r} v${t}`);try{await H(r,t,!0)}catch(o){if(o instanceof c&&o.code==="provider_version_retired"||o instanceof Object&&E.has(o))continue;re(r,t,o)}}}a(De,"syncOnce");function on(){if(g!==null){g.rerun=!0;const n=Date.now()-g.stageAt;return n>=Ae&&m({level:"error",event:"daemon.providers.sync_stalled",fields:{stage:g.stage,stalled_ms:n}}),g.promise}const e={promise:Promise.resolve(),stage:"starting",stageAt:Date.now(),rerun:!1};return g=e,e.promise=(async()=>{try{do e.rerun=!1,await De(e);while(e.rerun)}finally{g=null}})(),e.promise}a(on,"syncProviderBundles");export{nn as ensureProviderBundle,Pe as providerInstallState,rn as refreshProviderBundle,tn as resolveProviderBundle,on as syncProviderBundles,Me as unavailableProviderError};
1
+ var fe=Object.defineProperty;var o=(e,n)=>fe(e,"name",{value:n,configurable:!0});import{existsSync as b,readdirSync as W,readFileSync as _,rmSync as p,statSync as C}from"node:fs";import{join as d}from"node:path";import{validateCommandManifest as le}from"../../api/command-manifest/manifest.js";import{crtrHome as z}from"../canvas/paths.js";import{isCloudRole as m}from"../canvas/person-state.js";import{withCanvasWrite as pe}from"../canvas/db.js";import{bundleVersion as me,isInstalledGeneration as ve,recordCheckedGeneration as he}from"../command-plugins/bundle.js";import{readState as ge,updateConfig as we,updateState as $e}from"../config.js";import{directoryIssuer as L}from"../directory/issuer.js";import{emitEvent as v}from"../events/emit.js";import{describeOutboundFailure as ye,outboundFetch as be,outboundRefusal as q,OutboundError as _e}from"../events/outbound.js";import{withExclusiveDirectoryLockAsync as Z}from"../exclusive-lock.js";import{atomicWriteText as T,ensureDir as D,pathExists as V}from"../fs-utils.js";import{reconcilePackages as Pe}from"../graph/package-reconcile.js";import{readPluginManifest as k}from"../manifest.js";import{bundleSwapLockPath as J}from"../plugin-swap-lock.js";import{pluginsDir as K,userScopeRoot as Q}from"../scope.js";import{installedProviderPlugins as Se}from"./roots.js";import{allGrants as Ee,localGrants as Me,providerIdsFromGrants as X}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const Te="[A-Za-z0-9_-]{1,64}",Y=new RegExp(`^${Te}$`),ke=3e4,ee=3e4;function h(e){return d(K("user"),e)}o(h,"pluginRoot");function P(e){return d(K("user"),`.${e}.etag`)}o(P,"etagFile");function Ie(e){if(!m())return ge("user").plugins[e]?.etag;try{return _(P(e),"utf8")}catch(n){if(n.code==="ENOENT")return;throw n}}o(Ie,"storedEtag");async function ne(e,n){if(!m())return he("user",e,n,{swapped:!1});n===void 0?p(P(e),{force:!0}):T(P(e),n)}o(ne,"recordEtag");async function re(e){if(!m())try{await pe(async n=>await Pe(n))}catch(n){v({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:n})}}o(re,"reconcileProviderDocs");function Ae(e,n,r){return m()?k(n)?.version===r&&V(d(n,"commands.json")):ve(e,"user",n,r)}o(Ae,"installedGeneration");function N(){return d(z(),"providers")}o(N,"providersRoot");function te(e,n){return d(N(),e,`v${n}`)}o(te,"majorDir");function R(e){if(!Y.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}o(R,"assertId");function I(){const e=L();if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e}o(I,"directoryBase");async function oe(e,n){const r=`${I()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await be("bundle_fetch",r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout(ke)})}catch(i){return{status:"failed",message:`could not reach ${r}: ${i instanceof Error?i.message:String(i)}`,cause:i}}if(t.status===304){if(n.ifNoneMatch===void 0){const i=`HTTP 304 from ${r} without a conditional request`;return{status:"failed",message:i,cause:q("bundle_fetch",r,i)}}return{status:304}}if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300){await t.body?.cancel().catch(()=>{});{const i=`HTTP ${t.status} from ${r}`;return{status:"failed",message:i,cause:q("bundle_fetch",r,i)}}}let a;try{a=new Uint8Array(await t.arrayBuffer())}catch(i){return{status:"failed",message:`reading ${r} failed: ${i instanceof Error?i.message:String(i)}`,cause:new _e("bundle_fetch",r,i)}}const s=t.headers.get("etag");return{status:200,raw:a,...s!==null?{etag:s}:{}}}o(oe,"fetchProviderBundle");const A=new WeakSet;class x extends Error{static{o(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function ae(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(a=>r[a]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}o(ae,"wrongBundle");function B(e,n,r){v({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof x?{issues:r.issues}:{}},error:r})}o(B,"logInvalid");function ie(e,n,r){v({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r instanceof Error?r.message:String(r),...ye(r instanceof Error?r.cause:void 0)}})}o(ie,"logFailure");async function se(){return import("../../commands/pkg/plugin-manage.js")}o(se,"pluginManage");const S=new Map,E=o(e=>`${z()}\0${e}`,"installKey");function xe(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}o(xe,"publicInstallCause");function je(e){if(g(e)===void 0)return S.get(E(e))??{status:"installing"}}o(je,"providerInstallState");function Ce(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${je(e)?.error??"bundle installation pending"}`)}o(Ce,"unavailableProviderError");function g(e){const n=k(h(e));if(!(n?.provider===void 0||n.transport?.kind!=="http"&&n.transport?.kind!=="machine")&&V(d(h(e),"commands.json"))){try{if(C(d(h(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:n.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:n.transport.endpoint}}}}o(g,"installedManifest");async function O(e,n,r=!1){const t=Q();g(e)===void 0&&S.set(E(e),{status:"installing"});try{return D(d(t,"tmp")),await Z(J(t,e),async()=>{const a=h(e),s=k(a);if(s!==null&&s.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const i=g(e)!==void 0;if(i&&r)return"unchanged";const f=i&&n?Ie(e):void 0,u=await oe(e,f!==void 0?{ifNoneMatch:f}:{});if(u.status===304)return"unchanged";if(u.status===404||u.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${u.message})`,{param:"provider"});if(u.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${u.message}`,{cause:u.cause});const l=me(u.raw);if(i&&Ae(e,a,l))return await ne(e,u.etag),"unchanged";const{installPluginArchive:$}=await se();m()&&p(P(e),{force:!0});try{await $(e,u.raw,{scope:"user",scopeRootPath:t,root:a,version:l,etag:u.etag,enable:!i,bundle:{endpoint:`${I()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:I()},accept:o(y=>ae(e,void 0,y),"accept"),record:!m()})}catch(y){B(e,void 0,y);const U=new c("not_found",`provider "${e}" served an invalid bundle: ${y instanceof Error?y.message:String(y)}`,{param:"provider"});throw A.add(U),U}return m()&&await ne(e,u.etag),await re(e),v({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:l,replaced:i}}),S.delete(E(e)),i?"updated":"installed"},{timeoutMs:ee,timeoutError:o(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(a){throw g(e)===void 0&&S.set(E(e),{status:"install_failed",error:xe(a)}),a instanceof c?a:(v({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:a}),Ce(e))}}o(O,"refreshInstalled");async function fn(e){R(e),g(e)===void 0&&await O(e,!1,!0)}o(fn,"ensureProviderBundle");async function ln(e,n){return R(e),n.version!==void 0&&g(e)?.provider.major!==n.version?H(e,n.version,n.conditional):O(e,n.conditional)}o(ln,"refreshProviderBundle");async function ue(e,n,r){const{validatePluginArchive:t}=await se(),a=await t(r);if(a.bundle===void 0)throw new x(`provider "${e}" major ${n} bundle is invalid: ${a.issues.map(i=>i.message).join("; ")}`,a.issues);const s=ae(e,n,a.bundle);if(s!==void 0)throw new x(`provider "${e}" major ${n} bundle is invalid: ${s}`,[]);if(a.bundle.transport===void 0)throw new x(`provider "${e}" major ${n} bundle declares no transport`,[]);return a.bundle}o(ue,"validateArchive");function De(e){D(e),T(d(e,"retired"),`${new Date().toISOString()}
2
+ `),p(d(e,"bundle.tar"),{force:!0}),p(d(e,"etag"),{force:!0})}o(De,"retire");function de(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}o(de,"retiredError");async function H(e,n,r){const t=te(e,n),a=d(t,"bundle.tar"),s=b(a),i=s&&r&&b(d(t,"etag"))?_(d(t,"etag"),"utf8"):void 0,f=await oe(e,{version:n,...i!==void 0?{ifNoneMatch:i}:{}});if(f.status===304)return"unchanged";if(f.status===410)throw De(t),v({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),de(e,n);if(f.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(f.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${f.message}`,{cause:f.cause});try{await ue(e,n,f.raw)}catch(l){B(e,n,l);const $=new c(s?"provider_unavailable":"not_found",l instanceof Error?l.message:String(l),{param:"version"});throw A.add($),$}D(t),p(d(t,"retired"),{force:!0});const u=s&&Buffer.from(f.raw).equals(_(a));return u||T(a,f.raw),f.etag!==void 0?T(d(t,"etag"),f.etag):p(d(t,"etag"),{force:!0}),u?"unchanged":s?"updated":"installed"}o(H,"refreshPinned");function Ne(){const e=[],n=N();if(!b(n))return e;for(const r of W(n)){if(!Y.test(r))continue;let t;try{t=W(d(n,r))}catch{continue}for(const a of t){const s=/^v([1-9][0-9]*)$/.exec(a);s&&b(d(n,r,a,"bundle.tar"))&&e.push([r,Number(s[1])])}}return e}o(Ne,"cachedMajors");function Re(e){const n=le(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}o(Re,"readCommands");const M=new Map,F=new Map;function Be(e,n){const r=C(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,a=F.get(e);if(a?.stamp===t)return a.commands;const s=Re(JSON.parse(_(n,"utf8")));return F.set(e,{stamp:t,commands:s}),s}o(Be,"installedCommands");async function pn(e,n){R(e);const r=g(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const l=h(e),$=Be(e,d(l,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:$,transport:r.transport,source:"installed",root:l}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=te(e,n);if(b(d(t,"retired")))throw de(e,n);const a=d(t,"bundle.tar");b(a)||await H(e,n,!1);const s=`${e}/${n}`,i=C(a),f=`${i.mtimeMs}:${i.size}`;let u=M.get(s)?.stamp===f?M.get(s).bundle:void 0;if(u===void 0){try{u=await ue(e,n,new Uint8Array(_(a)))}catch(l){throw B(e,n,l),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}M.set(s,{stamp:f,bundle:u})}return{id:e,major:n,provider:u.provider,commands:u.commands,transport:u.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:u.transport.endpoint},source:"pinned"}}o(pn,"resolveProviderBundle");let w=null;const Oe=4*6e4;function j(e,n){e.stage=n,e.stageAt=Date.now()}o(j,"enter");function He(e,n){return e?.provider?.id===n&&e.bundle?.endpoint===`${I()}/providers/${encodeURIComponent(n)}/plugin`}o(He,"isDirectoryBundle");async function G(){return m()?Ee():Me()}o(G,"bundleGrants");async function ce(e){return X(await G()).includes(e)}o(ce,"grantNames");async function Fe(e){await Z(J(Q(),e),async()=>{if(!(await ce(e)||!He(k(h(e)),e))){p(h(e),{recursive:!0,force:!0}),m()?p(P(e),{force:!0}):(await we("user",n=>{delete n.plugins[e]}),await $e("user",n=>{delete n.plugins[e]})),p(d(N(),e),{recursive:!0,force:!0}),F.delete(e),S.delete(E(e));for(const n of[...M.keys()])n.startsWith(`${e}/`)&&M.delete(n);await re(e),v({level:"info",event:"daemon.providers.bundle_uninstalled",fields:{provider:e}})}},{timeoutMs:ee,timeoutError:o(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}o(Fe,"uninstallProvider");async function Ge(){if(!(await G()).every(e=>e.status!=="active")){for(const e of Se())if(!(e.manifest.provider===void 0||await ce(e.name)))try{await Fe(e.name)}catch(n){v({level:"error",event:"daemon.providers.bundle_uninstall_failed",fields:{provider:e.name},error:n})}}}o(Ge,"uninstallDisconnected");async function Ue(e){if(!L())return;j(e,"reading grants");const n=X(await G());for(const r of n){j(e,`refreshing installed bundle ${r}`);try{await O(r,!0)}catch(t){t instanceof Object&&A.has(t)||ie(r,void 0,t)}}j(e,"uninstalling disconnected bundles"),await Ge();for(const[r,t]of Ne()){j(e,`refreshing pinned bundle ${r} v${t}`);try{await H(r,t,!0)}catch(a){if(a instanceof c&&a.code==="provider_version_retired"||a instanceof Object&&A.has(a))continue;ie(r,t,a)}}}o(Ue,"syncOnce");function mn(){if(w!==null){w.rerun=!0;const n=Date.now()-w.stageAt;return n>=Oe&&v({level:"error",event:"daemon.providers.sync_stalled",fields:{stage:w.stage,stalled_ms:n}}),w.promise}const e={promise:Promise.resolve(),stage:"starting",stageAt:Date.now(),rerun:!1};return w=e,e.promise=(async()=>{try{do e.rerun=!1,await Ue(e);while(e.rerun)}finally{w=null}})(),e.promise}o(mn,"syncProviderBundles");export{fn as ensureProviderBundle,je as providerInstallState,ln as refreshProviderBundle,pn as resolveProviderBundle,mn as syncProviderBundles,Ce as unavailableProviderError};
@@ -1 +1 @@
1
- var de=Object.defineProperty;var m=(e,r)=>de(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as x}from"../../api/command-manifest/result.js";import{callerAllows as ue,requireGroup as le}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as pe}from"../grants/terminal.js";import{findRefusal as ce,payerOf as fe,refusalError as me,refusedMark as ve,writeCharge as ge}from"../ledger/index.js";import{listInstalledPlugins as he}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as we}from"./roots.js";import{providerToolPath as ye}from"../plugin-objects-manifest.js";import{ensureProviderBundle as be,refreshProviderBundle as X,resolveProviderBundle as O,unavailableProviderError as _e}from"./bundles.js";import{prepareFileCall as Ae,resignForRetry as Y,resolveFileResult as Z}from"./files.js";import{consumeApproval as je,requireProviderApproval as ke}from"./approval.js";import{outboundToken as Pe}from"./mint.js";import{discardFile as $e}from"./token-cache.js";import{registerProviderCall as qe}from"./inflight.js";import{buildRequestPlan as Ce}from"../command-plugins/transport/http-plan.js";import{newTraceId as Ee}from"../../shared/traceparent.js";import{sendProviderRequest as Re,ProviderTransportError as Te}from"./request.js";import{acceptProviderReceipt as Ie}from"./receipts.js";import{writeProviderAudit as Me}from"./audit.js";import{selectDevice as Se,sendDeviceCall as Be,deviceFailure as Ne,deviceUnreachable as ee,DEFAULT_DEVICE_REQUEST_MS as Oe}from"./device.js";import{isLibsSearch as re,wantsBundling as Fe,callLibsSearch as De,bundleExec as Ue,mapLibOutcome as Le,reportLibCalls as Je}from"./device-libs.js";import{ownMachineId as He}from"../peer/directory.js";import{directoryIssuer as xe}from"../directory/issuer.js";import{formatCrtrCaller as te}from"../command-plugins/caller-header.js";import{getNode as Ge}from"../canvas/canvas.js";import{envelopeForProviderCaller as ze}from"../peer/envelope.js";const Qe="app:terminal";function oe(e){const r=[],n=m((c,t,i)=>{const s=[...t,c.name],d=i||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)n(v,s,d);return}const j=ye(e.roots.length,s);r.push({tool:j,leaf:c,hidden:d})},"walk");for(const c of e.roots)n(c,[],!1);return r}m(oe,"providerLeaves");function ie(e){if(e.kind!=="branch")return null;const r=[];for(const g of e.children)if(g.kind==="branch"){const b=ie(g);b&&r.push(b)}else if("group"in g&&g.group){const{kind:b,name:u,description:_,whenToUse:h,tier:w,summary:k,params:P,output:o,effects:p,group:A}=g;r.push({kind:b,name:u,description:_,whenToUse:h,...w===void 0?{}:{tier:w},summary:k,params:P,output:o,effects:p,group:A})}if(r.length===0)return null;const{kind:n,name:c,description:t,whenToUse:i,tier:s,summary:d,model:j,rootEntry:v}=e;return{kind:n,name:c,description:t,whenToUse:i,...s===void 0?{}:{tier:s},summary:d,...j===void 0?{}:{model:j},...v===void 0?{}:{rootEntry:v},children:r}}m(ie,"providerHelpBranch");async function Cr(e,r){const n=await O(r),c=oe(n.commands),t=he("user").find(i=>i.name===r)?.manifest.description??r;return{provider:r,status:"available",major:n.major,display_name:t,transport:n.transport.kind,groups:n.provider.groups.filter(i=>ue(e,`${r}:${i.group}`)).map(i=>({group:i.group,leaves:c.filter(({leaf:s,hidden:d})=>!d&&s.group===i.group).map(({tool:s,leaf:d})=>({tool:s,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:n.commands.roots.flatMap(i=>{const s=ie(i);return s?[s]:[]})}}m(Cr,"providerTools");async function Ve(e){return await Ie(e.headers["crtr-receipt"],e)}m(Ve,"onProviderResponse");async function Ke(e){if(e.class==="person"){const r=(await pe())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}m(Ke,"identity");function We(e,r){return[`${e.id}:${r.group}`]}m(We,"callScope");function Xe(e,r){const n=oe(e.commands).find(c=>c.tool===r);if(!n)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!n.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return n.leaf}m(Xe,"leafFor");function G(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}m(G,"errorBody");function Ye(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const n=Number(r);if(Number.isFinite(n)&&n>=0)return n;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}m(Ye,"retryAfter");function F(e,r,n,c=!1){const t=G(r),i=typeof t.code=="string"?t.code:void 0,s=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,v={origin:"provider",details:{code:i??null,message:s,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new l("provider_rate_limited",s,{...v,retry_after_s:Ye(n["retry-after"])}):e===401||e>=500?new l("provider_unavailable",s,v):e===403&&i==="provider_refused"?new l("provider_refused",s,v):e===403&&i==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",s,{...v,status:e})}m(F,"mapProviderResponse");function ne(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}m(ne,"approvalShape");async function Ze(e){const r=e.origin!==void 0?te({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):te({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await Ge(e.node_id))?.profile_id??void 0:void 0,machine:xe()!==null?He():void 0});return r===""?{}:{"Crtr-Caller":r}}m(Ze,"crtrCallerHeader");async function Er(e,r,n){const c=we(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},i=new AbortController,s=m(()=>i.abort(n.signal.reason),"abort");n.signal.aborted?s():n.signal.addEventListener("abort",s,{once:!0});let d=n.requestId;const j=n.traceId??Ee(),v=qe({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:i});let g,b,u,_,h,w,k,P="allowed";try{try{await be(t.provider)}catch{throw _e(t.provider)}let o=await O(t.provider,t.version),p=!1,A=!1,$,D,C,z=!1,Q=!1,U,V=0;for(;;){const y=Xe(o,t.tool);if(u=`${o.id}:${y.group}`,le(e,o.id,y.group),o.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&U===void 0&&(U=await Se(t.machine,void 0,{newest:re(o.major,t.tool)}),V=Date.now()+(o.commands.timeouts?.requestMs??Oe));let L=null;if(t.approval&&!z){const a=await je(e,t,ne(o,y));C=a.option,L=a.prepared,k=t.approval,d=a.requestId,z=!0}const M={params:y.params.filter(a=>"type"in a&&a.type==="file").map(a=>a.name),output:y.output.find(a=>a.type==="file")?.name??null},K=JSON.stringify(M);if(D!==void 0&&D!==K)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=K,L&&($=await Y(e,M,t.arguments,L,{signal:i.signal})),$??=await Ae(e,M,t.arguments,{signal:i.signal});const{sub:R,grantee:S}=await Ke(e);if(o.transport.kind==="machine"){const a=await er(e,o,t,y,$,{sub:R,requestId:d,deadlineAt:V,signal:i.signal,machine:U});return w=a.responder,g=a.cleanup,{status:200,body:a.result}}const W=o.transport.endpoint;let E;try{E=await Pe({audience:W,sub:R,grantee:S,initiating_app:S,scope:We(o,y)},{signal:i.signal})}catch(a){if(!(a instanceof l)||a.details?.directory_error!=="invalid_target"||A)throw a;A=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}});const q=await O(o.id,t.version);if(q.transport.kind==="machine"||q.transport.endpoint===W)throw a;o=q;continue}_=E.jti;const J=e.class==="person"?Qe:S,T=fe({call:"tool",tokenPayer:E.payer,sub:R}),H=await ce({scope:"call",payer:T.payer,funding:T.funding,sub:R,grantee:J,provider:`app:${o.id}`});if(H!==null)throw await ge({request:d,kind:"tool",what:`${o.id}:${t.tool}`,usd:0,payer:T.payer,funding:T.funding,sub:R,grantee:J,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:n.causedBy??null,refused:ve(H)}),me(H);const ae={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[o.id,...t.tool.split(" ")]},se=Ce(ae,$.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,traceId:j,fileMode:"pass-through",extraHeaders:{...n.causedBy?{"Crtr-Caused-By":n.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Ze(e),...C?{"Crtr-Approval":C}:{},...$.headers}});b??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Re(se,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:b,signal:i.signal}),i.signal.aborted)throw i.signal.reason??new Error("provider call aborted")}catch(a){throw i.signal.aborted?i.signal.reason??a:a instanceof Te?new l("provider_unavailable",a.message,{origin:"provider",details:{status:null,code:a.kind}}):a}if(h??=await Ve({provider:o.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:R,grantee:S,payer:E.payer,ledger_grantee:J,funding:T.funding,node_id:e.node_id,caused_by:n.causedBy??null,jti:E.jti,status:f.status,headers:f.headers}),w=f.headers["crtr-responder"],f.status===401&&$e(E.key),f.status>=200&&f.status<300){const a=f.body;if(!a||typeof a!="object"||Array.isArray(a))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let q;try{q=await Z(e,$,a,{signal:i.signal})}catch(I){throw I instanceof l&&I.code==="provider_error"?new l("provider_bad_response",I.message,{origin:"provider",details:{status:f.status,message:I.message}}):I}g=q.cleanup;const N=x(y.output,q.result);if(N)throw new l("provider_bad_response",`provider result has an invalid output field "${N.field}"`,{origin:"provider",param:N.field,details:{status:f.status,...N}});if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");return{status:200,body:q.result}}const B=G(f.body);if(f.status===403&&B.code==="approval_required"&&!C&&!Q){Q=!0;const a=await ke(e,t,d,B.question,i.signal,ne(o,y),$);if(k=a.questionId,C=a.option,$=await Y(e,M,t.arguments,$,{signal:i.signal}),b=void 0,i.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&B.code==="approval_required"&&C)throw F(f.status,f.body,f.headers,!0);if(f.status!==401&&B.manifest_stale===!0&&!p){p=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),o=await O(o.id,t.version);continue}throw F(f.status,f.body,f.headers,!!C)}}catch(o){throw o instanceof l&&o.question_id&&(k=o.question_id),w===void 0&&o instanceof l&&typeof o.responder=="string"&&(w=o.responder),P=`refused:${o instanceof l?o.code:"server_error"}`,await g?.(),o}finally{try{await Me({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:u,outcome:P,jti:_,receipt_id:h,responder:w,question_id:k})}finally{v()}n.signal.removeEventListener("abort",s)}}m(Er,"callProvider");async function er(e,r,n,c,t,i){const{machine:s}=i,d=await ze(e,i.sub),j={machine:s,envelope:d,signal:i.signal,deadlineAt:i.deadlineAt,mapFailure:F};if(re(r.major,n.tool)){const p=await De(j,t.arguments,r.major),A=x(c.output,p);if(A)throw new l("provider_bad_response",`the libraries result has an invalid output field "${A.field}"`,{origin:"provider",param:A.field,details:{status:200,...A}});return{result:p,responder:void 0,cleanup:void 0}}let v=t.arguments,g=null,b="";if(Fe(r.major,n.tool,t.arguments)){const p=await Ue(j,t.arguments,r.major);if(i.deadlineAt-Date.now()<=0)throw ee(s,"timeout","");p!==null&&(v=p.arguments,g=p.services,b=p.release)}const u=await Be(s,{tool:n.tool,arguments:v,version:r.major,requestId:i.requestId,runId:e.run_id,deadlineAt:i.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,i.signal);if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw ee(s,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],h=G(u.body);if(u.status<200||u.status>=300){const p=Ne(s,u.status,typeof h.code=="string"?h.code:void 0,typeof h.message=="string"?h.message:void 0,u.body),A=p===null&&u.status>=500&&typeof h.code=="string"?new l("provider_error",typeof h.message=="string"?h.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:h.code,status:u.status}}):null;throw Object.assign(p??A??F(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let k=w;if(g!==null){const p=Le(k,g);if(Je(s,d,b,p.calls),"error"in p)throw Object.assign(p.error,{responder:_});k=p.result}let P;try{P=await Z(e,t,k,{signal:i.signal})}catch(p){throw p instanceof l&&p.code==="provider_error"?Object.assign(new l("provider_bad_response",p.message,{origin:"provider",details:{status:u.status,message:p.message}}),{responder:_}):p}const o=x(c.output,P.result);if(o)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:u.status,...o}}),{responder:_});return{result:P.result,responder:_,cleanup:P.cleanup}}m(er,"callDevice");export{Er as callProvider,Ze as crtrCallerHeader,Ke as identity,F as mapProviderResponse,Ve as onProviderResponse,oe as providerLeaves,Cr as providerTools};
1
+ var de=Object.defineProperty;var m=(e,r)=>de(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as x}from"../../api/command-manifest/result.js";import{callerAllows as ue,requireGroup as le}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as pe}from"../grants/terminal.js";import{findRefusal as ce,payerOf as fe,refusalError as me,refusedMark as ve,writeCharge as ge}from"../ledger/index.js";import{listInstalledPlugins as he}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as we}from"./roots.js";import{providerToolPath as ye}from"../plugin-objects-manifest.js";import{ensureProviderBundle as be,refreshProviderBundle as X,resolveProviderBundle as O,unavailableProviderError as _e}from"./bundles.js";import{prepareFileCall as Ae,resignForRetry as Y,resolveFileResult as Z}from"./files.js";import{consumeApproval as je,requireProviderApproval as ke}from"./approval.js";import{outboundToken as Pe}from"./mint.js";import{discardFile as $e}from"./token-cache.js";import{registerProviderCall as Ee}from"./inflight.js";import{buildRequestPlan as qe}from"../command-plugins/transport/http-plan.js";import{newTraceId as Ce}from"../../shared/traceparent.js";import{sendProviderRequest as Re,ProviderTransportError as Te}from"./request.js";import{acceptProviderReceipt as Ie}from"./receipts.js";import{writeProviderAudit as Me}from"./audit.js";import{selectDevice as Se,sendDeviceCall as Be,deviceFailure as Ne,deviceUnreachable as ee,DEFAULT_DEVICE_REQUEST_MS as Oe}from"./device.js";import{isLibsSearch as re,wantsBundling as Fe,callLibsSearch as De,bundleExec as Ue,mapLibOutcome as Le,reportLibCalls as Je}from"./device-libs.js";import{ownMachineId as He}from"../peer/directory.js";import{directoryIssuer as xe}from"../directory/issuer.js";import{formatCrtrCaller as te}from"../command-plugins/caller-header.js";import{getNode as Ge}from"../canvas/canvas.js";import{envelopeForProviderCaller as ze,EnvelopeError as Qe}from"../peer/envelope.js";const Ve="app:terminal";function oe(e){const r=[],n=m((c,t,i)=>{const u=[...t,c.name],s=i||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)n(v,u,s);return}const j=ye(e.roots.length,u);r.push({tool:j,leaf:c,hidden:s})},"walk");for(const c of e.roots)n(c,[],!1);return r}m(oe,"providerLeaves");function ie(e){if(e.kind!=="branch")return null;const r=[];for(const g of e.children)if(g.kind==="branch"){const b=ie(g);b&&r.push(b)}else if("group"in g&&g.group){const{kind:b,name:p,description:_,whenToUse:h,tier:w,summary:k,params:P,output:o,effects:d,group:A}=g;r.push({kind:b,name:p,description:_,whenToUse:h,...w===void 0?{}:{tier:w},summary:k,params:P,output:o,effects:d,group:A})}if(r.length===0)return null;const{kind:n,name:c,description:t,whenToUse:i,tier:u,summary:s,model:j,rootEntry:v}=e;return{kind:n,name:c,description:t,whenToUse:i,...u===void 0?{}:{tier:u},summary:s,...j===void 0?{}:{model:j},...v===void 0?{}:{rootEntry:v},children:r}}m(ie,"providerHelpBranch");async function Cr(e,r){const n=await O(r),c=oe(n.commands),t=he("user").find(i=>i.name===r)?.manifest.description??r;return{provider:r,status:"available",major:n.major,display_name:t,transport:n.transport.kind,groups:n.provider.groups.filter(i=>ue(e,`${r}:${i.group}`)).map(i=>({group:i.group,leaves:c.filter(({leaf:u,hidden:s})=>!s&&u.group===i.group).map(({tool:u,leaf:s})=>({tool:u,description:s.description,summary:s.summary,params:s.params,output:s.output}))})),commands:n.commands.roots.flatMap(i=>{const u=ie(i);return u?[u]:[]})}}m(Cr,"providerTools");async function Ke(e){return await Ie(e.headers["crtr-receipt"],e)}m(Ke,"onProviderResponse");async function We(e){if(e.class==="person"){const r=(await pe())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}m(We,"identity");function Xe(e,r){return[`${e.id}:${r.group}`]}m(Xe,"callScope");function Ye(e,r){const n=oe(e.commands).find(c=>c.tool===r);if(!n)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!n.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return n.leaf}m(Ye,"leafFor");function G(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}m(G,"errorBody");function Ze(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const n=Number(r);if(Number.isFinite(n)&&n>=0)return n;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}m(Ze,"retryAfter");function F(e,r,n,c=!1){const t=G(r),i=typeof t.code=="string"?t.code:void 0,u=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,s=typeof t.field=="string"?t.field:void 0,v={origin:"provider",details:{code:i??null,message:u,...s?{field:s}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...s?{param:s}:{}};return e===429?new l("provider_rate_limited",u,{...v,retry_after_s:Ze(n["retry-after"])}):e===401||e>=500?new l("provider_unavailable",u,v):e===403&&i==="provider_refused"?new l("provider_refused",u,v):e===403&&i==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",u,{...v,status:e})}m(F,"mapProviderResponse");function ne(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}m(ne,"approvalShape");async function er(e){const r=e.origin!==void 0?te({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):te({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await Ge(e.node_id))?.profile_id??void 0:void 0,machine:xe()!==null?He():void 0});return r===""?{}:{"Crtr-Caller":r}}m(er,"crtrCallerHeader");async function Rr(e,r,n){const c=we(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},i=new AbortController,u=m(()=>i.abort(n.signal.reason),"abort");n.signal.aborted?u():n.signal.addEventListener("abort",u,{once:!0});let s=n.requestId;const j=n.traceId??Ce(),v=Ee({request_id:s,run_id:e.run_id,node_id:e.node_id,controller:i});let g,b,p,_,h,w,k,P="allowed";try{try{await be(t.provider)}catch{throw _e(t.provider)}let o=await O(t.provider,t.version),d=!1,A=!1,$,D,q,z=!1,Q=!1,U,V=0;for(;;){const y=Ye(o,t.tool);if(p=`${o.id}:${y.group}`,le(e,o.id,y.group),o.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&U===void 0&&(U=await Se(t.machine,void 0,{newest:re(o.major,t.tool)}),V=Date.now()+(o.commands.timeouts?.requestMs??Oe));let L=null;if(t.approval&&!z){const a=await je(e,t,ne(o,y));q=a.option,L=a.prepared,k=t.approval,s=a.requestId,z=!0}const M={params:y.params.filter(a=>"type"in a&&a.type==="file").map(a=>a.name),output:y.output.find(a=>a.type==="file")?.name??null},K=JSON.stringify(M);if(D!==void 0&&D!==K)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=K,L&&($=await Y(e,M,t.arguments,L,{signal:i.signal})),$??=await Ae(e,M,t.arguments,{signal:i.signal});const{sub:R,grantee:S}=await We(e);if(o.transport.kind==="machine"){const a=await rr(e,o,t,y,$,{sub:R,requestId:s,deadlineAt:V,signal:i.signal,machine:U});return w=a.responder,g=a.cleanup,{status:200,body:a.result}}const W=o.transport.endpoint;let C;try{C=await Pe({audience:W,sub:R,grantee:S,initiating_app:S,scope:Xe(o,y)},{signal:i.signal})}catch(a){if(!(a instanceof l)||a.details?.directory_error!=="invalid_target"||A)throw a;A=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}});const E=await O(o.id,t.version);if(E.transport.kind==="machine"||E.transport.endpoint===W)throw a;o=E;continue}_=C.jti;const J=e.class==="person"?Ve:S,T=fe({call:"tool",tokenPayer:C.payer,sub:R}),H=await ce({scope:"call",payer:T.payer,funding:T.funding,sub:R,grantee:J,provider:`app:${o.id}`});if(H!==null)throw await ge({request:s,kind:"tool",what:`${o.id}:${t.tool}`,usd:0,payer:T.payer,funding:T.funding,sub:R,grantee:J,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:n.causedBy??null,refused:ve(H)}),me(H);const ae={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[o.id,...t.tool.split(" ")]},se=qe(ae,$.arguments,void 0,{authorization:`Bearer ${C.access_token}`,requestId:s,traceId:j,fileMode:"pass-through",extraHeaders:{...n.causedBy?{"Crtr-Caused-By":n.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await er(e),...q?{"Crtr-Approval":q}:{},...$.headers}});b??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Re(se,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:b,signal:i.signal}),i.signal.aborted)throw i.signal.reason??new Error("provider call aborted")}catch(a){throw i.signal.aborted?i.signal.reason??a:a instanceof Te?new l("provider_unavailable",a.message,{origin:"provider",details:{status:null,code:a.kind}}):a}if(h??=await Ke({provider:o.id,tool:t.tool,request_id:s,run_id:e.run_id,sub:R,grantee:S,payer:C.payer,ledger_grantee:J,funding:T.funding,node_id:e.node_id,caused_by:n.causedBy??null,jti:C.jti,status:f.status,headers:f.headers}),w=f.headers["crtr-responder"],f.status===401&&$e(C.key),f.status>=200&&f.status<300){const a=f.body;if(!a||typeof a!="object"||Array.isArray(a))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let E;try{E=await Z(e,$,a,{signal:i.signal})}catch(I){throw I instanceof l&&I.code==="provider_error"?new l("provider_bad_response",I.message,{origin:"provider",details:{status:f.status,message:I.message}}):I}g=E.cleanup;const N=x(y.output,E.result);if(N)throw new l("provider_bad_response",`provider result has an invalid output field "${N.field}"`,{origin:"provider",param:N.field,details:{status:f.status,...N}});if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");return{status:200,body:E.result}}const B=G(f.body);if(f.status===403&&B.code==="approval_required"&&!q&&!Q){Q=!0;const a=await ke(e,t,s,B.question,i.signal,ne(o,y),$);if(k=a.questionId,q=a.option,$=await Y(e,M,t.arguments,$,{signal:i.signal}),b=void 0,i.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&B.code==="approval_required"&&q)throw F(f.status,f.body,f.headers,!0);if(f.status!==401&&B.manifest_stale===!0&&!d){d=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),o=await O(o.id,t.version);continue}throw F(f.status,f.body,f.headers,!!q)}}catch(o){throw o instanceof l&&o.question_id&&(k=o.question_id),w===void 0&&o instanceof l&&typeof o.responder=="string"&&(w=o.responder),P=`refused:${o instanceof l?o.code:"server_error"}`,await g?.(),o}finally{try{await Me({request_id:s,caller:e,provider:t.provider,tool:t.tool,scope_checked:p,outcome:P,jti:_,receipt_id:h,responder:w,question_id:k})}finally{v()}n.signal.removeEventListener("abort",u)}}m(Rr,"callProvider");async function rr(e,r,n,c,t,i){const{machine:u}=i;let s;try{s=await ze(e,i.sub)}catch(d){throw d instanceof Qe?new l("invalid_request",d.message,{origin:"runtime"}):d}const j={machine:u,envelope:s,signal:i.signal,deadlineAt:i.deadlineAt,mapFailure:F};if(re(r.major,n.tool)){const d=await De(j,t.arguments,r.major),A=x(c.output,d);if(A)throw new l("provider_bad_response",`the libraries result has an invalid output field "${A.field}"`,{origin:"provider",param:A.field,details:{status:200,...A}});return{result:d,responder:void 0,cleanup:void 0}}let v=t.arguments,g=null,b="";if(Fe(r.major,n.tool,t.arguments)){const d=await Ue(j,t.arguments,r.major);if(i.deadlineAt-Date.now()<=0)throw ee(u,"timeout","");d!==null&&(v=d.arguments,g=d.services,b=d.release)}const p=await Be(u,{tool:n.tool,arguments:v,version:r.major,requestId:i.requestId,runId:e.run_id,deadlineAt:i.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},s,i.signal);if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");if("unreachable"in p)throw ee(u,p.unreachable.reason,p.unreachable.message);const _=p.headers["crtr-responder"],h=G(p.body);if(p.status<200||p.status>=300){const d=Ne(u,p.status,typeof h.code=="string"?h.code:void 0,typeof h.message=="string"?h.message:void 0,p.body),A=d===null&&p.status>=500&&typeof h.code=="string"?new l("provider_error",typeof h.message=="string"?h.message:`the device answered HTTP ${p.status}`,{origin:"runtime",status:p.status,details:{code:h.code,status:p.status}}):null;throw Object.assign(d??A??F(p.status,p.body,p.headers),{responder:_})}const w=p.body&&typeof p.body=="object"&&!Array.isArray(p.body)?p.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:p.status,message:"the device result is not a JSON object"}}),{responder:_});let k=w;if(g!==null){const d=Le(k,g);if(Je(u,s,b,d.calls),"error"in d)throw Object.assign(d.error,{responder:_});k=d.result}let P;try{P=await Z(e,t,k,{signal:i.signal})}catch(d){throw d instanceof l&&d.code==="provider_error"?Object.assign(new l("provider_bad_response",d.message,{origin:"provider",details:{status:p.status,message:d.message}}),{responder:_}):d}const o=x(c.output,P.result);if(o)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:p.status,...o}}),{responder:_});return{result:P.result,responder:_,cleanup:P.cleanup}}m(rr,"callDevice");export{Rr as callProvider,er as crtrCallerHeader,We as identity,F as mapProviderResponse,Ke as onProviderResponse,oe as providerLeaves,Cr as providerTools};
@@ -4,6 +4,10 @@ import type { InstalledPlugin } from '../../types.js';
4
4
  export declare function rootNameOfCommands(raw: unknown): string | undefined;
5
5
  /** An installed provider plugin's root command name, cached per file replacement. */
6
6
  export declare function installedRootName(plugin: Pick<InstalledPlugin, 'root'>): string | undefined;
7
+ /** The provider bundles this process serves. A cloud role holds one plugin directory for every account it serves, so a bundle there is
8
+ * installed for the deployment, not for a person: the directory's valid provider manifests, with no enabled flag. Anything else lists
9
+ * the user scope's plugins. */
10
+ export declare function installedProviderPlugins(): InstalledPlugin[];
7
11
  export interface ProviderRootClaims {
8
12
  /** root command name → provider id (the earliest-installed claimant). */
9
13
  byRoot: Map<string, string>;
@@ -1 +1 @@
1
- var v=Object.defineProperty;var m=(o,n)=>v(o,"name",{value:n,configurable:!0});import{readFileSync as y,statSync as w}from"node:fs";import{join as S}from"node:path";import{emitEvent as $}from"../events/emit.js";import{readState as h}from"../config.js";import{listInstalledPlugins as p}from"../resolver.js";function g(o){const n=o?.mounts;if(!Array.isArray(n))return;const t=new Set;for(const r of n)Array.isArray(r?.parent)&&r.parent.length===0&&typeof r.node?.name=="string"&&t.add(r.node.name);return t.size===1?[...t][0]:void 0}m(g,"rootNameOfCommands");const u=new Map;function C(o){const n=S(o.root,"commands.json");try{const t=w(n),r=`${t.ino}:${t.mtimeMs}:${t.size}`,d=u.get(n);if(d?.stamp===r)return d.root;const a=g(JSON.parse(y(n,"utf8")));return u.set(n,{stamp:r,root:a}),a}catch{return}}m(C,"installedRootName");const l=new Set;function R(o=p("user")){const n=o.filter(e=>e.enabled&&e.manifest.provider!==void 0&&e.manifest.provider.id===e.name),t=new Map(n.map(e=>[e.name,C(e)])),r=new Set,d=new Set;for(const e of t.values())e!==void 0&&(r.has(e)&&d.add(e),r.add(e));if(d.size>0){const e=h("user").plugins;n.sort((s,i)=>(e[s.name]?.last_updated??"").localeCompare(e[i.name]?.last_updated??"")||s.name.localeCompare(i.name))}const a=new Map,c=new Set;for(const e of n){const s=t.get(e.name);if(s===void 0)continue;const i=a.get(s);if(i===void 0){a.set(s,e.name);continue}c.add(e.name);const f=`${e.name}\0${s}\0${i}`;l.has(f)||(l.add(f),$({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e.name,issues:[{code:"root_command_claimed",message:`root command "${s}" is already served by provider "${i}"; "${e.name}" is skipped`}]}}))}return{byRoot:a,skipped:c}}m(R,"providerRootClaims");function z(o){const n=p("user"),t=R(n);return t.skipped.has(o)?null:n.some(r=>r.name===o&&r.manifest.provider!==void 0)?o:t.byRoot.get(o)??o}m(z,"resolveProviderRef");export{C as installedRootName,R as providerRootClaims,z as resolveProviderRef,g as rootNameOfCommands};
1
+ var w=Object.defineProperty;var m=(o,n)=>w(o,"name",{value:n,configurable:!0});import{readdirSync as h,readFileSync as S,statSync as g}from"node:fs";import{join as u}from"node:path";import{emitEvent as $}from"../events/emit.js";import{isCloudRole as p}from"../canvas/person-state.js";import{readState as C}from"../config.js";import{readPluginManifest as M}from"../manifest.js";import{listInstalledPlugins as R}from"../resolver.js";import{pluginsDir as b}from"../scope.js";function x(o){const n=o?.mounts;if(!Array.isArray(n))return;const e=new Set;for(const r of n)Array.isArray(r?.parent)&&r.parent.length===0&&typeof r.node?.name=="string"&&e.add(r.node.name);return e.size===1?[...e][0]:void 0}m(x,"rootNameOfCommands");const l=new Map;function N(o){const n=u(o.root,"commands.json");try{const e=g(n),r=`${e.ino}:${e.mtimeMs}:${e.size}`,s=l.get(n);if(s?.stamp===r)return s.root;const a=x(JSON.parse(S(n,"utf8")));return l.set(n,{stamp:r,root:a}),a}catch{return}}m(N,"installedRootName");function v(){if(!p())return R("user");const o=b("user");let n;try{n=h(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).sort()}catch(e){if(e.code==="ENOENT")return[];throw e}return n.flatMap(e=>{const r=u(o,e),s=M(r);return s?.provider===void 0?[]:[{name:e,scope:"user",root:r,manifest:s,enabled:!0,version:s.version}]})}m(v,"installedProviderPlugins");const y=new Set;function P(o=v()){const n=o.filter(t=>t.enabled&&t.manifest.provider!==void 0&&t.manifest.provider.id===t.name),e=new Map(n.map(t=>[t.name,N(t)])),r=new Set,s=new Set;for(const t of e.values())t!==void 0&&(r.has(t)&&s.add(t),r.add(t));if(s.size>0){const t=p()?{}:C("user").plugins;n.sort((i,d)=>(t[i.name]?.last_updated??"").localeCompare(t[d.name]?.last_updated??"")||i.name.localeCompare(d.name))}const a=new Map,c=new Set;for(const t of n){const i=e.get(t.name);if(i===void 0)continue;const d=a.get(i);if(d===void 0){a.set(i,t.name);continue}c.add(t.name);const f=`${t.name}\0${i}\0${d}`;y.has(f)||(y.add(f),$({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:t.name,issues:[{code:"root_command_claimed",message:`root command "${i}" is already served by provider "${d}"; "${t.name}" is skipped`}]}}))}return{byRoot:a,skipped:c}}m(P,"providerRootClaims");function T(o){const n=v(),e=P(n);return e.skipped.has(o)?null:n.some(r=>r.name===o&&r.manifest.provider!==void 0)?o:e.byRoot.get(o)??o}m(T,"resolveProviderRef");export{v as installedProviderPlugins,N as installedRootName,P as providerRootClaims,T as resolveProviderRef,x as rootNameOfCommands};
@@ -44,6 +44,10 @@ export declare function acknowledgeBrokerMail(nodeId: string, deliveries: MailRe
44
44
  export declare function recordBrokerTurn(nodeId: string, request: Omit<BrokerTurnRequest, 'expected_execution_id'>): Promise<BrokerTurnResultDTO>;
45
45
  export declare function mutateBrokerProviderRetry(nodeId: string, request: Omit<BrokerProviderRetryRequest, 'expected_execution_id'>): Promise<BrokerProviderRetryResultDTO>;
46
46
  export declare function mutateBrokerFault(nodeId: string, request: Omit<BrokerFaultRequest, 'expected_execution_id'>): Promise<BrokerFaultResultDTO>;
47
+ /** A conversation store that refused writes past its deadline: the node's durable fault, written (execution-fenced) before the broker
48
+ * exits so the control plane and a harness read the cause. The record is capped at 5 s: a failed or slow record is logged and the
49
+ * exit proceeds. */
50
+ export declare function recordConversationWriteFault(nodeId: string, error: unknown): Promise<void>;
47
51
  export declare function brokerRecovery(nodeId: string): Promise<RecoveryStateDTO>;
48
52
  /** Node-scoped fault writes are for non-broker clients such as attach transport.
49
53
  * Broker-owned recovery mutations use the execution-fenced wrappers above. */
@@ -1 +1 @@
1
- var h=Object.defineProperty;var t=(e,r)=>h(e,"name",{value:r,configurable:!0});import{CrtrClient as R}from"../../../api/client.js";import{currentNodeToken as y}from"./node-token.js";import{localClient as b}from"../../../api/node-transport.js";import{ApiError as l}from"../../../api/errors.js";import{envExecutionId as w}from"../../../shared/env.js";import{brokerSignalClient as N}from"./signal-stream.js";import{cachedBrokerNodeFields as k}from"../../../daemon/broker-signals/bus.js";import{fetchRunAttachments as P}from"./attachments-fetch.js";import{reportRefNodeId as v}from"../../../shared/inbox-entry-body.js";function g(){const e=process.env.CRTR_API_URL;if(!(e===void 0||e==="")){if(!/^https?:\/\//.test(e))throw new Error(`CRTR_API_URL must be an http(s) URL: ${e}`);return e}}t(g,"brokerApiUrl");function o(){const e=g();if(e===void 0)return b({autostart:!1});const r=y();if(r===void 0)throw new Error("broker has no node token for CRTR_API_URL");return new R({baseUrl:e,headers:{authorization:`Bearer ${r}`}})}t(o,"daemonClient");function $(e,r){return o().appendNodeLog(e,{record:r,expected_execution_id:n()})}t($,"appendBrokerLog");function D(e,r){return o().putNodeTelemetry(e,{...r,expected_execution_id:n()})}t(D,"putBrokerTelemetry");function j(e,r){return o().putNodeRecap(e,{briefing:r,expected_execution_id:n()})}t(j,"putBrokerRecap");function z(e,r){return o().readNodePassiveMessage(e,r)}t(z,"readBrokerPassiveMessage");function G(e){return o().nodePushedFinal(e,{action:"clear",expected_execution_id:n()})}t(G,"clearBrokerPushedFinal");function O(e){return o().nodePushedFinal(e,{action:"consume",expected_execution_id:n()})}t(O,"consumeBrokerPushedFinal");function q(e,r){return o().request("POST",`/v1/nodes/${encodeURIComponent(e)}/jobs/start`,{...r,expected_execution_id:n()})}t(q,"startBrokerBashJob");function X(e,r,i){return o().recordBackgroundedJob(e,r,i)}t(X,"recordBackgroundedJob");function H(e,r,i){return o().reportBashJob(e,r,{...i,expected_execution_id:n()})}t(H,"reportBrokerJob");function K(e,r){return o().request("DELETE",`/v1/nodes/${encodeURIComponent(e)}/jobs/${encodeURIComponent(r)}?foreground=1`,{expected_execution_id:n()})}t(K,"stopBrokerBashJob");function n(){const e=w();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}t(n,"brokerExecutionId");function Q(e,r){return o().bindBrokerSession(e,{...r,executionId:n()})}t(Q,"bindBrokerSession");function V(e,r){return o().settleBroker(e,{...r,expected_execution_id:n()})}t(V,"settleBroker");function W(e){return o().postBrokerIdle(e,{expected_execution_id:n()})}t(W,"postBrokerIdle");function Y(e,r){return o().completeBrokerPark(e,{...r,expected_execution_id:n()})}t(Y,"completeBrokerPark");function Z(e){return o().recordBrokerParkActivity(e,{expected_execution_id:n()})}t(Z,"recordBrokerParkActivity");function ee(e,r){return o().recordBrokerTelemetry(e,{...r,expected_execution_id:n()})}t(ee,"recordBrokerTelemetry");const m=new Set;async function re(e,r,i){const s=o(),f=n(),a=await s.claimNodeMail(e,{execution_id:f,channel:r});if(a.action==="hold")return a;const x=a.deliveries.filter(u=>!m.has(u.entry.entry_id));if(x.length>0){await P(e);for(const u of x)m.add(u.entry.entry_id)}const p=await Promise.all(a.deliveries.map(async u=>{const c=u.entry.ref;if(c===void 0||v(c)===void 0)return u;try{let d=i.get(c);d===void 0&&(d=s.readNodeInboxReport(e,c,f).then(({content:B})=>B),i.set(c,d));const _=await d;return{...u,entry:{...u.entry,data:{...u.entry.data,report_body:_}}}}catch(d){if(i.delete(c),d instanceof l&&d.status===404)return u;throw d}}));if(p.length>0){const u=new Set(p.map(({entry:c})=>c.ref).filter(c=>c!==void 0));for(const c of i.keys())u.has(c)||i.delete(c)}return{...a,deliveries:p}}t(re,"claimBrokerMail");async function te(e,r){return await(await import("../../conversation-store/index.js")).flushConversation(),o().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}t(te,"acknowledgeBrokerMail");function oe(e,r){return o().recordBrokerTurn(e,{...r,expected_execution_id:n()})}t(oe,"recordBrokerTurn");function ne(e,r){return o().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}t(ne,"mutateBrokerProviderRetry");function ie(e,r){return o().mutateBrokerFault(e,{...r,expected_execution_id:n()})}t(ie,"mutateBrokerFault");function ce(e){return o().getBrokerRecovery(e,n())}t(ce,"brokerRecovery");function ue(e,r){return o().recordNodeFault(e,r)}t(ue,"recordNodeFault");function de(e,r={}){return o().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}t(de,"clearNodeFault");function ae(e,r){return o().commitBrokerModel(e,{...r,expected_execution_id:n()})}t(ae,"commitBrokerModel");function C(e){return o().brokerExtensionState(e)}t(C,"brokerExtensionState");async function pe(e){const r=N();return r.state==="connected"&&r.latestNode!==void 0?k(r.latestNode):k((await C(e)).node)}t(pe,"cachedBrokerNode");function se(e,r){return o().nodeDelivery(e,{...r,expected_execution_id:n()})}t(se,"brokerDelivery");function fe(e,r){return o().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}t(fe,"commitBrokerGeneratedName");function xe(e,r){return o().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}t(xe,"commitBrokerPersonaAck");async function le(e,r){try{await o().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof l&&i.code==="already_finalized")return;throw i}}t(le,"publishBrokerReport");function ke(e){return o().relaunchRoot(e)}t(ke,"relaunchBrokerRoot");export{te as acknowledgeBrokerMail,$ as appendBrokerLog,Q as bindBrokerSession,g as brokerApiUrl,se as brokerDelivery,n as brokerExecutionId,C as brokerExtensionState,ce as brokerRecovery,pe as cachedBrokerNode,re as claimBrokerMail,G as clearBrokerPushedFinal,de as clearNodeFault,fe as commitBrokerGeneratedName,ae as commitBrokerModel,xe as commitBrokerPersonaAck,Y as completeBrokerPark,O as consumeBrokerPushedFinal,o as daemonClient,ie as mutateBrokerFault,ne as mutateBrokerProviderRetry,W as postBrokerIdle,le as publishBrokerReport,j as putBrokerRecap,D as putBrokerTelemetry,z as readBrokerPassiveMessage,X as recordBackgroundedJob,Z as recordBrokerParkActivity,ee as recordBrokerTelemetry,oe as recordBrokerTurn,ue as recordNodeFault,ke as relaunchBrokerRoot,H as reportBrokerJob,V as settleBroker,q as startBrokerBashJob,K as stopBrokerBashJob};
1
+ var h=Object.defineProperty;var t=(e,r)=>h(e,"name",{value:r,configurable:!0});import{CrtrClient as y}from"../../../api/client.js";import{currentNodeToken as R}from"./node-token.js";import{localClient as w}from"../../../api/node-transport.js";import{ApiError as x}from"../../../api/errors.js";import{envExecutionId as b}from"../../../shared/env.js";import{brokerSignalClient as v}from"./signal-stream.js";import{emitEvent as P}from"../../events/emit.js";import{cachedBrokerNodeFields as k}from"../../../daemon/broker-signals/bus.js";import{fetchRunAttachments as N}from"./attachments-fetch.js";import{reportRefNodeId as g}from"../../../shared/inbox-entry-body.js";function E(){const e=process.env.CRTR_API_URL;if(!(e===void 0||e==="")){if(!/^https?:\/\//.test(e))throw new Error(`CRTR_API_URL must be an http(s) URL: ${e}`);return e}}t(E,"brokerApiUrl");function o(){const e=E();if(e===void 0)return w({autostart:!1});const r=R();if(r===void 0)throw new Error("broker has no node token for CRTR_API_URL");return new y({baseUrl:e,headers:{authorization:`Bearer ${r}`}})}t(o,"daemonClient");function z(e,r){return o().appendNodeLog(e,{record:r,expected_execution_id:n()})}t(z,"appendBrokerLog");function G(e,r){return o().putNodeTelemetry(e,{...r,expected_execution_id:n()})}t(G,"putBrokerTelemetry");function O(e,r){return o().putNodeRecap(e,{briefing:r,expected_execution_id:n()})}t(O,"putBrokerRecap");function q(e,r){return o().readNodePassiveMessage(e,r)}t(q,"readBrokerPassiveMessage");function W(e){return o().nodePushedFinal(e,{action:"clear",expected_execution_id:n()})}t(W,"clearBrokerPushedFinal");function X(e){return o().nodePushedFinal(e,{action:"consume",expected_execution_id:n()})}t(X,"consumeBrokerPushedFinal");function H(e,r){return o().request("POST",`/v1/nodes/${encodeURIComponent(e)}/jobs/start`,{...r,expected_execution_id:n()})}t(H,"startBrokerBashJob");function K(e,r,i){return o().recordBackgroundedJob(e,r,i)}t(K,"recordBackgroundedJob");function Q(e,r,i){return o().reportBashJob(e,r,{...i,expected_execution_id:n()})}t(Q,"reportBrokerJob");function V(e,r){return o().request("DELETE",`/v1/nodes/${encodeURIComponent(e)}/jobs/${encodeURIComponent(r)}?foreground=1`,{expected_execution_id:n()})}t(V,"stopBrokerBashJob");function n(){const e=b();if(e===void 0||e==="")throw new Error("broker launch is missing CRTR_EXECUTION_ID");return e}t(n,"brokerExecutionId");function Y(e,r){return o().bindBrokerSession(e,{...r,executionId:n()})}t(Y,"bindBrokerSession");function Z(e,r){return o().settleBroker(e,{...r,expected_execution_id:n()})}t(Z,"settleBroker");function ee(e){return o().postBrokerIdle(e,{expected_execution_id:n()})}t(ee,"postBrokerIdle");function re(e,r){return o().completeBrokerPark(e,{...r,expected_execution_id:n()})}t(re,"completeBrokerPark");function te(e){return o().recordBrokerParkActivity(e,{expected_execution_id:n()})}t(te,"recordBrokerParkActivity");function oe(e,r){return o().recordBrokerTelemetry(e,{...r,expected_execution_id:n()})}t(oe,"recordBrokerTelemetry");const m=new Set;async function ne(e,r,i){const a=o(),p=n(),s=await a.claimNodeMail(e,{execution_id:p,channel:r});if(s.action==="hold")return s;const l=s.deliveries.filter(d=>!m.has(d.entry.entry_id));if(l.length>0){await N(e);for(const d of l)m.add(d.entry.entry_id)}const f=await Promise.all(s.deliveries.map(async d=>{const c=d.entry.ref;if(c===void 0||g(c)===void 0)return d;try{let u=i.get(c);u===void 0&&(u=a.readNodeInboxReport(e,c,p).then(({content:B})=>B),i.set(c,u));const _=await u;return{...d,entry:{...d.entry,data:{...d.entry.data,report_body:_}}}}catch(u){if(i.delete(c),u instanceof x&&u.status===404)return d;throw u}}));if(f.length>0){const d=new Set(f.map(({entry:c})=>c.ref).filter(c=>c!==void 0));for(const c of i.keys())d.has(c)||i.delete(c)}return{...s,deliveries:f}}t(ne,"claimBrokerMail");async function ie(e,r){return await(await import("../../conversation-store/index.js")).flushConversation(),o().acknowledgeNodeMail(e,{execution_id:n(),deliveries:r})}t(ie,"acknowledgeBrokerMail");function ce(e,r){return o().recordBrokerTurn(e,{...r,expected_execution_id:n()})}t(ce,"recordBrokerTurn");function de(e,r){return o().mutateBrokerProviderRetry(e,{...r,expected_execution_id:n()})}t(de,"mutateBrokerProviderRetry");function C(e,r){return o().mutateBrokerFault(e,{...r,expected_execution_id:n()})}t(C,"mutateBrokerFault");async function ue(e,r){const i=C(e,{op:"record",input:{link:"daemon\u2192node",op:"conversation_write_failed",kind:"other",retry:{disposition:"manual"},message:r instanceof Error?r.message:String(r)}});await Promise.race([i,new Promise((a,p)=>setTimeout(()=>p(new Error("conversation_write_failed fault record timed out")),5e3).unref())]).catch(a=>P({level:"error",event:"broker.daemon.operation.failed",node_id:e,error:a,fields:{operation:"conversation_write_fault_record"}}))}t(ue,"recordConversationWriteFault");function ae(e){return o().getBrokerRecovery(e,n())}t(ae,"brokerRecovery");async function se(e,r){return o().recordNodeFault(e,r)}t(se,"recordNodeFault");async function pe(e,r={}){return o().clearNodeFault(e,{...r.link===void 0?{}:{link:r.link},...r.preserveEpisode===void 0?{}:{preserve_episode:r.preserveEpisode}}).then(i=>i.cleared)}t(pe,"clearNodeFault");function fe(e,r){return o().commitBrokerModel(e,{...r,expected_execution_id:n()})}t(fe,"commitBrokerModel");function T(e){return o().brokerExtensionState(e)}t(T,"brokerExtensionState");async function le(e){const r=v();return r.state==="connected"&&r.latestNode!==void 0?k(r.latestNode):k((await T(e)).node)}t(le,"cachedBrokerNode");function xe(e,r){return o().nodeDelivery(e,{...r,expected_execution_id:n()})}t(xe,"brokerDelivery");function ke(e,r){return o().commitBrokerGeneratedName(e,{...r,expected_execution_id:n()})}t(ke,"commitBrokerGeneratedName");function me(e,r){return o().commitBrokerPersonaAck(e,{...r,expected_execution_id:n()})}t(me,"commitBrokerPersonaAck");async function _e(e,r){try{await o().pushReport(e,r)}catch(i){if(r.tier==="final"&&i instanceof x&&i.code==="already_finalized")return;throw i}}t(_e,"publishBrokerReport");function Be(e){return o().relaunchRoot(e)}t(Be,"relaunchBrokerRoot");export{ie as acknowledgeBrokerMail,z as appendBrokerLog,Y as bindBrokerSession,E as brokerApiUrl,xe as brokerDelivery,n as brokerExecutionId,T as brokerExtensionState,ae as brokerRecovery,le as cachedBrokerNode,ne as claimBrokerMail,W as clearBrokerPushedFinal,pe as clearNodeFault,ke as commitBrokerGeneratedName,fe as commitBrokerModel,me as commitBrokerPersonaAck,re as completeBrokerPark,X as consumeBrokerPushedFinal,o as daemonClient,C as mutateBrokerFault,de as mutateBrokerProviderRetry,ee as postBrokerIdle,_e as publishBrokerReport,O as putBrokerRecap,G as putBrokerTelemetry,q as readBrokerPassiveMessage,K as recordBackgroundedJob,te as recordBrokerParkActivity,oe as recordBrokerTelemetry,ce as recordBrokerTurn,ue as recordConversationWriteFault,se as recordNodeFault,Be as relaunchBrokerRoot,Q as reportBrokerJob,Z as settleBroker,H as startBrokerBashJob,V as stopBrokerBashJob};
@@ -1 +1 @@
1
- var b=Object.defineProperty;var c=(r,t)=>b(r,"name",{value:t,configurable:!0});import{randomUUID as f}from"node:crypto";import{BrokerClient as h}from"../broker-client/index.js";const u=15e3;class k extends Error{static{c(this,"BrokerUnreachableError")}constructor(t){super(t),this.name="BrokerUnreachableError"}}function y(r){return new Promise(async(t,i)=>{const o=new h(r.nodeId),w=f(),d=f();let a=!1,l=!1;const s=setTimeout(()=>n(()=>i(new Error(`timed out after ${u}ms waiting for the broker to ack ${r.what}`))),u);typeof s.unref=="function"&&s.unref();function n(e){if(!a){a=!0,clearTimeout(s);try{o.close()}catch{}e()}}c(n,"finish"),o.on("error",e=>n(()=>i(l?e:new k(`broker connection refused mid-revive: ${e.message}`)))),o.on("close",()=>n(()=>i(l?new Error(`broker connection closed before it acked ${r.what}`):new k("broker connection closed before it was established (mid-revive)")))),o.on("connect",()=>{l=!0,o.send({type:"hello",role:"controller",client_id:w}),o.send(r.frame(d))}),o.on("frame",e=>{e.type==="ack"&&e.for===r.ackFor&&(r.correlated!==!0||e.id===d)?e.ok?n(()=>t(r.result(e.detail))):n(()=>i(new Error(e.detail??`broker rejected ${r.what}`))):e.type==="error"?n(()=>i(new Error(e.message))):r.observe!==void 0&&r.observe(e)}),o.connect()})}c(y,"oneShotControllerRequest");export{k as BrokerUnreachableError,y as oneShotControllerRequest};
1
+ var b=Object.defineProperty;var i=(e,t)=>b(e,"name",{value:t,configurable:!0});import{randomUUID as f}from"node:crypto";import{BrokerClient as h,SocketTransport as m}from"../broker-client/index.js";const u=15e3;class w extends Error{static{i(this,"BrokerUnreachableError")}constructor(t){super(t),this.name="BrokerUnreachableError"}}function I(e){return new Promise(async(t,c)=>{const o=new h(e.nodeId,{transport:new m(e.nodeId,{recordsViewerFaults:!1})}),k=f(),d=f();let a=!1,s=!1;const l=setTimeout(()=>n(()=>c(new Error(`timed out after ${u}ms waiting for the broker to ack ${e.what}`))),u);typeof l.unref=="function"&&l.unref();function n(r){if(!a){a=!0,clearTimeout(l);try{o.close()}catch{}r()}}i(n,"finish"),o.on("error",r=>n(()=>c(s?r:new w(`broker connection refused mid-revive: ${r.message}`)))),o.on("close",()=>n(()=>c(s?new Error(`broker connection closed before it acked ${e.what}`):new w("broker connection closed before it was established (mid-revive)")))),o.on("connect",()=>{s=!0,o.send({type:"hello",role:"controller",client_id:k}),o.send(e.frame(d))}),o.on("frame",r=>{r.type==="ack"&&r.for===e.ackFor&&(e.correlated!==!0||r.id===d)?r.ok?n(()=>t(e.result(r.detail))):n(()=>c(new Error(r.detail??`broker rejected ${e.what}`))):r.type==="error"?n(()=>c(new Error(r.message))):e.observe!==void 0&&e.observe(r)}),o.connect()})}i(I,"oneShotControllerRequest");export{w as BrokerUnreachableError,I as oneShotControllerRequest};
@@ -1 +1 @@
1
- var De=Object.defineProperty;var n=(t,o)=>De(t,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Ne,envModelIntent as Fe,envNodeCwd as Le,envNodeId as Be,envProfileId as Ue,envScopes as $e,scopeAllowed as Ke}from"../../shared/env.js";import{createServer as We}from"node:net";import{WebSocketServer as Ge,createWebSocketStream as je}from"ws";import{BROKER_VIEW_PORT as qe}from"./view-socket.js";import{existsSync as Re,readFileSync as Ve,unlinkSync as Te}from"node:fs";import{join as Ee}from"node:path";import{randomUUID as M}from"node:crypto";import{mark as Xe}from"../timing.js";import{SUBMIT_RESULT_TOOL as He}from"./structured-output.js";import{flushConversation as ke,installSessionManagerStorePatch as Ye}from"../conversation-store/index.js";import{getAgentDir as J,ModelRegistry as ze,ModelRuntime as Je}from"@earendil-works/pi-coding-agent";import{nodeRunDir as Qe,viewSocketPath as Ze}from"../canvas/paths.js";import{bindBrokerEventSource as en}from"../events/source.js";import{emitEvent as b,flushBrokerLog as nn}from"../events/emit.js";import{operationIdContext as tn}from"../events/operation-id.js";import{findMissingPackagePaths as rn}from"./package-health.js";import{installBrokerConfigSnapshot as on}from"../config.js";import{FRONT_DOOR_ENV as sn}from"./front-door.js";import{CANVAS_EXTENSIONS as oe,piInvocationToSdkConfig as an}from"./launch.js";import{assertEngineVersion as dn,loadBrokerEngine as ln}from"./broker-sdk.js";import{initCrtrTheme as cn}from"./crtr-theme.js";import{resolveBundledPiPackageDir as mn}from"./pi-cli.js";import{captureSessionChatCapabilities as un}from"./command-surface.js";import{InMemoryCredentialStore as fn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as pn}from"./broker/model-adapter.js";import{brokerApiUrl as gn,mutateBrokerFault as Q,recordBrokerTurn as Ce}from"./broker/daemon-ops.js";import{fetchRunAttachments as vn}from"./broker/attachments-fetch.js";import{modelRequestFromConfig as _n,expandModelCandidates as hn,parseModelSpec as wn,unregisteredConcreteModel as Sn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as bn}from"./stream-watchdog.js";import{probeOnline as yn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as Rn,cycleAwareMessages as Tn,endedByAbort as En}from"./session-cycles.js";import{turnErrorOf as kn}from"../llm/refusal.js";import{projectTranscript as Cn}from"./session-visibility.js";import{currentTurnVisibility as xn}from"./turn-visibility.js";import{isUnknownModel as ie}from"./model-selection.js";import{BrokerClientRegistry as Mn}from"./broker/client-registry.js";import{ToolGroupTracker as An}from"./broker/tool-groups.js";import{TurnReplyTracker as Pn}from"./broker/turn-replies.js";import{onNodeNamed as On}from"./broker/node-named.js";import{FaultRetry as In,willDaemonRetry as Dn}from"./broker/fault-retry.js";import{RunTurnEnds as Nn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Fn}from"./broker/turn-admission.js";import{BROKER_DISPOSE_AND_EXIT as Ln,BROKER_IDLE_TURN_START as Bn,BROKER_RUN_TURN_BUSY as Un}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as $n,settleRunDeferredMail as Kn}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Wn}from"./broker/run-turn-queue.js";import{EventProjection as Gn}from"./broker/event-projection.js";import{createFrameDispatchContext as jn,handleFrame as qn}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as Vn,installAdvertisedCommandInvocationContract as Xn}from"./advertised-command-invocation.js";import{RebindDriver as Hn}from"./broker/rebind.js";import{beginRuntimeTeardown as Yn}from"./broker/extension-abort.js";import{receiveNodeToken as zn}from"./broker/node-token.js";import{serveCliRelay as Jn}from"./broker/cli-relay.js";import{recordBrokerRelease as Qn}from"./lifecycle.js";import{setTurnCauseSource as Zn}from"./broker/turn-cause.js";import{decodeKickoffOrigin as et,KICKOFF_ORIGIN_ENV as nt}from"./stamp/protocol.js";import{announceMessageOrigin as tt}from"./stamp/channel.js";import{commitBrokerModel as rt}from"./broker/daemon-ops.js";import{bootExtensionState as ot}from"./broker/boot-state.js";import{composerNames as it}from"./broker/frame-memory-refs.js";import{BROKER_READ_CAPS as st,FrameOverflowError as at,normalizeSnapshotTail as dt}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as Mr,REVIEW_BOUNDARY_NAVIGATION_CODE as Ar}from"./broker/frame-replies.js";function se(t){return new ze(t.modelRuntime)}n(se,"registryOf");function $(t,o){if(t==null||ie(t))return null;const s=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${t.provider}/${t.id}${s}`}n($,"formatModelSpec");function lt(t,o){const s=$(t,void 0);return s===null?null:`${s}:${o===void 0||o===""?"off":o}`}n(lt,"formatExactModelSpec");const ct=12e4;let Z=null;import{brokerSignalClient as K}from"./broker/signal-stream.js";function mt(){K().stop();const t=Z;if(Z=null,t!==null)try{t.dispose()}catch{}}n(mt,"disposeActiveSession");function ut(t,o){const s=Ke(o,"crtr:act")?void 0:["bash"],u=t!==void 0&&t.length>0?[...new Set([...t,He])]:t===void 0?void 0:[...t];return{...u!==void 0?{tools:u}:{},...s!==void 0?{excludeTools:s}:{}}}n(ut,"brokerToolOptions");async function kr(t,o=process.hrtime.bigint(),s=new Date().toISOString()){en(t);const u=await zn(),i=await Jn(t,u);process.env.CRTR_API_SOCKET=i.path,tn.fresh(()=>{b({level:"info",event:"broker.startup.cli_entry",ts:s,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),b({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let c=null;const d=n((e,r=null)=>{a.has(e)||(a.add(e),Xe(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),b({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:c,model:r}}))},"emitStartupMilestone");process.env[sn]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,Ye(t);const v=await ln();dn(v.VERSION),c=v.VERSION;const w=Qe(t),E=Ee(w,"broker-launch.json"),S=JSON.parse(Ve(E,"utf8"));if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");on(S.configSnapshot);const g=an(S);g.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await it(t);let R,A;const X=n(e=>{R!==void 0?R(e):A??=e},"onSignal");process.on("SIGTERM",()=>X("SIGTERM")),process.on("SIGINT",()=>X("SIGINT")),process.on("SIGUSR1",()=>{const e=process.env.CRTR_EXECUTION_ID;e!==void 0&&e!==""&&K().start(t,e)});let{session:W,services:P,resuming:de,runtime:G}=await vt(v,g);d("broker.startup.session_built");const k=(await ot(t)).node.review_binding?.review_id,T=Ne();Z=W;const F=yn;try{process.env.PI_PACKAGE_DIR=mn(),cn(P.settingsManager.getTheme(),J(),!1)}catch(e){b({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of rn(J()))b({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const j=Ze(t),_=new Mn(t),H=new Map,I=new An(t,e=>_.broadcast(e)),q=new Pn(t,e=>_.broadcast(e));On(e=>_.broadcast({type:"node_named",...e}));let D=!1,le=!1,Y,z,ce,m,V;const ee=new Nn;let L,me=n(()=>{},"notifyTurnAccepted"),ue=n(()=>{},"resetFrameState");const ne=Fn();let fe=n(()=>0,"pendingPromptDispatches"),pe;const B=Wn({runNode:T,session:n(()=>m.session(),"session"),isReplacing:n(()=>m.isReplacing(),"isReplacing"),pendingRebind:n(()=>m.pendingRebind(),"pendingRebind"),isAgentRunActive:n(()=>m.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:n(()=>fe(),"pendingDispatches"),turnAdmission:ne,prependDeferred:n(e=>$n(t,e),"prependDeferred"),onError:n(e=>b({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")});Zn(()=>m.session());const ge=B.drain;g.firstPrompt!==void 0&&g.firstPrompt!==""&&B.holdForKickoff(),globalThis[Bn]=B.start,globalThis[Un]=B.busy,m=new Hn({nodeId:t,cfg:g,session:W,services:P,runtime:G,registry:_,toolGroups:I,turnReplies:q,transcriptMessages:n(e=>ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:n(()=>ce,"uiContext"),faultRetry:n(()=>V,"faultRetry"),projection:n(()=>L,"projection"),setActiveSession:n(e=>{if(Z=e,pe?.(),T||process.env.CRTR_RUN_ID){let r="stop",l,f=!1;pe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",l=void 0,f=!1,ee.started()),h.type==="agent_end"){const p=[...h.messages??[]].reverse().find(U=>U.role==="assistant");p&&(r=p.stopReason,l=En(p)?void 0:kn(p),f=p.role==="assistant"&&Dn(p,e.model?.contextWindow))}h.type==="agent_settled"&&(ee.settled(e.sessionManager,{stop_reason:r,...l?{error:l}:{}},f),T&&(ke().then(()=>Kn(t,e)).catch(p=>{if(String(p?.message).startsWith("conversation_write_failed")){b({level:"error",event:"broker.exited",node_id:t,error:p,fields:{fault:"conversation_write_failed"}}),C("conversation_write_failed",1);return}b({level:"error",event:"broker.run_deferred_mail.settle_failed",error:p})}),queueMicrotask(()=>{m.session()===e&&ge()})))})}},"setActiveSession"),disposeAndExit:n((e,r)=>C(e,r),"disposeAndExit"),onSessionRebind:n(()=>{ue()},"onSessionRebind"),onReplacementIdle:n(()=>{T&&ge()},"onReplacementIdle"),reWelcomeAll:n(()=>te(),"reWelcomeAll")});const ve=n(async(e,r=!1)=>{const l=m.session(),f=$(l.model,l.thinkingLevel);if(f===null)return null;const h=await rt(t,{spec:f,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(g.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,g.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",g.modelExact=!0)),h.modelOverride},"persistModelChoice"),_e=n(async(e=!0,r,l=!1)=>{const f=m.session(),h=$(f.model,f.thinkingLevel),p=e?await ve(r,l):h;_.broadcast({type:"model_changed",model:ie(f.model)?void 0:f.model,spec:p})},"broadcastModelChanged");V=new In({nodeId:t,cfg:g,retryProbe:F,currentSession:n(()=>m.session(),"currentSession"),currentServices:n(()=>m.services(),"currentServices"),installedGeneration:n(()=>m.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:$,broadcastModelChanged:_e,turnAdmission:ne,reWelcomeAll:n(()=>te(),"reWelcomeAll"),...T?{turnEnds:ee}:{}});const he=n(()=>{V.rearmIfStranded().catch(e=>{b({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");K().subscribe("resync",he),K().subscribe("fault-retry",he),L=new Gn({registry:_,faultRetry:V,installedGeneration:n(()=>m.installedGeneration(),"installedGeneration"),currentSession:n(()=>m.session(),"currentSession"),notifyTurnAccepted:n(()=>me(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Me=n(e=>{const r=m.session(),l=ae(r,k),f=dt(e.snapshotTail),h=l===void 0||f===void 0?l:l.slice(-f),p=h?.map(({message:N})=>N)??r.sessionManager.buildSessionContext().messages,U=I.summaries(),ye=h!==void 0&&f!==void 0?ft(p):void 0,Ie=ye===void 0?U:Object.fromEntries(Object.entries(U).filter(([N])=>ye.has(N)));return{messages:p,...h===void 0?{}:{messageIds:h.map(({id:N})=>N)},messageVisibility:h?.map(({visibility:N})=>N)??p.map(()=>"visible"),turnVisibility:xn(),stats:r.getSessionStats(),state:{model:ie(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{..._.displaySnapshot()},toolGroupSummaries:Ie,turnReplies:q.snapshot(),workingActivity:L.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),we=n(e=>{const r=e.role==="controller"?H.values().next().value:void 0;_.sendFrame(e,{type:"welcome",snapshot:Me(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:J()},!0)},"sendWelcome"),Ae=n(e=>{const r=[...H.values()];for(let l=1;l<r.length;l++)_.sendFrame(e,r[l].request)},"replayExtraPendingDialogsTo"),te=n(()=>{try{const e=m.session();q.seed(ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){b({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}_.forEachHelloed(we)},"reWelcomeAll"),Se=n(async e=>{if(D)return;D=!0;const r=K().latestNode;r!==void 0&&(r.intent==="idle-release"||r.status==="done")&&Qn(t,process.env.CRTR_EXECUTION_ID??null),K().stop(),e===0&&await ke().catch(l=>{e=1,b({level:"error",event:"broker.exited",node_id:t,error:l,fields:{fault:"conversation_write_failed"}})}),I.persistPendingSummary(),L.dispose(),mt();try{Y?.close(),z?.close()}catch{}i.close(),_.dispose();try{Re(j)&&Te(j)}catch{}_.clearAttachState(),await nn(),process.exit(e)},"completeExit"),C=n((e,r=0)=>{if(D)return;const l=e==="shutdown-hook"||e==="shutdown-after-settle";if(l&&I.finishOpenToolGroup(!0),l&&(I.hasSummaryTasks()||q.hasTasks())){if(le)return;le=!0,Promise.allSettled([I.waitForSummaryTasks(),q.waitForTasks()]).finally(()=>Se(r));return}Se(r)},"disposeAndExit");globalThis[Ln]=C,ce=_t({writable:n(()=>_.writableClients(),"writable"),forward:n((e,r)=>_.sendFrame(e,r),"forward"),pending:H,broadcast:n(e=>_.broadcastUi(e),"broadcast"),onKnownStreamWait:n(e=>L.knownStreamWait(e),"onKnownStreamWait")}),m.setRebindSession(),await m.enqueueRebind(W,P),d("broker.startup.extensions_bound");const x=jn({nodeId:t,registry:_,toolGroups:I,projection:L,rebind:m,boundaryReviewId:k,pendingDialogs:H,sendWelcome:we,replayExtraPendingDialogsTo:Ae,reWelcomeAll:te,disposeAndExit:C,persistModelChoice:ve,broadcastModelChanged:_e,registryOf:se,formatModelSpec:$,formatExactModelSpec:lt,turnAdmission:ne,memoryInventory:y,runNode:T,onKickoffAdmitted:B.releaseKickoff});me=x.notifyTurnAccepted,ue=x.resetForSession,fe=x.pendingPromptDispatches;const Pe=2500;let re=!1;const Oe=n(async e=>{if(D||re)return;if(re=!0,m.isAgentRunActive()||m.session().isStreaming||x.pendingPromptDispatches()>0){const l=Date.now()+Pe;for(;x.pendingPromptDispatches()>0&&!m.session().isStreaming&&Date.now()<l;)await new Promise(f=>setTimeout(f,25));if(m.session().isStreaming){const f=l-Date.now();if(f>0){let h;try{Yn(),await Promise.race([m.session().abort().then(()=>!0,()=>!1),new Promise(U=>{h=setTimeout(()=>U(!1),f)})])&&await Ce(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(x.pendingPromptDispatches()>0||m.isAgentRunActive())&&await Ce(t,{event:"interrupted"})}C(e)},"abortAndExit");if(R=n(e=>{Oe(e)},"signalTeardown"),A!==void 0){R(A);return}try{Re(j)&&Te(j)}catch{}const be=n(e=>{const r=_.create(e);e.on("data",f=>{let h;try{h=r.decoder.push(f)}catch(p){p instanceof at?(_.sendFrame(r,{type:"error",code:"frame_overflow",message:p.message}),_.dropClient(r,`frame overflow: ${p.message}`)):_.dropClient(r,`decoder error: ${String(p)}`);return}for(const p of h)try{qn(x,r,p)}catch{}});const l=n(()=>{_.removeClient(r)},"drop");e.on("close",l),e.on("error",()=>{})},"serveViewer");Y=We(be),gn()!==void 0&&(z=new Ge({host:"127.0.0.1",port:qe,path:"/view",maxPayload:st.maxLineBytes}),z.on("connection",e=>be(je(e))),z.on("error",e=>{D||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))})),Y.on("error",e=>{D||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))}),Y.listen(j,async()=>{Promise.all([Q(t,{op:"clear",link:"viewer\u2194broker"}),Q(t,{op:"clear",link:"relay\u2194broker"})]).catch(r=>b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await V.recoverOnStartup()}catch(r){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"recovery_startup"}}),C("recovery-startup-failed",1);return}if(!(D||re))if(e==="none"&&g.firstPrompt!==void 0&&g.firstPrompt!==""){const r=et(process.env[nt]);r!==null&&tt(g.firstPrompt,r);try{await vn(t)}catch(f){b({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:f,fields:{operation:"attachments_fetch"}}),C("attachments-fetch-failed",1);return}const l=process.env.CRTR_KICKOFF_MESSAGE_IDS;x.kickoff(g.firstPrompt,l?JSON.parse(l):[])}else B.releaseKickoff()}),_.persistAttachState()}n(kr,"runBroker");function ft(t){const o=new Set;for(const s of t)if(!(s.role!=="assistant"||!Array.isArray(s.content)))for(const u of s.content)u!==null&&typeof u=="object"&&u.type==="toolCall"&&typeof u.id=="string"&&o.add(u.id);return o}n(ft,"toolCallIds");function ae(t,o){const s=t.sessionManager,u=Tn(s);return u!==void 0&&Vn(u.map(({message:i})=>i)),u===void 0?void 0:Cn(u,{boundaryReviewId:o,sessionEntries:s.getEntries?.()})}n(ae,"snapshotMessages");function xe(){const t=Be();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}n(xe,"currentBrokerNodeId");async function pt(t,o){const s=_n(o.model,Fe(),o.modelExact===!0);if(s===void 0)return;const u=se(t),i={cwd:Le()??o.cwd,profileId:Ue()},a=await Sn(s,u,i);if(a!==void 0)throw await Q(xe(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const c=await hn(s,i.cwd,i.profileId),d=wn(s.spec);for(const v of c){const w=u.find(v.providerId,v.modelId);if(w===void 0)continue;const S=d?.providerId===v.providerId&&d.modelId===v.modelId?d.thinkingLevel??(v.thinkingLevel===void 0?void 0:"off"):v.thinkingLevel;return{model:w,thinkingLevel:S}}if(o.modelExact===!0){const v=c.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await Q(xe(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${v})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}b({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:c.map(v=>({provider:v.providerId,model:v.modelId,reason:"unregistered"})).slice(0,16)}})}n(pt,"resolveLaunchModel");function gt(t){let o=!0;return{runtime:new Proxy(t,{get(u,i,a){return o&&i==="getAvailableSnapshot"?()=>[]:o&&i==="getAvailable"?async()=>[]:o&&i==="getModel"?()=>{}:Reflect.get(u,i,a)}}),reveal:n(()=>{o=!1},"reveal")}}n(gt,"modelLessRegistry");async function vt(t,o){const s=J(),u=n(async S=>{const g=await Je.create({credentials:new fn,modelsPath:Ee(S.agentDir,"models.json")});pn(g);const y=await t.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:g,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:n(O=>({...O,extensions:O.extensions.filter(k=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(k.path))}),"extensionsOverride")}}),R=y.resourceLoader.getExtensions();if(o.extensionPaths.some(O=>oe.includes(O))){const O=new Set(R.extensions.map(T=>T.path)),k=oe.filter(T=>!O.has(T));if(k.length>0){const T=R.errors.filter(F=>oe.includes(F.path)).map(F=>`${F.path}: ${F.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${k.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const A=await pt(y,o),X=A?.model,W=A?.thinkingLevel,P=A===void 0?gt(y.modelRuntime):void 0,de=P!==void 0?{...y,modelRuntime:P.runtime}:y,G=await t.createAgentSessionFromServices({services:de,sessionManager:S.sessionManager,model:X,thinkingLevel:W,...ut(o.tools,$e()),sessionStartEvent:S.sessionStartEvent});return Xn(G.session),un(G.session),P?.reveal(),{...G,services:y}},"buildForManager"),i=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(i===void 0||i==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const c=!a&&i!==void 0&&i!=="",d=c&&o.newCycle===!0,v=c&&!d;let w;if(a)w=await t.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(v||d){if(w=await t.SessionManager.open(i),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(Rn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=await t.SessionManager.create(o.cwd);if(t.createAgentSessionRuntime!==void 0){const S=n(async y=>{const R=await u({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...R,diagnostics:R.services.diagnostics??[]}},"factory"),g=await t.createAgentSessionRuntime(S,{cwd:o.cwd,agentDir:s,sessionManager:w});return{session:g.session,services:g.services,resuming:v,runtime:g}}const E=await u({cwd:o.cwd,agentDir:s,sessionManager:w});return{session:E.session,services:E.services,resuming:v,runtime:void 0}}n(vt,"buildBrokerSession");function _t(t){const o=n((i,a,c,d)=>{if(d?.signal?.aborted)return Promise.resolve(i);const v=t.writable();return v.length===0?Promise.resolve(i):new Promise(w=>{let E;const S=n(()=>{E!==void 0&&clearTimeout(E),d?.signal?.removeEventListener("abort",g),t.pending.delete(a.id)},"cleanup"),g=n(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},"onAbort");d?.signal?.addEventListener("abort",g,{once:!0});const y=d?.timeout!==void 0?d.timeout:ct;E=setTimeout(()=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},y),typeof E.unref=="function"&&E.unref(),t.pending.set(a.id,{request:a,resolve:n(R=>{S(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),w(c(R))},"resolve")});for(const R of v)t.forward(R,a)})},"dialogPromise"),s=n(()=>{},"noop");return{[bn]:t.onKnownStreamWait??(i=>()=>{}),get theme(){const i=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(i==null)throw new Error("Theme not initialized. Call initTheme() first.");return i},select:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:M(),method:"select",title:i,options:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"select"),confirm:n((i,a,c)=>o(!1,{type:"extension_ui_request",id:M(),method:"confirm",title:i,message:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,c),"confirm"),input:n((i,a,c)=>o(void 0,{type:"extension_ui_request",id:M(),method:"input",title:i,placeholder:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"input"),editor:n((i,a)=>o(void 0,{type:"extension_ui_request",id:M(),method:"editor",title:i,prefill:a},c=>"cancelled"in c&&c.cancelled?void 0:"value"in c?c.value:void 0),"editor"),setStatus:n((i,a)=>t.broadcast({type:"extension_ui_request",id:M(),method:"setStatus",statusKey:i,statusText:a}),"setStatus"),setWidget:n((i,a,c)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:M(),method:"setWidget",widgetKey:i,widgetLines:a,widgetPlacement:c?.placement})},"setWidget"),setTitle:n(i=>t.broadcast({type:"extension_ui_request",id:M(),method:"setTitle",title:i}),"setTitle"),notify:n((i,a)=>{const c=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:M(),method:"notify",message:i,notifyType:c})},"notify"),onTerminalInput:n(()=>s,"onTerminalInput"),setWorkingMessage:s,setWorkingVisible:s,setWorkingIndicator:s,setHiddenThinkingLabel:s,setFooter:s,setHeader:s,custom:n(()=>Promise.resolve(void 0),"custom"),pasteToEditor:s,setEditorText:s,getEditorText:n(()=>"","getEditorText"),addAutocompleteProvider:s,setEditorComponent:s,getEditorComponent:n(()=>{},"getEditorComponent"),getAllThemes:n(()=>[],"getAllThemes"),getTheme:n(()=>{},"getTheme"),setTheme:s,getToolsExpanded:n(()=>!1,"getToolsExpanded"),setToolsExpanded:s}}n(_t,"makeBrokerUiContext");export{Ar as REVIEW_BOUNDARY_NAVIGATION_CODE,Mr as ReviewBoundaryNavigationError,ut as brokerToolOptions,vt as buildBrokerSession,mt as disposeActiveSession,_t as makeBrokerUiContext,kr as runBroker,ae as snapshotMessages};
1
+ var Ne=Object.defineProperty;var t=(n,o)=>Ne(n,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Fe,envModelIntent as Le,envNodeCwd as Be,envNodeId as Ue,envProfileId as $e,envScopes as We,scopeAllowed as Ke}from"../../shared/env.js";import{createServer as Ge}from"node:net";import{WebSocketServer as je,createWebSocketStream as qe}from"ws";import{BROKER_VIEW_PORT as Ve}from"./view-socket.js";import{existsSync as Re,readFileSync as Xe,unlinkSync as Te}from"node:fs";import{join as Ee}from"node:path";import{randomUUID as M}from"node:crypto";import{mark as He}from"../timing.js";import{SUBMIT_RESULT_TOOL as Ye}from"./structured-output.js";import{flushConversation as ke,installSessionManagerStorePatch as ze}from"../conversation-store/index.js";import{getAgentDir as J,ModelRegistry as Je,ModelRuntime as Qe}from"@earendil-works/pi-coding-agent";import{nodeRunDir as Ze,viewSocketPath as en}from"../canvas/paths.js";import{bindBrokerEventSource as nn}from"../events/source.js";import{emitEvent as b,flushBrokerLog as tn}from"../events/emit.js";import{operationIdContext as rn}from"../events/operation-id.js";import{findMissingPackagePaths as on}from"./package-health.js";import{installBrokerConfigSnapshot as sn}from"../config.js";import{FRONT_DOOR_ENV as an}from"./front-door.js";import{CANVAS_EXTENSIONS as oe,piInvocationToSdkConfig as dn}from"./launch.js";import{assertEngineVersion as ln,loadBrokerEngine as cn}from"./broker-sdk.js";import{initCrtrTheme as mn}from"./crtr-theme.js";import{resolveBundledPiPackageDir as un}from"./pi-cli.js";import{captureSessionChatCapabilities as fn}from"./command-surface.js";import{InMemoryCredentialStore as pn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as gn}from"./broker/model-adapter.js";import{brokerApiUrl as vn,mutateBrokerFault as Q,recordBrokerTurn as Ce}from"./broker/daemon-ops.js";import{fetchRunAttachments as _n}from"./broker/attachments-fetch.js";import{modelRequestFromConfig as hn,expandModelCandidates as wn,parseModelSpec as Sn,unregisteredConcreteModel as bn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as yn}from"./stream-watchdog.js";import{probeOnline as Rn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as Tn,cycleAwareMessages as En,endedByAbort as kn}from"./session-cycles.js";import{turnErrorOf as Cn}from"../llm/refusal.js";import{projectTranscript as xn}from"./session-visibility.js";import{currentTurnVisibility as Mn}from"./turn-visibility.js";import{isUnknownModel as ie}from"./model-selection.js";import{BrokerClientRegistry as An}from"./broker/client-registry.js";import{ToolGroupTracker as Pn}from"./broker/tool-groups.js";import{TurnReplyTracker as On}from"./broker/turn-replies.js";import{onNodeNamed as Dn}from"./broker/node-named.js";import{FaultRetry as In,willDaemonRetry as Nn}from"./broker/fault-retry.js";import{RunTurnEnds as Fn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Ln}from"./broker/turn-admission.js";import{BROKER_DISPOSE_AND_EXIT as Bn,BROKER_IDLE_TURN_START as Un,BROKER_RUN_TURN_BUSY as $n}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as Wn,settleRunDeferredMail as Kn}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Gn}from"./broker/run-turn-queue.js";import{EventProjection as jn}from"./broker/event-projection.js";import{createFrameDispatchContext as qn,handleFrame as Vn}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as Xn,installAdvertisedCommandInvocationContract as Hn}from"./advertised-command-invocation.js";import{RebindDriver as Yn}from"./broker/rebind.js";import{beginRuntimeTeardown as zn}from"./broker/extension-abort.js";import{receiveNodeToken as Jn}from"./broker/node-token.js";import{serveCliRelay as Qn}from"./broker/cli-relay.js";import{recordBrokerRelease as Zn}from"./lifecycle.js";import{setTurnCauseSource as et}from"./broker/turn-cause.js";import{decodeKickoffOrigin as nt,KICKOFF_ORIGIN_ENV as tt}from"./stamp/protocol.js";import{announceMessageOrigin as rt}from"./stamp/channel.js";import{commitBrokerModel as ot,recordConversationWriteFault as xe}from"./broker/daemon-ops.js";import{bootExtensionState as it}from"./broker/boot-state.js";import{composerNames as st}from"./broker/frame-memory-refs.js";import{BROKER_READ_CAPS as at,FrameOverflowError as dt,normalizeSnapshotTail as lt}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as Ar,REVIEW_BOUNDARY_NAVIGATION_CODE as Pr}from"./broker/frame-replies.js";function se(n){return new Je(n.modelRuntime)}t(se,"registryOf");function $(n,o){if(n==null||ie(n))return null;const s=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${n.provider}/${n.id}${s}`}t($,"formatModelSpec");function ct(n,o){const s=$(n,void 0);return s===null?null:`${s}:${o===void 0||o===""?"off":o}`}t(ct,"formatExactModelSpec");const mt=12e4;let Z=null;import{brokerSignalClient as W}from"./broker/signal-stream.js";function ut(){W().stop();const n=Z;if(Z=null,n!==null)try{n.dispose()}catch{}}t(ut,"disposeActiveSession");function ft(n,o){const s=Ke(o,"crtr:act")?void 0:["bash"],f=n!==void 0&&n.length>0?[...new Set([...n,Ye])]:n===void 0?void 0:[...n];return{...f!==void 0?{tools:f}:{},...s!==void 0?{excludeTools:s}:{}}}t(ft,"brokerToolOptions");async function Cr(n,o=process.hrtime.bigint(),s=new Date().toISOString()){nn(n);const f=await Jn(),i=await Qn(n,f);process.env.CRTR_API_SOCKET=i.path,rn.fresh(()=>{b({level:"info",event:"broker.startup.cli_entry",ts:s,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),b({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let c=null;const d=t((e,r=null)=>{a.has(e)||(a.add(e),He(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),b({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:c,model:r}}))},"emitStartupMilestone");process.env[an]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,ze(n);const v=await cn();ln(v.VERSION),c=v.VERSION;const w=Ze(n),E=Ee(w,"broker-launch.json"),S=JSON.parse(Xe(E,"utf8"));if(!S.configSnapshot)throw new Error("broker launch is missing its config snapshot");sn(S.configSnapshot);const g=dn(S);g.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await st(n);let R,A;const X=t(e=>{R!==void 0?R(e):A??=e},"onSignal");process.on("SIGTERM",()=>X("SIGTERM")),process.on("SIGINT",()=>X("SIGINT")),process.on("SIGUSR1",()=>{const e=process.env.CRTR_EXECUTION_ID;e!==void 0&&e!==""&&W().start(n,e)});let{session:K,services:P,resuming:de,runtime:G}=await _t(v,g);d("broker.startup.session_built");const k=(await it(n)).node.review_binding?.review_id,T=Fe();Z=K;const F=Rn;try{process.env.PI_PACKAGE_DIR=un(),mn(P.settingsManager.getTheme(),J(),!1)}catch(e){b({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of on(J()))b({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const j=en(n),_=new An(n),H=new Map,D=new Pn(n,e=>_.broadcast(e)),q=new On(n,e=>_.broadcast(e));Dn(e=>_.broadcast({type:"node_named",...e}));let I=!1,le=!1,Y,z,ce,m,V;const ee=new Fn;let L,me=t(()=>{},"notifyTurnAccepted"),ue=t(()=>{},"resetFrameState");const ne=Ln();let fe=t(()=>0,"pendingPromptDispatches"),pe;const B=Gn({runNode:T,session:t(()=>m.session(),"session"),isReplacing:t(()=>m.isReplacing(),"isReplacing"),pendingRebind:t(()=>m.pendingRebind(),"pendingRebind"),isAgentRunActive:t(()=>m.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:t(()=>fe(),"pendingDispatches"),turnAdmission:ne,prependDeferred:t(e=>Wn(n,e),"prependDeferred"),onError:t(e=>b({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")});et(()=>m.session());const ge=B.drain;g.firstPrompt!==void 0&&g.firstPrompt!==""&&B.holdForKickoff(),globalThis[Un]=B.start,globalThis[$n]=B.busy,m=new Yn({nodeId:n,cfg:g,session:K,services:P,runtime:G,registry:_,toolGroups:D,turnReplies:q,transcriptMessages:t(e=>ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:t(()=>ce,"uiContext"),faultRetry:t(()=>V,"faultRetry"),projection:t(()=>L,"projection"),setActiveSession:t(e=>{if(Z=e,pe?.(),T||process.env.CRTR_RUN_ID){let r="stop",l,p=!1;pe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",l=void 0,p=!1,ee.started()),h.type==="agent_end"){const u=[...h.messages??[]].reverse().find(U=>U.role==="assistant");u&&(r=u.stopReason,l=kn(u)?void 0:Cn(u),p=u.role==="assistant"&&Nn(u,e.model?.contextWindow))}h.type==="agent_settled"&&(ee.settled(e.sessionManager,{stop_reason:r,...l?{error:l}:{}},p),T&&(ke().then(()=>Kn(n,e)).catch(async u=>{if(String(u?.message).startsWith("conversation_write_failed")){b({level:"error",event:"broker.exited",node_id:n,error:u,fields:{fault:"conversation_write_failed"}}),await xe(n,u),C("conversation_write_failed",1);return}b({level:"error",event:"broker.run_deferred_mail.settle_failed",error:u})}),queueMicrotask(()=>{m.session()===e&&ge()})))})}},"setActiveSession"),disposeAndExit:t((e,r)=>C(e,r),"disposeAndExit"),onSessionRebind:t(()=>{ue()},"onSessionRebind"),onReplacementIdle:t(()=>{T&&ge()},"onReplacementIdle"),reWelcomeAll:t(()=>te(),"reWelcomeAll")});const ve=t(async(e,r=!1)=>{const l=m.session(),p=$(l.model,l.thinkingLevel);if(p===null)return null;const h=await ot(n,{spec:p,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(g.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,g.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",g.modelExact=!0)),h.modelOverride},"persistModelChoice"),_e=t(async(e=!0,r,l=!1)=>{const p=m.session(),h=$(p.model,p.thinkingLevel),u=e?await ve(r,l):h;_.broadcast({type:"model_changed",model:ie(p.model)?void 0:p.model,spec:u})},"broadcastModelChanged");V=new In({nodeId:n,cfg:g,retryProbe:F,currentSession:t(()=>m.session(),"currentSession"),currentServices:t(()=>m.services(),"currentServices"),installedGeneration:t(()=>m.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:$,broadcastModelChanged:_e,turnAdmission:ne,reWelcomeAll:t(()=>te(),"reWelcomeAll"),...T?{turnEnds:ee}:{}});const he=t(()=>{V.rearmIfStranded().catch(e=>{b({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");W().subscribe("resync",he),W().subscribe("fault-retry",he),L=new jn({registry:_,faultRetry:V,installedGeneration:t(()=>m.installedGeneration(),"installedGeneration"),currentSession:t(()=>m.session(),"currentSession"),notifyTurnAccepted:t(()=>me(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:$});const Ae=t(e=>{const r=m.session(),l=ae(r,k),p=lt(e.snapshotTail),h=l===void 0||p===void 0?l:l.slice(-p),u=h?.map(({message:N})=>N)??r.sessionManager.buildSessionContext().messages,U=D.summaries(),ye=h!==void 0&&p!==void 0?pt(u):void 0,Ie=ye===void 0?U:Object.fromEntries(Object.entries(U).filter(([N])=>ye.has(N)));return{messages:u,...h===void 0?{}:{messageIds:h.map(({id:N})=>N)},messageVisibility:h?.map(({visibility:N})=>N)??u.map(()=>"visible"),turnVisibility:Mn(),stats:r.getSessionStats(),state:{model:ie(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{..._.displaySnapshot()},toolGroupSummaries:Ie,turnReplies:q.snapshot(),workingActivity:L.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),we=t(e=>{const r=e.role==="controller"?H.values().next().value:void 0;_.sendFrame(e,{type:"welcome",snapshot:Ae(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:J()},!0)},"sendWelcome"),Pe=t(e=>{const r=[...H.values()];for(let l=1;l<r.length;l++)_.sendFrame(e,r[l].request)},"replayExtraPendingDialogsTo"),te=t(()=>{try{const e=m.session();q.seed(ae(e,k)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){b({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}_.forEachHelloed(we)},"reWelcomeAll"),Se=t(async e=>{if(I)return;I=!0;const r=W().latestNode;r!==void 0&&(r.intent==="idle-release"||r.status==="done")&&Zn(n,process.env.CRTR_EXECUTION_ID??null),W().stop(),e===0&&await ke().catch(async l=>{e=1,b({level:"error",event:"broker.exited",node_id:n,error:l,fields:{fault:"conversation_write_failed"}}),await xe(n,l)}),D.persistPendingSummary(),L.dispose(),ut();try{Y?.close(),z?.close()}catch{}i.close(),_.dispose();try{Re(j)&&Te(j)}catch{}_.clearAttachState(),await tn(),process.exit(e)},"completeExit"),C=t((e,r=0)=>{if(I)return;const l=e==="shutdown-hook"||e==="shutdown-after-settle";if(l&&D.finishOpenToolGroup(!0),l&&(D.hasSummaryTasks()||q.hasTasks())){if(le)return;le=!0,Promise.allSettled([D.waitForSummaryTasks(),q.waitForTasks()]).finally(()=>Se(r));return}Se(r)},"disposeAndExit");globalThis[Bn]=C,ce=ht({writable:t(()=>_.writableClients(),"writable"),forward:t((e,r)=>_.sendFrame(e,r),"forward"),pending:H,broadcast:t(e=>_.broadcastUi(e),"broadcast"),onKnownStreamWait:t(e=>L.knownStreamWait(e),"onKnownStreamWait")}),m.setRebindSession(),await m.enqueueRebind(K,P),d("broker.startup.extensions_bound");const x=qn({nodeId:n,registry:_,toolGroups:D,projection:L,rebind:m,boundaryReviewId:k,pendingDialogs:H,sendWelcome:we,replayExtraPendingDialogsTo:Pe,reWelcomeAll:te,disposeAndExit:C,persistModelChoice:ve,broadcastModelChanged:_e,registryOf:se,formatModelSpec:$,formatExactModelSpec:ct,turnAdmission:ne,memoryInventory:y,runNode:T,onKickoffAdmitted:B.releaseKickoff});me=x.notifyTurnAccepted,ue=x.resetForSession,fe=x.pendingPromptDispatches;const Oe=2500;let re=!1;const De=t(async e=>{if(I||re)return;if(re=!0,m.isAgentRunActive()||m.session().isStreaming||x.pendingPromptDispatches()>0){const l=Date.now()+Oe;for(;x.pendingPromptDispatches()>0&&!m.session().isStreaming&&Date.now()<l;)await new Promise(p=>setTimeout(p,25));if(m.session().isStreaming){const p=l-Date.now();if(p>0){let h;try{zn(),await Promise.race([m.session().abort().then(()=>!0,()=>!1),new Promise(U=>{h=setTimeout(()=>U(!1),p)})])&&await Ce(n,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(x.pendingPromptDispatches()>0||m.isAgentRunActive())&&await Ce(n,{event:"interrupted"})}C(e)},"abortAndExit");if(R=t(e=>{De(e)},"signalTeardown"),A!==void 0){R(A);return}try{Re(j)&&Te(j)}catch{}const be=t(e=>{const r=_.create(e);e.on("data",p=>{let h;try{h=r.decoder.push(p)}catch(u){u instanceof dt?(_.sendFrame(r,{type:"error",code:"frame_overflow",message:u.message}),_.dropClient(r,`frame overflow: ${u.message}`)):_.dropClient(r,`decoder error: ${String(u)}`);return}for(const u of h)try{Vn(x,r,u)}catch{}});const l=t(()=>{_.removeClient(r)},"drop");e.on("close",l),e.on("error",()=>{})},"serveViewer");Y=Ge(be),vn()!==void 0&&(z=new je({host:"::",port:Ve,path:"/view",maxPayload:at.maxLineBytes}),z.on("connection",e=>be(qe(e))),z.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))})),Y.on("error",e=>{I||(b({level:"error",event:"broker.socket.failed",error:e}),C("socket-error",1))}),Y.listen(j,async()=>{Promise.all([Q(n,{op:"clear",link:"viewer\u2194broker"}),Q(n,{op:"clear",link:"relay\u2194broker"})]).catch(r=>b({level:"error",event:"broker.daemon.operation.failed",node_id:n,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await V.recoverOnStartup()}catch(r){b({level:"error",event:"broker.daemon.operation.failed",node_id:n,error:r,fields:{operation:"recovery_startup"}}),C("recovery-startup-failed",1);return}if(!(I||re))if(e==="none"&&g.firstPrompt!==void 0&&g.firstPrompt!==""){const r=nt(process.env[tt]);r!==null&&rt(g.firstPrompt,r);try{await _n(n)}catch(p){b({level:"error",event:"broker.daemon.operation.failed",node_id:n,error:p,fields:{operation:"attachments_fetch"}}),C("attachments-fetch-failed",1);return}const l=process.env.CRTR_KICKOFF_MESSAGE_IDS;x.kickoff(g.firstPrompt,l?JSON.parse(l):[])}else B.releaseKickoff()}),_.persistAttachState()}t(Cr,"runBroker");function pt(n){const o=new Set;for(const s of n)if(!(s.role!=="assistant"||!Array.isArray(s.content)))for(const f of s.content)f!==null&&typeof f=="object"&&f.type==="toolCall"&&typeof f.id=="string"&&o.add(f.id);return o}t(pt,"toolCallIds");function ae(n,o){const s=n.sessionManager,f=En(s);return f!==void 0&&Xn(f.map(({message:i})=>i)),f===void 0?void 0:xn(f,{boundaryReviewId:o,sessionEntries:s.getEntries?.()})}t(ae,"snapshotMessages");function Me(){const n=Ue();if(n===void 0||n==="")throw new Error("broker launch is missing CRTR_NODE_ID");return n}t(Me,"currentBrokerNodeId");async function gt(n,o){const s=hn(o.model,Le(),o.modelExact===!0);if(s===void 0)return;const f=se(n),i={cwd:Be()??o.cwd,profileId:$e()},a=await bn(s,f,i);if(a!==void 0)throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const c=await wn(s,i.cwd,i.profileId),d=Sn(s.spec);for(const v of c){const w=f.find(v.providerId,v.modelId);if(w===void 0)continue;const S=d?.providerId===v.providerId&&d.modelId===v.modelId?d.thinkingLevel??(v.thinkingLevel===void 0?void 0:"off"):v.thinkingLevel;return{model:w,thinkingLevel:S}}if(o.modelExact===!0){const v=c.map(w=>`'${w.providerId}/${w.modelId}' unregistered`).join("; ");throw await Q(Me(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${v})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}b({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:c.map(v=>({provider:v.providerId,model:v.modelId,reason:"unregistered"})).slice(0,16)}})}t(gt,"resolveLaunchModel");function vt(n){let o=!0;return{runtime:new Proxy(n,{get(f,i,a){return o&&i==="getAvailableSnapshot"?()=>[]:o&&i==="getAvailable"?async()=>[]:o&&i==="getModel"?()=>{}:Reflect.get(f,i,a)}}),reveal:t(()=>{o=!1},"reveal")}}t(vt,"modelLessRegistry");async function _t(n,o){const s=J(),f=t(async S=>{const g=await Qe.create({credentials:new pn,modelsPath:Ee(S.agentDir,"models.json")});gn(g);const y=await n.createAgentSessionServices({cwd:S.cwd,agentDir:S.agentDir,modelRuntime:g,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:t(O=>({...O,extensions:O.extensions.filter(k=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(k.path))}),"extensionsOverride")}}),R=y.resourceLoader.getExtensions();if(o.extensionPaths.some(O=>oe.includes(O))){const O=new Set(R.extensions.map(T=>T.path)),k=oe.filter(T=>!O.has(T));if(k.length>0){const T=R.errors.filter(F=>oe.includes(F.path)).map(F=>`${F.path}: ${F.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${k.join(", ")}${T===""?"":` (${T})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const A=await gt(y,o),X=A?.model,K=A?.thinkingLevel,P=A===void 0?vt(y.modelRuntime):void 0,de=P!==void 0?{...y,modelRuntime:P.runtime}:y,G=await n.createAgentSessionFromServices({services:de,sessionManager:S.sessionManager,model:X,thinkingLevel:K,...ft(o.tools,We()),sessionStartEvent:S.sessionStartEvent});return Hn(G.session),fn(G.session),P?.reveal(),{...G,services:y}},"buildForManager"),i=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(i===void 0||i==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const c=!a&&i!==void 0&&i!=="",d=c&&o.newCycle===!0,v=c&&!d;let w;if(a)w=await n.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(v||d){if(w=await n.SessionManager.open(i),d){const S=w.getLeafId();w.resetLeaf(),w.appendCustomEntry(Tn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:S})}}else w=await n.SessionManager.create(o.cwd);if(n.createAgentSessionRuntime!==void 0){const S=t(async y=>{const R=await f({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...R,diagnostics:R.services.diagnostics??[]}},"factory"),g=await n.createAgentSessionRuntime(S,{cwd:o.cwd,agentDir:s,sessionManager:w});return{session:g.session,services:g.services,resuming:v,runtime:g}}const E=await f({cwd:o.cwd,agentDir:s,sessionManager:w});return{session:E.session,services:E.services,resuming:v,runtime:void 0}}t(_t,"buildBrokerSession");function ht(n){const o=t((i,a,c,d)=>{if(d?.signal?.aborted)return Promise.resolve(i);const v=n.writable();return v.length===0?Promise.resolve(i):new Promise(w=>{let E;const S=t(()=>{E!==void 0&&clearTimeout(E),d?.signal?.removeEventListener("abort",g),n.pending.delete(a.id)},"cleanup"),g=t(()=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},"onAbort");d?.signal?.addEventListener("abort",g,{once:!0});const y=d?.timeout!==void 0?d.timeout:mt;E=setTimeout(()=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(i)},y),typeof E.unref=="function"&&E.unref(),n.pending.set(a.id,{request:a,resolve:t(R=>{S(),n.broadcast({type:"extension_ui_dismiss",id:a.id}),w(c(R))},"resolve")});for(const R of v)n.forward(R,a)})},"dialogPromise"),s=t(()=>{},"noop");return{[yn]:n.onKnownStreamWait??(i=>()=>{}),get theme(){const i=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(i==null)throw new Error("Theme not initialized. Call initTheme() first.");return i},select:t((i,a,c)=>o(void 0,{type:"extension_ui_request",id:M(),method:"select",title:i,options:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"select"),confirm:t((i,a,c)=>o(!1,{type:"extension_ui_request",id:M(),method:"confirm",title:i,message:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,c),"confirm"),input:t((i,a,c)=>o(void 0,{type:"extension_ui_request",id:M(),method:"input",title:i,placeholder:a,timeout:c?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,c),"input"),editor:t((i,a)=>o(void 0,{type:"extension_ui_request",id:M(),method:"editor",title:i,prefill:a},c=>"cancelled"in c&&c.cancelled?void 0:"value"in c?c.value:void 0),"editor"),setStatus:t((i,a)=>n.broadcast({type:"extension_ui_request",id:M(),method:"setStatus",statusKey:i,statusText:a}),"setStatus"),setWidget:t((i,a,c)=>{typeof a!="function"&&n.broadcast({type:"extension_ui_request",id:M(),method:"setWidget",widgetKey:i,widgetLines:a,widgetPlacement:c?.placement})},"setWidget"),setTitle:t(i=>n.broadcast({type:"extension_ui_request",id:M(),method:"setTitle",title:i}),"setTitle"),notify:t((i,a)=>{const c=a==="warn"?"warning":a;n.broadcast({type:"extension_ui_request",id:M(),method:"notify",message:i,notifyType:c})},"notify"),onTerminalInput:t(()=>s,"onTerminalInput"),setWorkingMessage:s,setWorkingVisible:s,setWorkingIndicator:s,setHiddenThinkingLabel:s,setFooter:s,setHeader:s,custom:t(()=>Promise.resolve(void 0),"custom"),pasteToEditor:s,setEditorText:s,getEditorText:t(()=>"","getEditorText"),addAutocompleteProvider:s,setEditorComponent:s,getEditorComponent:t(()=>{},"getEditorComponent"),getAllThemes:t(()=>[],"getAllThemes"),getTheme:t(()=>{},"getTheme"),setTheme:s,getToolsExpanded:t(()=>!1,"getToolsExpanded"),setToolsExpanded:s}}t(ht,"makeBrokerUiContext");export{Pr as REVIEW_BOUNDARY_NAVIGATION_CODE,Ar as ReviewBoundaryNavigationError,ft as brokerToolOptions,_t as buildBrokerSession,ut as disposeActiveSession,ht as makeBrokerUiContext,Cr as runBroker,ae as snapshotMessages};
@@ -102,4 +102,10 @@ export declare function reviveNode(nodeId: string, opts: ReviveOptions): Promise
102
102
  * cron in place. Anything the person types reaches the node as a message, and
103
103
  * that delivery is the wake that consumes the deadline. */
104
104
  export declare function decideAttachRevive(nodeId: string, opts: Omit<ReviveOptions, 'viewerAttach'>, wakeParked: boolean): Promise<AttachReviveDecision>;
105
+ /** A recorded cwd that no longer exists (e.g. a closed managed worktree whose tombstone dir was later
106
+ * reaped) can never host a launch. Fail loud with a typed, user-visible error naming the path instead
107
+ * of letting `headlessBrokerHost.launch` fail deep inside the crash/doctrine-wake catch, where it would
108
+ * surface as an opaque `internal error` (toErrorBody masks every 5xx). Callers admit work to a node
109
+ * with this before changing any state. Returns the node's Blaxel environment (null on a machine). */
110
+ export declare function assertRecordedCwdExists(nodeId: string, meta: NodeMeta): Promise<string | null>;
105
111
  export {};
@@ -1,3 +1,3 @@
1
- var te=Object.defineProperty;var l=(e,r)=>te(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ne}from"./unsandboxed.js";import{existsSync as M}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ae}from"node:path";import{findNodeBySessionFile as oe,getNode as $,updateNode as N,beginExecution as se,ExecutionAlreadyLive as le,recordExecutionPid as ce,abortExecution as C,endLiveExecution as ue,unbindSession as U,recordLaunch as fe,setFrozen as we,clearFrozen as G,fullName as de}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as he}from"../feed/messages.js";import{isParked as W,transition as F}from"./lifecycle.js";import{publishNotice as pe}from"./close.js";import{InputError as A}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as me,drainBearings as ve,hasRetainedReports as _e,readGoal as g,readYieldMessage as ye,RUNTIME_RESTART_CONTINUATION as ke}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ge,KICKOFF_ORIGIN_ENV as be}from"./stamp/protocol.js";import{headlessBrokerHost as Re,brokerLaunchJson as xe}from"./host.js";import{processRunner as Ee}from"./runner/process.js";import{runnerForEnvironment as Se}from"./runner/index.js";import{blaxelEnvironmentOf as j}from"./blaxel-environment.js";import{recordLaunchFailure as $e}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Ne,checkBilledWake as Ce,EnvironmentImagePending as Fe,imageForWake as Ae}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Pe,liveExecutionForNode as Be,setExecutionLaunchJson as Oe}from"../canvas/executions.js";import{appMemoryFull as De,appMemoryTooSmall as Te,boundFleet as V,brokerCapReached as X,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as Le}from"./memory-admission.js";import{beginBootFaultAttempt as ze,clearFault as Me,hasAdmittedTurn as He}from"../canvas/recovery.js";import{clearNodeLedger as Y,forkNodeLedger as Ue,noticeChangedWhileDone as Ge}from"./ledger.js";import{forkSourceNode as Ke,rootOfSpine as We}from"./nodes.js";import{ApiError as Je}from"../../api/errors.js";import{grantSnapshotMissing as je}from"../../daemon/readiness.js";import{checkStart as Ve}from"./start-check.js";import{isReviewCompanionBound as Xe}from"../review/companion.js";import{assertProfileActive as Ye}from"../profiles/manifest.js";import{isPidAlive as qe}from"../canvas/pid.js";import{crtrHome as Qe,jobDir as Ze}from"../canvas/paths.js";import{contextDir as Ie,ensureNodeDirs as er,nodeAgentDir as rr}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as ir}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as tr}from"../command-hooks/transport/exec-lifecycle.js";async function nr(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(nr,"resumeArgs");async function q(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(q,"conversationExists");async function ar(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(ar,"sessionHasConversation");async function or(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||M(i)}l(or,"sessionCwdExists");async function sr(e,r,i,t){const a=r.pi_session_file;if(!a||!await q(a))return{};const w=await oe(a);return w!==null&&w.node_id!==e&&qe(w.pi_pid)?{}:t&&!await or(a)?{}:await nr(r,i)}l(sr,"resumableSessionArgs");async function lr(e){return await J(e)===null&&await ye(e)===null&&!await _e(e)}l(lr,"isUnstartedBirth");async function Xr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}l(Xr,"hasFreshGroundState");async function Yr(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(Yr,"reviveNode");async function qr(e,r,i){return Q(e,{...r,viewerAttach:!0},i)}l(qr,"decideAttachRevive");async function Q(e,r,i){let t=await $(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await $(e)??t,t.run_id&&(await $(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.`);Ye(t.profile_id),ne(t.grantee);const a=V(),w=t.grantee==="app:terminal"&&await je();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&W(t))&&(await Ve(t),await j(t.profile_id??null)!==null&&await Ce(t)),await a.has(e))return await F(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"&&W(t))return{parked:!0};if(w){if(r.capacity==="refuse")throw new Je(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await Z(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const c=await a.reserveSlot(e);let o=null;if(c){try{o=await Le(e)}catch(b){throw a.releaseReservation(e),b}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Te(o);if(!c||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?De(o):X(P().automaticReviveCap,await a.occupancy());return await Z(e,t,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:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await cr(e,t,r)}}finally{a.releaseReservation(e)}}l(Q,"decideRevive");async function Z(e,r,i){r.frozen_at==null&&(await we(e,new Date().toISOString()),await ue(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:i}))}l(Z,"freezeForWait");async function cr(e,r,i){const t=await j(r.profile_id??null);if(t===null&&!M(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 A({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await N(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Xe(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 w=r.fork_from!=null&&r.pi_session_id==null,c=r.fork_source_file;if(w&&(typeof c!="string"||!ae(c)))throw new A({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 o=w&&typeof c=="string";if(o&&!await q(c))throw new A({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${c}`,next:`Restore ${c}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:b}=P();if(t!==null){const s=await Ae(t);if(s.state==="pending")throw new Fe(t,s.error)}const I=t===null?Ee:Se("blaxel");let f;try{f=await se(e,{daemonEpoch:V().epoch(),cap:b,...t===null?{}:{runner:"blaxel",release:Ne()}})}catch(s){if(s instanceof Pe)throw X(s.cap,s.live);if(s instanceof le)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await N(e,{cycles:r.cycles});const R=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=o?{}:await sr(e,r,R,t===null),y=h.resumeSessionPath!==void 0,B=y&&h.newCycle===!0,m=y&&!B,O=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await lr(e),x=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await ar(h.resumeSessionPath)?(await g(e))?.trim():void 0,D=x!==void 0&&x!=="",ee=o||O||D,T=r.cycle_pending===!0||B;await N(e,{cycle_pending:T}),r.cycle_pending=T,!o&&!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 u,d=null;const E=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(o){const n=await g(e),S=v(c);if(S===null)throw new Error(`invalid fork source ${c}`);const ie=(await p().header(await p().fork(S,e))).path;u=_(r,{resumeSessionPath:ie,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=E()),await Ue(e,(await Ke(c))?.node_id??null)}else if(D)u=_(r,{...h,prompt:x}),d=E();else if(m)u=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ke}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(O){const n=(await g(e))?.trim();u=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=E()),await Y(e)}else{const n=await ve(r,f);u=_(r,{...h,prompt:await me(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(u.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 Y(e)}u.env={...u.env,CRTR_SUBTREE:await We(e)},d!==null&&(u.env[be]=ge(d)),r.status==="done"&&r.last_settled_at!=null&&await Ge(e,r.last_settled_at),await F(e,r.intent==="refresh"?"refresh-launch":"revive"),await Me(e,{preserveEpisode:!0});const L=await ze(e);i.recovery!==!0&&i.viewerAttach!==!0&&await he(e),await er(e,r.grantee);const re=ir(r.cwd,r.profile_id).plans.get("node:start")??[];await tr(re,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await rr(e),contextDir:await Ie(e),jobDir:Ze(e)},runtime:{isBirth:ee,canvasHome:Qe(),profile:r.profile_id??null}}),u.env={...u.env,CRTR_EXECUTION_ID:f};const z=await xe(e,u,r.cwd);await Oe(f,z);let k;try{const n=await Be(e);if(k=await I.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await F(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await pe(e,"notice.crash",`Child crashed \u2014 ${de(r)} (${e}) failed to relaunch and is now dead: ${n.message}
1
+ var te=Object.defineProperty;var s=(e,r)=>te(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ne}from"./unsandboxed.js";import{existsSync as M}from"node:fs";import{conversationIdFromPath as v,conversationStore as h,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ae}from"node:path";import{findNodeBySessionFile as oe,getNode as $,updateNode as C,beginExecution as se,ExecutionAlreadyLive as le,recordExecutionPid as ce,abortExecution as N,endLiveExecution as ue,unbindSession as U,recordLaunch as fe,setFrozen as we,clearFrozen as G,fullName as de}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as pe}from"../feed/messages.js";import{isParked as W,transition as F}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as A}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as me,drainBearings as ve,hasRetainedReports as _e,readGoal as g,readYieldMessage as ye,RUNTIME_RESTART_CONTINUATION as ke}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ge,KICKOFF_ORIGIN_ENV as be}from"./stamp/protocol.js";import{headlessBrokerHost as Re,brokerLaunchJson as xe}from"./host.js";import{processRunner as Ee}from"./runner/process.js";import{runnerForEnvironment as Se}from"./runner/index.js";import{blaxelEnvironmentOf as j}from"./blaxel-environment.js";import{recordLaunchFailure as $e}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Ce,checkBilledWake as Ne,EnvironmentImagePending as Fe,imageForWake as Ae}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Pe,liveExecutionForNode as Be,setExecutionLaunchJson as Oe}from"../canvas/executions.js";import{appMemoryFull as De,appMemoryTooSmall as Te,boundFleet as V,brokerCapReached as X,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as Le}from"./memory-admission.js";import{beginBootFaultAttempt as ze,clearFault as Me,hasAdmittedTurn as He,readFault as Ue}from"../canvas/recovery.js";import{clearNodeLedger as Y,forkNodeLedger as Ge,noticeChangedWhileDone as Ke}from"./ledger.js";import{forkSourceNode as We,rootOfSpine as Je}from"./nodes.js";import{ApiError as je}from"../../api/errors.js";import{grantSnapshotMissing as Ve}from"../../daemon/readiness.js";import{checkStart as Xe}from"./start-check.js";import{isReviewCompanionBound as Ye}from"../review/companion.js";import{assertProfileActive as qe}from"../profiles/manifest.js";import{isPidAlive as Qe}from"../canvas/pid.js";import{crtrHome as Ze,jobDir as Ie}from"../canvas/paths.js";import{contextDir as er,ensureNodeDirs as rr,nodeAgentDir as ir}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as tr}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as nr}from"../command-hooks/transport/exec-lifecycle.js";async function ar(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await h().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}s(ar,"resumeArgs");async function q(e){const r=v(e);if(r===null)return!1;try{return await h().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}s(q,"conversationExists");async function or(e){const r=v(e);return r===null?!0:(await h().read(r)).entries.some(i=>i.type==="message")}s(or,"sessionHasConversation");async function sr(e){const r=v(e);if(r===null)return!0;const i=(await h().header(r)).header.cwd;return typeof i!="string"||M(i)}s(sr,"sessionCwdExists");async function lr(e,r,i,t){const a=r.pi_session_file;if(!a||!await q(a))return{};const w=await oe(a);return w!==null&&w.node_id!==e&&Qe(w.pi_pid)?{}:t&&!await sr(a)?{}:await ar(r,i)}s(lr,"resumableSessionArgs");async function cr(e){return await J(e)===null&&await ye(e)===null&&!await _e(e)}s(cr,"isUnstartedBirth");async function qr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}s(qr,"hasFreshGroundState");async function Qr(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}s(Qr,"reviveNode");async function Zr(e,r,i){return Q(e,{...r,viewerAttach:!0},i)}s(Zr,"decideAttachRevive");async function Q(e,r,i){let t=await $(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await $(e)??t,t.run_id&&(await $(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.`);qe(t.profile_id),ne(t.grantee);const a=V(),w=t.grantee==="app:terminal"&&await Ve();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&W(t))&&(await Xe(t),await j(t.profile_id??null)!==null&&await Ne(t)),await a.has(e))return await F(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"&&W(t))return{parked:!0};if(w){if(r.capacity==="refuse")throw new je(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await Z(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const l=await a.reserveSlot(e);let o=null;if(l){try{o=await Le(e)}catch(b){throw a.releaseReservation(e),b}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Te(o);if(!l||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?De(o):X(P().automaticReviveCap,await a.occupancy());return await Z(e,t,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:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await fr(e,t,r)}}finally{a.releaseReservation(e)}}s(Q,"decideRevive");async function Z(e,r,i){r.frozen_at==null&&(await we(e,new Date().toISOString()),await ue(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:i}))}s(Z,"freezeForWait");async function ur(e,r){const i=await j(r.profile_id??null);if(i===null&&!M(r.cwd)){const t=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 A({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:t})}return i}s(ur,"assertRecordedCwdExists");async function fr(e,r,i){const t=await ur(e,r);r.host_kind!=="broker"&&(await C(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Ye(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 w=r.fork_from!=null&&r.pi_session_id==null,l=r.fork_source_file;if(w&&(typeof l!="string"||!ae(l)))throw new A({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 o=w&&typeof l=="string";if(o&&!await q(l))throw new A({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${l}`,next:`Restore ${l}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:b}=P();if(t!==null){const c=await Ae(t);if(c.state==="pending")throw new Fe(t,c.error)}const I=t===null?Ee:Se("blaxel");let f;try{f=await se(e,{daemonEpoch:V().epoch(),cap:b,...t===null?{}:{runner:"blaxel",release:Ce()}})}catch(c){if(c instanceof Pe)throw X(c.cap,c.live);if(c instanceof le)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw c}try{r.cycles=(r.cycles??0)+1,await C(e,{cycles:r.cycles});const R=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,p=o?{}:await lr(e,r,R,t===null),y=p.resumeSessionPath!==void 0,B=y&&p.newCycle===!0,m=y&&!B,O=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await cr(e),x=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await or(p.resumeSessionPath)?(await g(e))?.trim():void 0,D=x!==void 0&&x!=="",ee=o||O||D,T=r.cycle_pending===!0||B;await C(e,{cycle_pending:T}),r.cycle_pending=T,!o&&!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 u,d=null;const E=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(o){const n=await g(e),S=v(l);if(S===null)throw new Error(`invalid fork source ${l}`);const ie=(await h().header(await h().fork(S,e))).path;u=_(r,{resumeSessionPath:ie,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=E()),await Ge(e,(await We(l))?.node_id??null)}else if(D)u=_(r,{...p,prompt:x}),d=E();else if(m)u=_(r,{...p,...i.wakeReason==="runtime-restart-abort"?{prompt:ke}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(O){const n=(await g(e))?.trim();u=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=E()),await Y(e)}else{const n=await ve(r,f);u=_(r,{...p,prompt:await me(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(u.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 Y(e)}u.env={...u.env,CRTR_SUBTREE:await Je(e)},d!==null&&(u.env[be]=ge(d)),r.status==="done"&&r.last_settled_at!=null&&await Ke(e,r.last_settled_at),await F(e,r.intent==="refresh"?"refresh-launch":"revive"),(await Ue(e))?.op!=="conversation_write_failed"&&await Me(e,{preserveEpisode:!0});const L=await ze(e);i.recovery!==!0&&i.viewerAttach!==!0&&await pe(e),await rr(e,r.grantee);const re=tr(r.cwd,r.profile_id).plans.get("node:start")??[];await nr(re,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await ir(e),contextDir:await er(e),jobDir:Ie(e)},runtime:{isBirth:ee,canvasHome:Ze(),profile:r.profile_id??null}}),u.env={...u.env,CRTR_EXECUTION_ID:f};const z=await xe(e,u,r.cwd);await Oe(f,z);let k;try{const n=await Be(e);if(k=await I.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await F(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 ${de(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 C(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await fe(e,new Date().toISOString()),t!==null)return await G(e),{window:null,session:r.tmux_session??null,resumed:m,faultExplanation:L.explanation,outcome:"launched"};if(await ce(f,e,k.pid)==="shutdown")throw await C(f,{reason:"superseded"}),Re.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await G(e),{window:null,session:r.tmux_session??null,resumed:m,launch:k,faultExplanation:L.explanation,outcome:"launched"}}catch(s){throw await C(f,{reason:"launch_failed"}),await $e(f,s).catch(R=>{K({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:R})}),s}}l(cr,"launchRevive");export{qr as decideAttachRevive,Xr as hasFreshGroundState,nr as resumeArgs,Yr as reviveNode};
3
+ It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await N(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await fe(e,new Date().toISOString()),t!==null)return await G(e),{window:null,session:r.tmux_session??null,resumed:m,faultExplanation:L.explanation,outcome:"launched"};if(await ce(f,e,k.pid)==="shutdown")throw await N(f,{reason:"superseded"}),Re.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await G(e),{window:null,session:r.tmux_session??null,resumed:m,launch:k,faultExplanation:L.explanation,outcome:"launched"}}catch(c){throw await N(f,{reason:"launch_failed"}),await $e(f,c).catch(R=>{K({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:R})}),c}}s(fr,"launchRevive");export{ur as assertRecordedCwdExists,Zr as decideAttachRevive,qr as hasFreshGroundState,ar as resumeArgs,Qr as reviveNode};
@@ -1 +1 @@
1
- var _=Object.defineProperty;var a=(e,u)=>_(e,"name",{value:u,configurable:!0});import{spawn as R}from"node:child_process";import{createHash as b}from"node:crypto";import{captureTeardownSnapshot as k,isAnyPidAlive as x,killProcessTreePids as H}from"../canvas/pid.js";import{CRON_DEATH_POLL_MS as G,CRON_KILL_GRACE_MS as B,newHeadCapture as I}from"../../daemon/cron/capture.js";import{resolveAdmittedHostCommand as L}from"./spawn-env.js";import{appProcessSandboxed as K,launchAppProcess as N}from"../spaces/process.js";import{assertGranteeRunsHere as q}from"./unsandboxed.js";async function X(e){if(q(e.app),!K()){if(e.isolated)throw new Error("isolated cron requires the root launcher");return $(e)}const u=Date.now(),n=await N({nodeId:e.nodeId,app:e.app,isolated:e.isolated,...e.principal===void 0?{}:{principal:e.principal},...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron},command:[L("bash",e.env,e.cwd),"-c",e.command],cwd:e.cwd,env:e.env,stdoutBytes:e.headBytes,stderrBytes:e.headBytes});let m=!1,i;const p=a(()=>{n.stop().catch(t=>{console.error(`app command ${n.pid} could not be stopped:`,t)})},"terminate");i=setTimeout(()=>{m=!0,p()},e.timeoutMs),i.unref?.();const o=n.completion.then(t=>({exitCode:t.exitCode,signal:t.signal,stdout:t.stdout,stderr:t.stderr,stdoutTruncated:t.stdoutTruncated,stderrTruncated:t.stderrTruncated,stdoutSha256:t.stdoutSha256,timedOut:m,durationMs:Date.now()-u,processError:null})).finally(()=>{i&&clearTimeout(i)});return{pid:n.pid,completion:o,terminate:p}}a(X,"runAppCommand");function $({command:e,cwd:u,env:n,timeoutMs:m,headBytes:i}){const p=Date.now(),o=R(L("bash",n,u),["-c",e],{cwd:u,env:n,detached:!0,stdio:["ignore","pipe","pipe"]}),t=o.pid??null,h=I(i),T=I(i),P=b("sha256");o.stdout?.on("data",d=>{P.update(d),h.take(d)}),o.stderr?.on("data",d=>T.take(d));let g=!1,w=null,s,v=null,c=!1,y=!1,l,f,C,r,D;const M=new Promise(d=>{D=d}),S=a(()=>{c||s===void 0||(c=!0,l!==void 0&&clearTimeout(l),f!==void 0&&clearTimeout(f),C!==void 0&&clearTimeout(C),D({exitCode:s,signal:v,stdout:h.decode(),stdoutTruncated:h.truncated(),stderr:T.decode(),stderrTruncated:T.truncated(),timedOut:g,durationMs:Date.now()-p,stdoutSha256:P.digest("hex"),processError:w}))},"finish"),A=a(()=>{if(r===void 0||!x(r.tree)){S();return}C=setTimeout(A,G)},"awaitTeardownDeath"),E=a(()=>{t===null||c||(r??=k(t,null),H(r.tree,"SIGTERM",r.identities),f===void 0&&(f=setTimeout(()=>{x(r.tree)&&H(r.tree,"SIGKILL",r.identities),y=!0,s!==void 0&&A()},B),f.unref?.()))},"terminate");return o.on("error",d=>{w===null&&(w=d),t===null&&(s=null,S())}),o.on("close",(d,O)=>{if(!c){if(s=d,v=O,l!==void 0&&clearTimeout(l),r!==void 0&&x(r.tree)){y&&A();return}S()}}),t!==null&&(l=setTimeout(()=>{c||(g=!0,E())},m),l.unref?.()),{pid:t,completion:M,terminate:E}}a($,"runCommandOnce");export{X as runAppCommand,$ as runCommandOnce};
1
+ var _=Object.defineProperty;var a=(e,u)=>_(e,"name",{value:u,configurable:!0});import{spawn as R}from"node:child_process";import{createHash as b}from"node:crypto";import{captureTeardownSnapshot as k,isAnyPidAlive as A,killProcessTreePids as H}from"../canvas/pid.js";import{CRON_DEATH_POLL_MS as G,CRON_KILL_GRACE_MS as B,newHeadCapture as I}from"../../daemon/cron/capture.js";import{resolveAdmittedHostCommand as L}from"./spawn-env.js";import{appProcessSandboxed as K,launchAppProcess as N}from"../spaces/process.js";import{assertGranteeRunsHere as q}from"./unsandboxed.js";async function X(e){if(q(e.app),!K()){if(e.isolated)throw new Error("isolated cron requires the root launcher");return $(e)}const u=Date.now(),i=await N({nodeId:e.nodeId,app:e.app,isolated:e.isolated,...e.principal===void 0?{}:{principal:e.principal},...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron},command:[L("bash",e.env,e.cwd),"-c",e.command],cwd:e.cwd,env:e.env,stdoutBytes:e.headBytes,stderrBytes:e.headBytes});let m=!1,o;const p=a(()=>{i.stop().catch(t=>{console.error(`app command ${i.pid} could not be stopped:`,t)})},"terminate");o=setTimeout(()=>{m=!0,p()},e.timeoutMs),o.unref?.();const n=i.completion.then(t=>({exitCode:t.exitCode,signal:t.signal,stdout:t.stdout,stderr:t.stderr,stdoutTruncated:t.stdoutTruncated,stderrTruncated:t.stderrTruncated,stdoutSha256:t.stdoutSha256,timedOut:m,durationMs:Date.now()-u,processError:null})).finally(()=>{o&&clearTimeout(o)});return{pid:i.pid,completion:n,terminate:p}}a(X,"runAppCommand");function $({command:e,cwd:u,env:i,timeoutMs:m,headBytes:o}){const p=Date.now(),n=R(L("bash",i,u),["-c",e],{cwd:u,env:i,detached:!0,stdio:["ignore","pipe","pipe"]}),t=n.pid??null,h=I(o),T=I(o),x=b("sha256");n.stdout?.on("data",d=>{x.update(d),h.take(d)}),n.stderr?.on("data",d=>T.take(d));let P=!1,w=null,l,g=null,c=!1,v=!1,s,f,C,r,D;const M=new Promise(d=>{D=d}),S=a(()=>{c||l===void 0||(c=!0,s!==void 0&&clearTimeout(s),f!==void 0&&clearTimeout(f),C!==void 0&&clearTimeout(C),D({exitCode:l,signal:g,stdout:h.decode(),stdoutTruncated:h.truncated(),stderr:T.decode(),stderrTruncated:T.truncated(),timedOut:P,durationMs:Date.now()-p,stdoutSha256:x.digest("hex"),processError:w}))},"finish"),y=a(()=>{if(r===void 0||!A(r.tree)){S();return}C=setTimeout(y,G)},"awaitTeardownDeath"),E=a(()=>{t===null||c||(r??=k(t,null),H(r.tree,"SIGTERM",r.identities),f===void 0&&(f=setTimeout(()=>{A(r.tree)&&H(r.tree,"SIGKILL",r.identities),n.stdout?.destroy(),n.stderr?.destroy(),v=!0,l!==void 0&&y()},B),f.unref?.()))},"terminate");return n.on("error",d=>{w===null&&(w=d),t===null&&(l=null,S())}),n.on("close",(d,O)=>{if(!c){if(l=d,g=O,s!==void 0&&clearTimeout(s),r!==void 0&&A(r.tree)){v&&y();return}S()}}),t!==null&&(s=setTimeout(()=>{c||(P=!0,E())},m),s.unref?.()),{pid:t,completion:M,terminate:E}}a($,"runCommandOnce");export{X as runAppCommand,$ as runCommandOnce};
@@ -13,6 +13,8 @@ export declare class BlaxelApiError extends Error {
13
13
  readonly code: string | null;
14
14
  constructor(status: number, code: string | null, message: string);
15
15
  }
16
+ /** Blaxel's sandbox API uses this 404 when the workload URL itself no longer exists. */
17
+ export declare const isWorkloadUnavailable: (error: unknown) => error is BlaxelApiError;
16
18
  export interface SandboxSpec {
17
19
  name: string;
18
20
  image: string;
@@ -1 +1 @@
1
- var w=Object.defineProperty;var p=(n,o)=>w(n,"name",{value:o,configurable:!0});function h(n=process.env){const o=p(i=>{const $=n[i];if(!$)throw new Error(`${i} is required for the Blaxel runner`);return $},"need");return{apiKey:o("BLAXEL_API_KEY"),workspace:o("BLAXEL_WORKSPACE"),region:o("BLAXEL_REGION")}}p(h,"blaxelConfigFromEnv");class E extends Error{static{p(this,"BlaxelApiError")}status;code;constructor(o,i,$){super($),this.status=o,this.code=i,this.name="BlaxelApiError"}}function f(n){const o=n.metadata.url;if(!o)throw new Error(`Blaxel sandbox ${n.metadata.name} has no url`);return{name:n.metadata.name,url:o,state:n.state??null,status:n.status??null}}p(f,"toInfo");function b(n){const o=n.fetch??fetch,i=n.controlUrl??"https://api.blaxel.ai/v0",$=p(()=>({authorization:`Bearer ${n.apiKey}`,"x-blaxel-workspace":n.workspace,"content-type":"application/json"}),"headers");async function c(e,t,s,r=[]){const a=await o(e,{method:t,headers:$(),...s===void 0?{}:{body:JSON.stringify(s)}}),l=await a.text();let x=null;if(l!=="")try{x=JSON.parse(l)}catch{x={raw:l}}if(!a.ok&&!r.includes(a.status)){const d=x??{},m=typeof d.message=="string"?d.message:typeof d.error=="string"?d.error:l.slice(0,300);throw new E(a.status,typeof d.code=="string"?d.code:null,`Blaxel ${t} ${e} failed (${a.status}): ${m}`)}return{status:a.status,json:x}}p(c,"call");const u=encodeURIComponent;return{config:n,async createSandbox(e){const t=[...e.ports??[]].map(l=>({name:l.name,target:l.target,protocol:"HTTP"})),s={metadata:{name:e.name},spec:{runtime:{image:e.image,memory:e.memoryMb,...t.length>0?{ports:t}:{}},region:n.region}},{status:r,json:a}=await c(`${i}/sandboxes`,"POST",s,[409]);if(r===409){const l=await this.getSandbox(e.name);if(l===null)throw new Error(`Blaxel sandbox ${e.name} reported as existing but cannot be read`);return{...l,created:!1}}return{...f(a),created:!0}},async getSandbox(e){const{status:t,json:s}=await c(`${i}/sandboxes/${u(e)}`,"GET",void 0,[404]);return t===404?null:f(s)},async deleteSandbox(e){await c(`${i}/sandboxes/${u(e)}`,"DELETE",void 0,[404])},async startProcess(e,t){const{json:s}=await c(`${e.url}/process`,"POST",t);return s},async getProcess(e,t){const{status:s,json:r}=await c(`${e.url}/process/${u(t)}`,"GET",void 0,[404]);return s===404?null:r},async stopProcess(e,t){await c(`${e.url}/process/${u(t)}`,"DELETE",void 0,[404])},async killProcess(e,t){await c(`${e.url}/process/${u(t)}/kill`,"DELETE",void 0,[404])},async exec(e,t,s,r,a){return await this.startProcess(e,{name:t,command:s,waitForCompletion:!0,timeout:r,...a?{env:a}:{}})},async putFile(e,t,s,r="0644"){await c(`${e.url}/filesystem/${t.replace(/^\/+/,"").split("/").map(u).join("/")}`,"PUT",{content:s,permissions:r})},async ensurePreview(e,t,s){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews`,"POST",{metadata:{name:t},spec:{port:s,public:!1}},[409]),a=r?.spec?.url;if(a)return a;const x=(await c(`${i}/sandboxes/${u(e)}/previews`,"GET")).json.find(d=>d.metadata.name===t);if(!x)throw new Error(`Blaxel preview ${t} of ${e} not found`);return x.spec.url},async createPreviewToken(e,t,s){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews/${u(t)}/tokens`,"POST",{spec:{expiresAt:s.toISOString()}}),a=r.spec;return{token:a.token,expiresAt:a.expiresAt}}}}p(b,"createBlaxelClient");export{E as BlaxelApiError,h as blaxelConfigFromEnv,b as createBlaxelClient};
1
+ var E=Object.defineProperty;var d=(s,o)=>E(s,"name",{value:o,configurable:!0});function h(s=process.env){const o=d(i=>{const f=s[i];if(!f)throw new Error(`${i} is required for the Blaxel runner`);return f},"need");return{apiKey:o("BLAXEL_API_KEY"),workspace:o("BLAXEL_WORKSPACE"),region:o("BLAXEL_REGION")}}d(h,"blaxelConfigFromEnv");class w extends Error{static{d(this,"BlaxelApiError")}status;code;constructor(o,i,f){super(f),this.status=o,this.code=i,this.name="BlaxelApiError"}}const b=d(s=>s instanceof w&&s.status===404&&s.code==="WORKLOAD_UNAVAILABLE","isWorkloadUnavailable");function $(s){const o=s.metadata.url;if(!o)throw new Error(`Blaxel sandbox ${s.metadata.name} has no url`);return{name:s.metadata.name,url:o,state:s.state??null,status:s.status??null}}d($,"toInfo");function A(s){const o=s.fetch??fetch,i=s.controlUrl??"https://api.blaxel.ai/v0",f=d(()=>({authorization:`Bearer ${s.apiKey}`,"x-blaxel-workspace":s.workspace,"content-type":"application/json"}),"headers");async function c(e,t,a,r=[]){const n=await o(e,{method:t,headers:f(),...a===void 0?{}:{body:JSON.stringify(a)}}),l=await n.text();let x=null;if(l!=="")try{x=JSON.parse(l)}catch{x={raw:l}}if(!n.ok&&!r.includes(n.status)){const p=x??{},m=typeof p.message=="string"?p.message:typeof p.error=="string"?p.error:l.slice(0,300);throw new w(n.status,typeof p.code=="string"?p.code:null,`Blaxel ${t} ${e} failed (${n.status}): ${m}`)}return{status:n.status,json:x}}d(c,"call");const u=encodeURIComponent;return{config:s,async createSandbox(e){const t=[...e.ports??[]].map(l=>({name:l.name,target:l.target,protocol:"HTTP"})),a={metadata:{name:e.name},spec:{runtime:{image:e.image,memory:e.memoryMb,...t.length>0?{ports:t}:{}},region:s.region}},{status:r,json:n}=await c(`${i}/sandboxes`,"POST",a,[409]);if(r===409){const l=await this.getSandbox(e.name);if(l===null)throw new Error(`Blaxel sandbox ${e.name} reported as existing but cannot be read`);return{...l,created:!1}}return{...$(n),created:!0}},async getSandbox(e){const{status:t,json:a}=await c(`${i}/sandboxes/${u(e)}`,"GET",void 0,[404]);return t===404?null:$(a)},async deleteSandbox(e){await c(`${i}/sandboxes/${u(e)}`,"DELETE",void 0,[404])},async startProcess(e,t){const{json:a}=await c(`${e.url}/process`,"POST",t);return a},async getProcess(e,t){const{status:a,json:r}=await c(`${e.url}/process/${u(t)}`,"GET",void 0,[404]);if(a===404){const n=r?.code;if(n==="WORKLOAD_UNAVAILABLE")throw new w(404,n,`Blaxel sandbox ${e.name} is unavailable`);return null}return r},async stopProcess(e,t){await c(`${e.url}/process/${u(t)}`,"DELETE",void 0,[404])},async killProcess(e,t){await c(`${e.url}/process/${u(t)}/kill`,"DELETE",void 0,[404])},async exec(e,t,a,r,n){return await this.startProcess(e,{name:t,command:a,waitForCompletion:!0,timeout:r,...n?{env:n}:{}})},async putFile(e,t,a,r="0644"){await c(`${e.url}/filesystem/${t.replace(/^\/+/,"").split("/").map(u).join("/")}`,"PUT",{content:a,permissions:r})},async ensurePreview(e,t,a){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews`,"POST",{metadata:{name:t},spec:{port:a,public:!1}},[409]),n=r?.spec?.url;if(n)return n;const x=(await c(`${i}/sandboxes/${u(e)}/previews`,"GET")).json.find(p=>p.metadata.name===t);if(!x)throw new Error(`Blaxel preview ${t} of ${e} not found`);return x.spec.url},async createPreviewToken(e,t,a){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews/${u(t)}/tokens`,"POST",{spec:{expiresAt:a.toISOString()}}),n=r.spec;return{token:n.token,expiresAt:n.expiresAt}}}}d(A,"createBlaxelClient");export{w as BlaxelApiError,h as blaxelConfigFromEnv,A as createBlaxelClient,b as isWorkloadUnavailable};