@north-light/cli 0.3.571 → 0.3.573

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 (58) hide show
  1. package/dist/api/contract.d.ts +1 -1
  2. package/dist/api/contract.js +1 -1
  3. package/dist/api/dto/broker-ops.d.ts +3 -0
  4. package/dist/api/dto/recovery.d.ts +7 -0
  5. package/dist/api/errors.d.ts +3 -0
  6. package/dist/api/errors.js +1 -1
  7. package/dist/builtin-memory/crouter-sdk/release-notes.md +7 -0
  8. package/dist/commands/dashboard.js +3 -1
  9. package/dist/core/auth-file.d.ts +2 -0
  10. package/dist/core/auth-file.js +1 -1
  11. package/dist/core/canvas/node-tokens.js +3 -3
  12. package/dist/core/canvas/recovery.d.ts +3 -0
  13. package/dist/core/canvas/recovery.js +2 -2
  14. package/dist/core/command.d.ts +2 -3
  15. package/dist/core/command.js +6 -6
  16. package/dist/core/grants/mirror.d.ts +3 -1
  17. package/dist/core/grants/mirror.js +2 -2
  18. package/dist/core/grants/terminal.d.ts +10 -0
  19. package/dist/core/grants/terminal.js +1 -0
  20. package/dist/core/llm/run.js +2 -2
  21. package/dist/core/model-auth/readiness.js +1 -1
  22. package/dist/core/providers/audit.js +2 -2
  23. package/dist/core/providers/call.d.ts +4 -0
  24. package/dist/core/providers/call.js +1 -1
  25. package/dist/core/providers/files.js +1 -1
  26. package/dist/core/runs/operations.js +6 -6
  27. package/dist/core/runtime/blaxel-environment.d.ts +2 -0
  28. package/dist/core/runtime/blaxel-environment.js +1 -0
  29. package/dist/core/runtime/broker/fault-retry.d.ts +4 -0
  30. package/dist/core/runtime/broker/fault-retry.js +1 -1
  31. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  32. package/dist/core/runtime/broker/rebind.js +1 -1
  33. package/dist/core/runtime/nodes.js +1 -1
  34. package/dist/core/runtime/revive.js +2 -2
  35. package/dist/core/runtime/spawn.js +2 -2
  36. package/dist/core/runtime/start-check.js +1 -1
  37. package/dist/core/runtime/warm-pool.js +1 -1
  38. package/dist/core/spaces/process.js +1 -1
  39. package/dist/core/spaces/space.d.ts +2 -1
  40. package/dist/core/spaces/space.js +2 -2
  41. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  42. package/dist/daemon/api/handlers/crons.js +1 -1
  43. package/dist/daemon/api/handlers/modelauth.js +1 -1
  44. package/dist/daemon/api/handlers/nodes.js +1 -1
  45. package/dist/daemon/reconcilers/action-lane.js +1 -1
  46. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  47. package/dist/daemon/reconcilers/node-lifecycle/launch-failure.d.ts +1 -0
  48. package/dist/daemon/reconcilers/node-lifecycle/launch-failure.js +1 -0
  49. package/dist/daemon/reconcilers/node-lifecycle/node-person.d.ts +9 -0
  50. package/dist/daemon/reconcilers/node-lifecycle/node-person.js +1 -0
  51. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +0 -2
  52. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -1
  53. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  54. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  55. package/docs/sdk/release-notes.md +7 -0
  56. package/package.json +2 -2
  57. package/packages/crouter-identity/package.json +1 -1
  58. package/runtime.lock.json +13 -13
@@ -1 +1 @@
1
- var O=Object.defineProperty;var a=(n,e)=>O(n,"name",{value:e,configurable:!0});import{deleteAuthCredential as y,readAuthCredentials as S,setAuthCredential as b}from"../../../core/auth-file.js";import{ApiError as i}from"../../../api/index.js";import{RunError as g}from"../../../core/runs/operations.js";import{usage as u}from"../../../core/errors.js";import{modelAuthReadiness as E}from"../../../core/model-auth/readiness.js";import{MANAGED_PROVIDER_IDS as v,OPENAI_CHATGPT_PROVIDER_ID as D,DuplicateSubscriptionError as I,commitManagedLogin as P,isManagedProvider as l,promoteSubscription as $,readSubscriptionPool as m,removeAllManagedAccounts as T,removeManagedAccount as j,renameSubscription as F}from"../../../core/subscription-state.js";import{cancelModelAuthFlow as M,completeModelAuthFlow as C,startModelAuthFlow as R,waitModelAuthFlow as L}from"../../../core/model-auth/flows.js";import{waitSeconds as G}from"../long-poll-wait.js";function k(n,e){if(typeof e!="string"||e==="")throw new i(400,"invalid_request",`oauth credential requires \`${n}\``);const t=Date.parse(e);if(Number.isNaN(t))throw new i(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return t}a(k,"parseExpiry");function c(n,e,t){if(typeof t!="string"||t==="")throw new i(400,"invalid_request",`${n} credential requires \`${e}\``);return t}a(c,"requireField");function N(n,e=Date.now()){const t=Object.entries(n.modelCooldowns??{}).filter(([,o])=>o>e).map(([o,r])=>({family:o,rate_limited_until:new Date(r).toISOString()}));return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...t.length?{model_cooldowns:t}:{},...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}a(N,"toManagedAccountStatus");async function p(n){const e=(await m(n)).map(t=>N(t));return{provider:n,managed:!0,configured:e.length>0,accounts:e}}a(p,"managedStatus");function f(n,e){const t=n.query.getAll(e);if(t.length>1)throw u(`${e} must appear at most once`);return t[0]}a(f,"singleQueryValue");async function U(){const n=await S(),e=new Set;for(const r of v)r===D&&n[r]!==void 0&&(await m(r)).length===0&&e.add(r);const t=a(r=>e.has(r),"legacyApiKey"),o=await Promise.all(v.filter(r=>!t(r)).map(p));for(const[r,s]of Object.entries(n))l(r)&&!t(r)||s.type!=="api_key"&&s.type!=="oauth"||o.push({provider:r,managed:!1,configured:!0,kind:s.type});return{status:200,body:{providers:o}}}a(U,"handleList");async function K(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw u(`unknown model-auth readiness query parameter: ${s}`);const e=f(n,"profile"),t=f(n,"cwd"),o=f(n,"kind"),r=f(n,"model");if(o!==void 0&&o.trim()==="")throw u("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw u("model must be a non-empty string when provided");return{status:200,body:await E({...e!==void 0?{profile:e}:{},...t!==void 0?{cwd:t}:{},...o!==void 0?{kind:o}:{},...r!==void 0?{model:r}:{}})}}a(K,"handleReadiness");async function V(n){const e=n.params.provider,t=n.body;if(t===void 0||typeof t!="object"||typeof t.kind!="string")throw new i(400,"invalid_request","a credential `kind` is required");switch(t.kind){case"api_key":{const o=c("api_key","api_key",t.api_key);return await b(e,{type:"api_key",key:o}),{status:200,body:{provider:e,installed:!0,managed:!1}}}case"oauth":{if(l(e))throw new i(422,"unprocessable",`provider ${e} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const o=c("oauth","access_token",t.access_token),r=c("oauth","refresh_token",t.refresh_token),s=k("expires_at",t.expires_at),d=t.extra??{};await b(e,{type:"oauth",...d,access:o,refresh:r,expires:s});const w={provider:e,installed:!0,managed:!1};return typeof t.account_id=="string"&&t.account_id!==""&&(w.account_id=t.account_id),{status:200,body:w}}case"managed_account":{if(!l(e))throw new i(422,"unprocessable",`provider ${e} does not support managed accounts`);const o=typeof t.label=="string"&&t.label.trim()?t.label.trim():void 0;if(!o&&t.auto_label!==!0)throw new i(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof t.account_id=="string"&&t.account_id!==""?t.account_id:void 0,s=c("managed_account","access_token",t.access_token),d=c("managed_account","refresh_token",t.refresh_token),w=k("expires_at",t.expires_at),A=typeof t.last_rate_limited_at=="number"?t.last_rate_limited_at:Math.max(0,...(await m(e)).map(q=>q.lastRateLimitedAt));await P(e,o,{refresh:d,access:s,expires:w,...r?{accountId:r}:{},lastRateLimitedAt:A,autoLabel:t.auto_label===!0});const _={provider:e,installed:!0,managed:!0};return r&&(_.account_id=r),{status:200,body:_}}default:throw new i(400,"invalid_request",`unknown credential kind: ${String(t.kind)}`)}}a(V,"handleInstall");async function H(n){const e=n.params.provider;if(l(e)){const o=await T(e),r=await y(e);return{status:200,body:{provider:e,removed_accounts:o+(r?1:0)}}}const t=await y(e)?1:0;return{status:200,body:{provider:e,removed_accounts:t}}}a(H,"handleDelete");async function x(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);const t=h(n);for(const r of Object.keys(t))if(r!=="label"&&r!=="preferred")throw new i(400,"invalid_request",`unknown account field: ${r}`);if(t.label!==void 0&&typeof t.label!="string")throw new i(400,"invalid_request","`label` must be a string");if(t.preferred!==void 0&&t.preferred!==!0)throw new i(400,"invalid_request","`preferred` can only be true");if(t.label===void 0&&t.preferred===void 0)throw new i(400,"invalid_request","send `label` and/or `preferred`");let o=n.params.label;try{t.label!==void 0&&(await F(e,o,t.label),o=t.label.trim()),t.preferred&&await $(e,o)}catch(r){throw r instanceof Error&&/^Unknown .* subscription:/.test(r.message)?new i(404,"not_found",r.message):r instanceof I?new i(409,"conflict",r.message):r}return{status:200,body:await p(e)}}a(x,"handlePatchAccount");async function J(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);try{await j(e,n.params.label)}catch(t){throw t instanceof Error&&/^Unknown .* subscription:/.test(t.message)?new i(404,"not_found",t.message):t}return{status:200,body:await p(e)}}a(J,"handleDeleteAccount");function h(n){const e=n.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw new i(400,"invalid_request","request body must be a JSON object");return e}a(h,"bodyObject");async function Q(n){const e=h(n);return{status:200,body:await R({provider:e.provider,...e.redirect!==void 0?{redirect:e.redirect}:{},...e.label!==void 0?{label:e.label}:{}})}}a(Q,"handleFlowStart");async function z(n){const e=h(n);return{status:200,body:await C(n.params.flow_id,e.input)}}a(z,"handleFlowComplete");async function B(n){const e=await M(n.params.flow_id);if(!e)throw new g(400,"invalid_request","no sign-in has this flow_id","flow_id");const{jti:t,...o}=e;return{status:200,body:o}}a(B,"handleFlowCancel");async function W(n){for(const[d]of n.query)if(d!=="wait")throw u(`unknown model-auth flow query parameter: ${d}`);f(n,"wait");const e=G("model_auth.get",n.query),t=new AbortController;n.res.once("close",()=>t.abort());const o=await L(n.params.flow_id,e*1e3,t.signal);if(!o)throw new g(404,"not_found","no sign-in has this flow_id","flow_id");const{jti:r,...s}=o;return{status:200,body:s}}a(W,"handleFlowGet");const ie=[{method:"POST",pattern:"/v1/model-auth/flows",ownerOnly:!0,handler:Q},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/complete",ownerOnly:!0,handler:z},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/cancel",ownerOnly:!0,handler:B},{method:"GET",pattern:"/v1/model-auth/flows/:flow_id",ownerOnly:!0,handler:W},{method:"GET",pattern:"/v1/model-auth",handler:U},{method:"GET",pattern:"/v1/model-auth/readiness",handler:K},{method:"PUT",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:V},{method:"DELETE",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:H},{method:"DELETE",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:J},{method:"PATCH",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:x}];export{p as managedStatus,ie as modelAuthRoutes};
1
+ var O=Object.defineProperty;var o=(n,e)=>O(n,"name",{value:e,configurable:!0});import{deleteAuthCredential as y,readAuthCredentials as S,setAuthCredential as b,storedApiKey as E}from"../../../core/auth-file.js";import{ApiError as i}from"../../../api/index.js";import{RunError as g}from"../../../core/runs/operations.js";import{usage as u}from"../../../core/errors.js";import{modelAuthReadiness as D}from"../../../core/model-auth/readiness.js";import{MANAGED_PROVIDER_IDS as v,OPENAI_CHATGPT_PROVIDER_ID as I,DuplicateSubscriptionError as P,commitManagedLogin as $,isManagedProvider as l,promoteSubscription as T,readSubscriptionPool as m,removeAllManagedAccounts as j,removeManagedAccount as F,renameSubscription as M}from"../../../core/subscription-state.js";import{cancelModelAuthFlow as C,completeModelAuthFlow as R,startModelAuthFlow as L,waitModelAuthFlow as G}from"../../../core/model-auth/flows.js";import{waitSeconds as N}from"../long-poll-wait.js";function k(n,e){if(typeof e!="string"||e==="")throw new i(400,"invalid_request",`oauth credential requires \`${n}\``);const t=Date.parse(e);if(Number.isNaN(t))throw new i(400,"invalid_request",`\`${n}\` is not a valid ISO timestamp`);return t}o(k,"parseExpiry");function c(n,e,t){if(typeof t!="string"||t==="")throw new i(400,"invalid_request",`${n} credential requires \`${e}\``);return t}o(c,"requireField");function K(n,e=Date.now()){const t=Object.entries(n.modelCooldowns??{}).filter(([,a])=>a>e).map(([a,r])=>({family:a,rate_limited_until:new Date(r).toISOString()}));return{label:n.label,expires_at:new Date(n.expires).toISOString(),rate_limited_until:new Date(n.rateLimitedUntil).toISOString(),...t.length?{model_cooldowns:t}:{},...n.authFailure?{auth_failure:n.authFailure}:{},...n.accountId?{account_id:n.accountId}:{}}}o(K,"toManagedAccountStatus");async function p(n){const e=(await m(n)).map(t=>K(t));return{provider:n,managed:!0,configured:e.length>0,accounts:e}}o(p,"managedStatus");function f(n,e){const t=n.query.getAll(e);if(t.length>1)throw u(`${e} must appear at most once`);return t[0]}o(f,"singleQueryValue");async function U(){const n=await S(),e=new Set;for(const r of v)r===I&&n[r]!==void 0&&(await m(r)).length===0&&e.add(r);const t=o(r=>e.has(r),"legacyApiKey"),a=await Promise.all(v.filter(r=>!t(r)).map(p));for(const[r,d]of Object.entries(n))l(r)&&!t(r)&&(d.type!=="api_key"||await E(r)===void 0)||d.type!=="api_key"&&d.type!=="oauth"||a.push({provider:r,managed:!1,configured:!0,kind:d.type});return{status:200,body:{providers:a}}}o(U,"handleList");async function V(n){for(const[s]of n.query)if(s!=="profile"&&s!=="cwd"&&s!=="kind"&&s!=="model")throw u(`unknown model-auth readiness query parameter: ${s}`);const e=f(n,"profile"),t=f(n,"cwd"),a=f(n,"kind"),r=f(n,"model");if(a!==void 0&&a.trim()==="")throw u("kind must be a non-empty string when provided");if(r!==void 0&&r.trim()==="")throw u("model must be a non-empty string when provided");return{status:200,body:await D({...e!==void 0?{profile:e}:{},...t!==void 0?{cwd:t}:{},...a!==void 0?{kind:a}:{},...r!==void 0?{model:r}:{}})}}o(V,"handleReadiness");async function H(n){const e=n.params.provider,t=n.body;if(t===void 0||typeof t!="object"||typeof t.kind!="string")throw new i(400,"invalid_request","a credential `kind` is required");switch(t.kind){case"api_key":{const a=c("api_key","api_key",t.api_key);return await b(e,{type:"api_key",key:a}),{status:200,body:{provider:e,installed:!0,managed:!1}}}case"oauth":{if(l(e))throw new i(422,"unprocessable",`provider ${e} stores oauth credentials as managed accounts \u2014 use kind \`managed_account\``);const a=c("oauth","access_token",t.access_token),r=c("oauth","refresh_token",t.refresh_token),d=k("expires_at",t.expires_at),s=t.extra??{};await b(e,{type:"oauth",...s,access:a,refresh:r,expires:d});const w={provider:e,installed:!0,managed:!1};return typeof t.account_id=="string"&&t.account_id!==""&&(w.account_id=t.account_id),{status:200,body:w}}case"managed_account":{if(!l(e))throw new i(422,"unprocessable",`provider ${e} does not support managed accounts`);const a=typeof t.label=="string"&&t.label.trim()?t.label.trim():void 0;if(!a&&t.auto_label!==!0)throw new i(400,"invalid_request","managed_account credential requires `label` or `auto_label`");const r=typeof t.account_id=="string"&&t.account_id!==""?t.account_id:void 0,d=c("managed_account","access_token",t.access_token),s=c("managed_account","refresh_token",t.refresh_token),w=k("expires_at",t.expires_at),A=typeof t.last_rate_limited_at=="number"?t.last_rate_limited_at:Math.max(0,...(await m(e)).map(q=>q.lastRateLimitedAt));await $(e,a,{refresh:s,access:d,expires:w,...r?{accountId:r}:{},lastRateLimitedAt:A,autoLabel:t.auto_label===!0});const _={provider:e,installed:!0,managed:!0};return r&&(_.account_id=r),{status:200,body:_}}default:throw new i(400,"invalid_request",`unknown credential kind: ${String(t.kind)}`)}}o(H,"handleInstall");async function x(n){const e=n.params.provider;if(l(e)){const a=await j(e),r=await y(e);return{status:200,body:{provider:e,removed_accounts:a+(r?1:0)}}}const t=await y(e)?1:0;return{status:200,body:{provider:e,removed_accounts:t}}}o(x,"handleDelete");async function J(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);const t=h(n);for(const r of Object.keys(t))if(r!=="label"&&r!=="preferred")throw new i(400,"invalid_request",`unknown account field: ${r}`);if(t.label!==void 0&&typeof t.label!="string")throw new i(400,"invalid_request","`label` must be a string");if(t.preferred!==void 0&&t.preferred!==!0)throw new i(400,"invalid_request","`preferred` can only be true");if(t.label===void 0&&t.preferred===void 0)throw new i(400,"invalid_request","send `label` and/or `preferred`");let a=n.params.label;try{t.label!==void 0&&(await M(e,a,t.label),a=t.label.trim()),t.preferred&&await T(e,a)}catch(r){throw r instanceof Error&&/^Unknown .* subscription:/.test(r.message)?new i(404,"not_found",r.message):r instanceof P?new i(409,"conflict",r.message):r}return{status:200,body:await p(e)}}o(J,"handlePatchAccount");async function Q(n){const e=n.params.provider;if(!l(e))throw new i(400,"invalid_request",`${e} has no managed accounts`);try{await F(e,n.params.label)}catch(t){throw t instanceof Error&&/^Unknown .* subscription:/.test(t.message)?new i(404,"not_found",t.message):t}return{status:200,body:await p(e)}}o(Q,"handleDeleteAccount");function h(n){const e=n.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw new i(400,"invalid_request","request body must be a JSON object");return e}o(h,"bodyObject");async function z(n){const e=h(n);return{status:200,body:await L({provider:e.provider,...e.redirect!==void 0?{redirect:e.redirect}:{},...e.label!==void 0?{label:e.label}:{}})}}o(z,"handleFlowStart");async function B(n){const e=h(n);return{status:200,body:await R(n.params.flow_id,e.input)}}o(B,"handleFlowComplete");async function W(n){const e=await C(n.params.flow_id);if(!e)throw new g(400,"invalid_request","no sign-in has this flow_id","flow_id");const{jti:t,...a}=e;return{status:200,body:a}}o(W,"handleFlowCancel");async function X(n){for(const[s]of n.query)if(s!=="wait")throw u(`unknown model-auth flow query parameter: ${s}`);f(n,"wait");const e=N("model_auth.get",n.query),t=new AbortController;n.res.once("close",()=>t.abort());const a=await G(n.params.flow_id,e*1e3,t.signal);if(!a)throw new g(404,"not_found","no sign-in has this flow_id","flow_id");const{jti:r,...d}=a;return{status:200,body:d}}o(X,"handleFlowGet");const se=[{method:"POST",pattern:"/v1/model-auth/flows",ownerOnly:!0,handler:z},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/complete",ownerOnly:!0,handler:B},{method:"POST",pattern:"/v1/model-auth/flows/:flow_id/cancel",ownerOnly:!0,handler:W},{method:"GET",pattern:"/v1/model-auth/flows/:flow_id",ownerOnly:!0,handler:X},{method:"GET",pattern:"/v1/model-auth",handler:U},{method:"GET",pattern:"/v1/model-auth/readiness",handler:V},{method:"PUT",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:H},{method:"DELETE",pattern:"/v1/model-auth/:provider",ownerOnly:!0,handler:x},{method:"DELETE",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:Q},{method:"PATCH",pattern:"/v1/model-auth/:provider/accounts/:label",ownerOnly:!0,handler:J}];export{p as managedStatus,se as modelAuthRoutes};
@@ -1 +1 @@
1
- var Oe=Object.defineProperty;var d=(e,n)=>Oe(e,"name",{value:n,configurable:!0});import{envProfileId as Ae}from"../../../shared/env.js";import{pausedCanvasProfiles as $e}from"../../../core/profiles/manifest.js";import{existsSync as T,realpathSync as ee,statSync as ne}from"node:fs";import{isAbsolute as x,resolve as P}from"node:path";import{appendSituationalContext as Ce,formatSituationalProse as Ee}from"../../../core/runtime/situational-context.js";import{closeNode as Ne}from"../../../core/runtime/close.js";import{reviveNode as Te}from"../../../core/runtime/revive.js";import{nowIso as K}from"../../../core/fs-utils.js";import{appPaidLaunch as Pe,assertLaunchModelRegistered as V,forkNode as De,resolveForkSource as Le,spawnChildPrepared as je}from"../../../core/runtime/spawn.js";import{forkSourceNode as Me,newNodeId as te}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as ie,childrenOf as Ge,completeCreateRequest as re,findCreateRequest as oe,getNode as R,recordCreateRequestNode as Fe,reserveCreateRequest as ae,reserveCreateRequestNode as Be,listNodes as xe,recordRespawnAttempt as Ke,subscribersOf as Ve,subscriptionsOf as de,updateNode as E}from"../../../core/canvas/canvas.js";import{armControllerWait as We}from"../../../core/canvas/waits.js";import{withCanvasWrite as W}from"../../../core/canvas/db.js";import{markNodeRead as ze}from"../../../core/canvas/recovery.js";import{nodeObject as Je}from"../../../core/graph/objects.js";import{recordActedOn as Ue}from"../../../core/graph/edges.js";import{publish as Ye}from"../../../core/graph/events.js";import{readerFor as He}from"../reader.js";import{relocateSessionCwd as Qe,unbindSession as Xe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Ze}from"../../../core/canvas/attention.js";import{isSafeNodeId as qe}from"../../../core/canvas/paths.js";import{contextDir as se,nodeAgentDir as z}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as en,cronRefusalError as nn}from"../../cron/authority.js";import{cronBirthPlacement as tn}from"../../cron/armed-context.js";import{existsBeneath as rn,isAbsentOrRefused as on,isBeneathRefusal as an,readdirBeneath as dn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as sn,readNodeSession as ln,readNodeSnapshot as cn,transcriptMarkdown as un}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as fn}from"../../../core/substrate/subject.js";import{reviveAll as pn}from"../../../core/runtime/revive-all.js";import{promoteAsync as mn,requestYieldAsync as wn,reshapeNodeAsync as J}from"../../../core/runtime/promote.js";import{recycleNode as hn}from"../../../core/runtime/recycle.js";import{relaunchRoot as yn}from"../../../core/runtime/reset.js";import{assertReopenGate as _n}from"../../../core/runtime/reopen.js";import{requireCurrentExecution as gn}from"./broker-recovery.js";import{readOutputRequest as bn}from"../../../core/runtime/output-result.js";import{writeYieldMessage as vn,readGoal as kn,captureGoalIfAbsent as Sn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as Rn,hasRoadmap as In}from"../../../core/runtime/roadmap.js";import{renameWindow as On}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as An,explicitModelIntent as $n,normalizeModel as Cn,readMergedLaunchConfigAsync as le}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as En}from"../../../core/model-routes.js";import{persistDormantModel as Nn,setModelLive as Tn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as ce}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as Pn}from"../../../core/runtime/broker-request.js";import{boundFleet as D}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as Dn}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Ln}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as ue}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as jn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Mn}from"../../../core/human-actions.js";import{parseDurationMs as Gn}from"../../../core/wake.js";import{claimWarmNode as Fn,refillWarmPool as fe,resumeWarmClaim as Bn,warmPoolEnabled as xn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as U,isLaunchKind as Kn,resolveLaunchTarget as Vn}from"../../../core/runtime/launch-target.js";import{fullName as Wn}from"../../../core/canvas/labels.js";import{reportsForNode as pe}from"./reports.js";import{requireUsableProfile as zn}from"./profiles.js";import{assertProfileActive as Jn,loadExactProfileManifest as Un}from"../../../core/profiles/manifest.js";import{getCron as me}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Yn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Hn}from"../../control.js";import{notFound as L,usage as w}from"../../../core/errors.js";import{assertScope as Qn,validateScopes as we}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Xn,toNodeDetailDTO as Y,toNodeSummaryDTO as Zn,toReviveResultDTO as qn}from"../map.js";import{ApiError as p}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{actsAsPerson as j,canReadNode as $,readableNodeIds as et,resolvedScopes as nt}from"../router.js";import{forwardVerb as tt,queryWithoutMachine as it,relayError as rt,unknownError as ot,withMachine as at}from"../../peer/forward.js";import{fileRoot as dt}from"../../../core/spaces/file-root.js";import{activeGrant as st,payerOfGrant as lt,terminalGrant as ct}from"../../../core/grants/mirror.js";import{appRungForGrant as ut}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as ft}from"../../../core/model-routes.js";import{listProfileEnvNames as pt}from"../../../core/profiles/env-store.js";import{hasConfiguredProviderCredential as mt,NO_PROVIDER_CREDENTIAL_MESSAGE as he}from"../../../core/runtime/provider-credential-gate.js";import{filterAsync as wt,mapAsync as ye}from"../../../core/async-array.js";async function m(e){const n=await R(e);if(n===null)throw L(`unknown node: ${e}`,{received:e});return n}d(m,"requireMeta");async function H(e){return{subscribesTo:await de(e),subscribers:await Ve(e),children:await Ge(e)}}d(H,"edgesFor");async function b(e){const n=await m(e);return await Y(n,await H(e))}d(b,"detailOf");async function ht(e){let n=(await pe(e)).length;try{n+=dn(await z(e),await se(e)).length}catch(t){if(!on(t))throw t}return n}d(ht,"countFiles");function yt(e){if(typeof e!="object"||e===null)throw w("a node create requires a JSON body");const n=e;if(n.kind!==void 0&&(typeof n.kind!="string"||n.kind.trim()===""))throw w("kind must be a non-empty string when provided");if(n.description!==void 0&&(typeof n.description!="string"||n.description.trim()===""))throw w("description must be a non-empty string when provided");if(n.creator!==void 0&&(typeof n.creator!="string"||n.creator.trim()===""))throw w("creator must be a non-empty node id when provided");if(n.scopes!==void 0&&we(n.scopes),n.isolated!==void 0&&typeof n.isolated!="boolean")throw new p(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const t=n.root_lifecycle;if(t!==void 0&&t!=="resident"&&t!=="terminal")throw w("root_lifecycle must be 'resident' or 'terminal'");if(n.request_key!==void 0&&(typeof n.request_key!="string"||n.request_key.trim()===""||n.request_key.length>128))throw w("request_key must be a non-empty string of at most 128 characters when provided");return n}d(yt,"parseCreateBody");function _t(e){if(e===void 0)return;const n=Gn(e),t=n===null?null:new Date(Date.now()+n);if(n===null||!Number.isFinite(n)||n<=0||t===null||!Number.isFinite(t.getTime()))throw new p(422,"invalid_deadline","`deadline` must be a positive representable duration");return t.toISOString()}d(_t,"parseDeadline");function gt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new p(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!jn.test(e.action))throw new p(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let n;try{n=JSON.stringify(e.payload)}catch{throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(n===void 0)throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(n,"utf8")>ue)throw new p(413,"payload_too_large",`serialized payload exceeds ${ue} bytes`)}return e}}d(gt,"parseOutcomeDelivery");function bt(e,n){const t=Mn(e.action,n);if(!("kind"in t))return{actionName:e.action,argv:t.argv,cwd:t.cwd,configOrigin:t.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw t.kind==="unknown_action"?new p(422,"unknown_action",`no action named ${e.action} is declared from ${n}`):new p(422,"invalid_action",`${e.action} is declared in ${t.configOrigin} but unusable: ${t.reason}`,{reason:t.reason,configOrigin:t.configOrigin})}d(bt,"resolveOutcomeDelivery");function vt(e,n,t){const r={kind:e.kind,cwd:t,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),n!==void 0&&(r.parent=n),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=P(e.pin_cwd??e.cwd??t)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}d(vt,"buildRecipe");function kt(e,n,t){return!xn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:n,profileId:t,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}d(kt,"warmRequestFor");import{resolveCreateKind as Ir}from"../../../core/runtime/launch-target.js";function _e(e){const n=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return En(e.model,n,e.modelExact===!0)}d(_e,"requestFromLaunch");function St(e,n){if(n===null)return e;if(e.scopes===void 0)return{...e,scopes:[...n]};const t=e.scopes.filter(r=>!O(n,r));if(t.length===0)return e;throw new p(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${t.join(", ")}`,{scopes:t,ceiling:n})}d(St,"withinCeiling");async function ge(e,n,t){const r=(await An(n.kind,n.mode,{lifecycle:n.lifecycle,hasManager:e.parent!==null,model:n.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await V(_e(r),{cwd:e.cwd,profileId:e.profile_id??null},t)}d(ge,"assertNodeModelChangeRegistered");async function be(e,n){const t=e.principal;if(t.class!=="broker"&&t.class!=="cron")return;const r=dt({app:t.app,resolved:await nt(t),launched:t.scopes},n,"read");if("root"in r)return;const i="missing"in r?r.missing:null;throw new p(403,"scope_missing",i?`the child's directory ${n} needs missing scope ${i}`:`no permission of this run names the child's directory ${n}`,void 0,void 0,i?{scope:i}:void 0)}d(be,"assertCallerReaches");const Q=new Map;async function Rt(e,n={},t={}){const r=St(yt(e.body),e.ceiling);if(e.principal.class==="broker"){const s=e.principal;if(r.prefer_warm===!0&&s.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const o=await m(r.parent);if(o.grantee!==s.app)throw new p(403,"other_app_run","cannot create a child under another app's node");if(!await $(s,o.grantee??"app:terminal",r.parent))throw L(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==s.node)throw new p(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let o=null;try{o=await Me(await Le(r.fork_from))}catch{}if(o?.grantee!==s.app||!await $(s,o.grantee,o.node_id))throw new p(403,"other_app_run","cannot fork another app's conversation")}r.creator=s.node}if(e.principal.class==="cron"){const s=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new p(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1,r.node_id=await te(),s.isolated&&(r.isolated=!0,r.cwd=await z(r.node_id,s.app));const o=await en({grantee:s.app,sub:s.sub,grant_id:s.grant,scopes:s.scopes,from_exec:s.from_exec},{profile:r.profile,cwd:r.cwd,pin_cwd:r.pin_cwd,kind:r.kind,model:r.model,mode:r.mode});if(!o.allowed)throw nn(o);if(r.scopes!==void 0){const l=r.scopes.find(f=>!O(o.effectiveScopes,f)||!O(s.scopes,f));if(l!==void 0)throw new p(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else s.scopes!==null&&(r.scopes=[...s.scopes])}r.creator!==void 0&&Qn(await m(r.creator),"crtr:act");const i=r.request_key?.trim();if(i===void 0||r.node_id!==void 0&&qe(r.node_id)&&await R(r.node_id)!==null&&(await oe(i))?.nodeId!==r.node_id)return M(e,r,n,t);const a=Q.get(i);if(a!==void 0)return a;const c=Ot(e,r,i,n,t);Q.set(i,c);try{return await c}finally{Q.delete(i)}}d(Rt,"handleCreate");const ve="create_request_in_progress";async function It(e,n,t){const r=Date.now()+1e4;for(;t!==null;){const i=await R(t);if(i!==null){if(!j(e.principal)&&!await $(e.principal,i.grantee??"app:terminal",t))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(t)}}if(Date.now()>=r||(await oe(n))?.nodeId!==t)break;await new Promise(a=>setTimeout(a,100))}throw new p(409,ve,"another create with this request_key is in progress; retry it")}d(It,"awaitForeignCreate");async function Ot(e,n,t,r,i){const a=await ae(t);if(a.nodeId!==null&&await R(a.nodeId)!==null){if(a.state!=="warm_claimed"){const c=await R(a.nodeId);if(!j(e.principal)&&!await $(e.principal,c.grantee??"app:terminal",a.nodeId))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(a.nodeId)}}return M(e,n,r,i,a)}try{return await M(e,n,r,i,a)}catch(c){if(c instanceof p&&c.code===ve)throw c;const s=await ae(t);throw(s.nodeId===null||await R(s.nodeId)===null)&&await ie(t,s.nodeId),c}}d(Ot,"handleKeyedCreateRequest");async function M(e,n,t,r,i=void 0){const a=r.deadlineAt??_t(n.deadline),c=gt(n.outcome_delivery),s=e.principal.class==="cron"?await tn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:e.principal.kind==="exec"?null:(await me(e.principal.cron))?.created_by??null},n.node_id):null;s!==null&&(n.root=s.root===!0);const o=s?.parent??n.parent??void 0;if(o==null&&n.root!==!0)throw w("a node create requires a parent (or root: true for an independent root)");let l=null;if(n.output_schema!==void 0){try{l=JSON.parse(n.output_schema)}catch{throw w("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw w("output_schema must be a JSON schema object");await Ln(l)}const{profileId:f,kind:h,cwd:u,launch:S}=await Vn(n,{validateKind:Ie});await be(e,u),n.worktree!==void 0&&await be(e,P(n.pin_cwd??n.cwd??u));const _={...n,kind:h},v=c===void 0?void 0:bt(c,u),Z=("grant"in e.principal?e.principal.grant:null)??(o==null?null:(await R(o))?.grant_id??null);if(await V(_e(await Pe(S,Z,n.model)),{cwd:u,profileId:f},t.modelRegistry),await lt(Z)!=="app"&&!await mt(f===null?[]:await pt(f)))throw new p(412,"no_provider_credential",he,{error:"no_provider_credential",message:he,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let F=null;{const A=i===void 0||i.nodeId===null||i.state==="warm_claimed"?kt(_,u,f):null,B=l===null&&r.beforeBrokerLaunch===void 0?void 0:async g=>{l!==null&&await Dn(g,"terminal",l),r.beforeBrokerLaunch?.(g)};if(i?.state==="warm_claimed"&&i.nodeId!==null){const g=A===null?null:await Bn(A,i.nodeId,B);if(g===null)throw await ie(i.requestKey,i.nodeId),new p(503,"create_resume_failed",`could not resume warm claim ${i.nodeId}; retry the create`);return await re(i.requestKey,g),{status:201,body:await b(g)}}if(A!==null){const g=await Fn(A,{...a===void 0?{}:{deadlineAt:a},...v===void 0?{}:{outcomeDelivery:v},...i===void 0?{}:{requestKey:i.requestKey}},B);if(g!==null)return i!==void 0&&await re(i.requestKey,g),fe(A),{status:201,body:await b(g)};F=A}const N=i?.nodeId??n.node_id??(i===void 0?void 0:await te());if(i!==void 0&&i.nodeId===null){const g=await Be(i.requestKey,N);if(g!==N)return await It(e,i.requestKey,g)}const I=vt(N===void 0?_:{..._,node_id:N},o,u);s!==null&&(s.rootLifecycle!==void 0&&(I.rootLifecycle=s.rootLifecycle),s.scopes!==void 0&&_.scopes===void 0&&(I.scopes=s.scopes),s.run!==void 0&&(I.run=s.run),s.withinCreate!==void 0&&(I.withinCreate=s.withinCreate)),a!==void 0&&(I.deadlineAt=a),v!==void 0&&(I.outcomeDelivery=v),I.readiness=n.root===!0?"await":"launch";const q=await je(I,B,()=>{F!==null&&fe(F)});return i!==void 0&&await Fe(i.requestKey,q.node.node_id),{status:201,body:await b(q.node.node_id)}}}d(M,"handleCreateRequest");function k(e,n){const t=e.query.getAll(n);if(t.length>1)throw w(`${n} must appear at most once`);return t[0]}d(k,"singleQueryValue");function X(e,n){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw w(`${n} must be true or false`)}}d(X,"optionalBoolean");function G(e,n,t){if(e!==void 0){if(t.includes(e))return e;throw w(`${n} must be one of: ${t.join(", ")}`)}}d(G,"oneOf");function At(e){const n=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","under_inclusive","hanging","include"]);for(const[_]of e.query)if(!n.has(_))throw w(`unknown nodes query parameter: ${_}`);const t=G(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=G(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),i=k(e,"kind"),a=G(k(e,"mode"),"mode",["base","orchestrator"]),c=k(e,"profile_id"),s=k(e,"profile_prefix"),o=k(e,"parent"),l=X(k(e,"top_level"),"top_level"),f=k(e,"under"),h=X(k(e,"under_inclusive"),"under_inclusive"),u=X(k(e,"hanging"),"hanging"),S=G(k(e,"include"),"include",["activity"]);if(o!==void 0&&l===!0)throw w("parent and top_level=true cannot be combined");return{...t!==void 0?{status:t}:{},...r!==void 0?{lifecycle:r}:{},...i!==void 0?{kind:i}:{},...a!==void 0?{mode:a}:{},...c!==void 0?{profile_id:c}:{},...s!==void 0?{profile_prefix:s}:{},...o!==void 0?{parent:o}:{},...l!==void 0?{top_level:l}:{},...f!==void 0?{under:f}:{},...h!==void 0?{under_inclusive:h}:{},...u!==void 0?{hanging:u}:{},...S!==void 0?{include:S}:{}}}d(At,"parseListQuery");async function $t(e){const n=At(e);let t=await xe({...n.status!==void 0?{status:n.status}:{},...n.lifecycle!==void 0?{lifecycle:n.lifecycle}:{},...n.kind!==void 0?{kind:n.kind}:{},...n.mode!==void 0?{mode:n.mode}:{},...n.profile_id!==void 0?{profileId:n.profile_id}:{},...n.profile_prefix!==void 0?{profilePrefix:n.profile_prefix}:{},...n.parent!==void 0?{parent:n.parent}:{},...n.top_level===!0?{topLevel:!0}:{},...n.under!==void 0?{under:n.under}:{},...n.under_inclusive===!0?{underInclusive:!0}:{},...n.hanging===!0?{hanging:!0}:{}});const r=await et(e.principal);r!==null&&(t=t.filter(s=>r.has(s.node_id)));const i=n.include==="activity"?await Ze(t.map(s=>s.node_id)):null,a=t.length>0?$e():new Set;return{status:200,body:await ye(t,async s=>{const o=await Zn(s,s.profile_id!==null&&a.has(s.profile_id));if(i!==null){const l=await pe(s.node_id);o.activity={latest_report:l[0]??null,final_report:s.final_report===null?null:l.find(f=>f.name===s.final_report)??null,pending_human_count:i[s.node_id]??0}}return o})}}d($t,"handleList");async function Ct(e){const n=e.params.id,t=await tt(e,n,{method:"GET",path:`/v1/nodes/${encodeURIComponent(n)}`,query:it(e)});if(t.kind==="unknown")throw ot(n,t.unreachable);if(t.kind==="remote"){if(t.status>=400)throw rt(t.status,t.body);return{status:t.status,body:at(t.body,t.machine)}}return await m(n),{status:200,body:await b(n)}}d(Ct,"handleDetail");async function Et(e){const n=e.params.id;await m(n);const t=await cn(n);return{status:200,body:{node_id:n,snapshot:{messages:t.snapshot.messages,...t.snapshot.messageIds===void 0?{}:{messageIds:t.snapshot.messageIds},messageVisibility:t.snapshot.messageVisibility,turnVisibility:t.snapshot.turnVisibility,stats:t.snapshot.stats,state:t.snapshot.state,display:t.snapshot.display,...t.snapshot.queued===void 0?{}:{queued:t.snapshot.queued},...t.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:t.snapshot.toolGroupSummaries},...t.snapshot.turnReplies===void 0?{}:{turnReplies:t.snapshot.turnReplies},...t.snapshot.workingActivity===void 0?{}:{workingActivity:t.snapshot.workingActivity}},commands:t.commands.map(i=>({name:i.name,description:i.description,source:i.source})),captured_at:K()}}}d(Et,"handleSnapshot");async function Nt(e){const n=e.params.id,t=await fn(n);if(t===null)throw L(`unknown node: ${n}`,{received:n});return{status:200,body:t}}d(Nt,"handleSubject");function Tt(e){for(const[a]of e.query)if(a!=="cursor"&&a!=="limit")throw w(`unknown messages query parameter: ${a}`);const n=e.query.getAll("cursor"),t=e.query.getAll("limit");if(n.length>1)throw w("cursor must appear at most once");if(t.length>1)throw w("limit must appear at most once");if(t.length===0)return n.length===0?{}:{cursor:n[0]};const r=t[0],i=Number(r);if(!Number.isSafeInteger(i)||r==="")throw w("limit must be an integer from 1 through 500");return n.length===0?{limit:i}:{cursor:n[0],limit:i}}d(Tt,"parseMessagesQuery");async function Pt(e){const n=e.params.id,t=await sn(n,Tt(e));return{status:200,body:{node_id:n,messages:t.messages,...t.messageIds===void 0?{}:{message_ids:t.messageIds},message_visibility:t.messageVisibility,next_cursor:t.nextCursor,captured_at:K()}}}d(Pt,"handleMessages");async function Dt(e){const n=e.params.id;await m(n);const t=await ln(n);return{status:200,body:{node_id:n,session_file:t.sessionFile,session_jsonl:t.sessionJsonl,system_prompt:t.systemPrompt,captured_at:K()}}}d(Dt,"handleSession");async function Lt(e){const n=e.params.id;return await m(n),{status:200,body:{node_id:n,markdown:await un(n)}}}d(Lt,"handleTranscript");async function jt(e){const n=e.params.id;await m(n);const t=d(async(i,a)=>({node_id:i,label:(await R(i))?.name??i,dir:await se(i),self:a,files:await ht(i)}),"root"),r=await wt([await t(n,!0),...await ye(await de(n),async i=>await t(i.node_id,!1))],async i=>await Mt(i.node_id,i.dir)||i.files>0);return{status:200,body:{node_id:n,roots:r}}}d(jt,"handleContext");async function Mt(e,n){try{return rn(await z(e),n)}catch(t){if(an(t))return!1;throw t}}d(Mt,"hasDir");async function Gt(e){const n=await m(e.params.id),t=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=t===null?void 0:n.scopes==null?[...t]:[...new Set([...n.scopes.filter(a=>O(t,a)),...t.filter(a=>O(n.scopes,a))])],i=await De(n.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:await b(i.node.node_id)}}d(Gt,"handleFork");const Ft=1e4;async function Bt(e){const n=e.params.id;await m(n);const t=e.body,r=t?.resume??!0,i=t?.reopen??!1;await _n(n,i,e.principal.class==="broker"?e.principal.node:null);const a=!r&&t?.cron_id!==void 0?await me(t.cron_id):null,c=await Te(n,{resume:r,capacity:"refuse",...a!==null?{wakeReason:await Yn(a,"schedule_revive")}:{}});c.outcome!=="already-live"&&await Ke(n,{failures:0,notBefore:null});const s=(await R(n))?.status??"active",o=(c.launch??D().get(n)?.handle)?.exited,l=c.outcome!=="frozen"&&await ce(n,o,Ft);return{status:200,body:qn(n,c,s,l)}}d(Bt,"handleRevive");async function xt(e){const n=e.params.id;return{status:200,body:{newNodeId:(await yn(n))?.newNodeId??null}}}d(xt,"handleRelaunchRoot");async function Kt(e){const n=e.params.id;await m(n);const t=e.body;if(t?.caller_pid!==void 0&&(!Number.isInteger(t.caller_pid)||t.caller_pid<=0))throw w("caller_pid must be a positive integer when provided");const r=Hn(),i=new Promise(c=>{e.res.once("close",()=>c())}),a=await Ne(n,{teardownAfter:i,rootEvent:t?.finish===!0?"finish":"cancel",callerPid:t?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Xn(a)}}d(Kt,"handleClose");async function Vt(e){if(!j(e.principal))throw new p(403,"permission_error","only the person marks a conversation read");const n=e.params.id;return await m(n),await ze(n),{status:204}}d(Vt,"handleMarkRead");async function Wt(e){const n=e.params.id;await m(n);const t=await hn(n);return{status:200,body:{recycled:t.recycled,finalized:t.finalized,new_root:t.newRoot,delivered:t.delivered}}}d(Wt,"handleRecycle");async function zt(e){const n=e.params.id;return await m(n),await J(n,{lifecycle:"terminal"}),await C(e,n,["lifecycle"]),{status:200,body:await b(n)}}d(zt,"handleDemote");async function Jt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ge(r,{kind:i.kind??r.kind,mode:"orchestrator",lifecycle:i.resident===!0?"resident":r.lifecycle,model:i.model},n.modelRegistry);const a=await mn(t,{...i.kind!==void 0?{kind:i.kind}:{},...i.resident===!0?{resident:!0}:{},...i.model!==void 0?{model:i.model}:{}});await C(e,t,["mode",...i.kind!==void 0?["kind"]:[],...i.resident===!0?["lifecycle"]:[],...i.model!==void 0?["model"]:[]]);const c=await Y(a.meta,await H(t));return c.roadmap_written=a.roadmapWritten,c.roadmap_ref=a.roadmapRef,c.goal_path=a.goalPath,{status:200,body:c}}d(Jt,"handlePromote");async function Ut(e){const n=e.params.id;return await m(n),{status:200,body:{request:await bn(n)}}}d(Ut,"handleBrokerStructuredRequest");async function Yt(e){const n=e.params.id,t=e.body??{};if(await gn(n,t.expected_execution_id),typeof t.text!="string")throw new p(400,"invalid_request","text must be a string");return await m(n),{status:200,body:{captured:await Sn(n,t.text)}}}d(Yt,"handleBrokerGoal");async function Ht(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ge(r,{kind:i.kind??r.kind,mode:i.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:i.model},n.modelRegistry);const a=i.note??"Refresh: continue against your roadmap or goal.";await vn(t,a);const c=await wn(t,{...i.promote===!0?{promote:!0}:{},...i.kind!==void 0?{kind:i.kind}:{},...i.model!==void 0?{model:i.model}:{}});return{status:200,body:await Y(c.meta,await H(t))}}d(Ht,"handleYield");async function Qt(e){const n=e.params.id;await m(n);const t=e.body;if(t===void 0||typeof t.controller!="string"||t.controller.trim()==="")throw w("a wait requires a controller node id");const r=await R(t.controller);if(r===null)throw L(`unknown controller: ${t.controller}`,{received:t.controller});if(r.status!=="active"&&r.status!=="idle")throw new p(422,"unprocessable",`controller ${t.controller} is ${r.status}`);return await We(n,t.controller),{status:200,body:await b(n)}}d(Qt,"handleWait");async function Xt(e){const n=e.principal,t=await pn(n.class==="broker"?async i=>i.grantee===n.app&&await $(n,i.grantee,i.node_id):n.class==="person"&&!j(n)?async i=>await $(n,i.grantee??"app:terminal",i.node_id):void 0);return{status:200,body:{revived:[...t.revived],failed:[...t.failed],frozen:[...t.frozen]}}}d(Xt,"handleReviveAll");const Zt=new Set(["interrupt","steer","after-turn","next-turn"]);function qt(e){if(e===null)return null;const n=d(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return n("listen must be an object or null");const t=Object.entries(e);if(t.length===0)return n("listen must name at least one level");for(const[r,i]of t)/^(?:[1-9]|10)$/.test(r)||n(`listen level must be 1..10: ${r}`),(typeof i!="string"||!Zt.has(i))&&n(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(i)}`);return JSON.stringify(Object.fromEntries(t))}d(qt,"listenJson");async function C(e,n,t,r){t.length===0&&r===void 0||await W(async i=>{if(r?.(i),t.length===0)return;const a=await Je(i,n),c=await He(i,e),s=c.class==="person"?c.person:c.class==="app"?c.app:c.node;await Ue(i,s,a),await Ye(i,{event:"configured",object:a,actor:s,attrs:{changed:t.join(",")}})})}d(C,"recordConfigured");function ke(e){const n=D().get(e);if(n===void 0)return!1;try{return process.kill(n.pid,"SIGTERM"),!0}catch{return!1}}d(ke,"restartLiveBroker");function Se(e,n){try{return ee(e)===ee(n)}catch{return!1}}d(Se,"sameDirectory");async function ei(e,n={}){const t=e.params.id,r=e.body;let i;if(r===void 0)i={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))i=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(i.profile!==void 0){if(typeof i.profile!="string"||i.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:i.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(i).some(h=>h!=="profile"&&h!=="restart"&&i[h]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const o=await m(t),l=await zn(e,i.profile);Jn(l.profileId);const f=Un(l.profileId).manifest.grantee??"app:terminal";if(f!==(o.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${f}, node ${t} to ${o.grantee}`,received:i.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(o.profile_id??null)!==l.profileId&&(Kn(o.kind)?(await U(o.kind,o.cwd,l.profileId),await J(t,{profileId:l.profileId})):await E(t,{profile_id:l.profileId}),await C(e,t,["profile"])),i.restart===!0&&ke(t),{status:200,body:await b(t)}}if(Object.prototype.hasOwnProperty.call(i,"cwd")){const o=i.cwd;if(typeof o!="string"||o==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:o,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(i).some(u=>u!=="cwd"&&u!=="keep_session"&&u!=="restart"&&i[u]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:i,field:"cwd",next:"Send cwd as the only config field."});const l=await m(t),f=T(l.cwd);if(i.keep_session===!0||f&&x(o)&&T(o)&&Se(l.cwd,o)){if(!x(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const u=P(o);let S=!1;try{S=ne(u).isDirectory()}catch{}if(!S)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${u}`,received:o,field:"cwd",next:"Send an existing absolute directory."});if(f&&!Se(l.cwd,u))throw new y({error:"cwd_not_same_directory",message:`${u} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:o,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot relocate its cwd`,received:o,field:"cwd",next:"Reconcile the managed worktree first."});const _=l.cwd;return _!==u&&(await W(async v=>{await E(t,{cwd:u}),await v.prepare("UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(u,t,_),await Qe(t,_,u)}),await C(e,t,["cwd"])),i.restart===!0&&ke(t),{status:200,body:await b(t)}}if(await D().has(t)){const u=`${t} cannot repair its cwd while its broker is live`;throw new p(409,"cwd_node_live",u,{error:"cwd_node_live",message:u,received:o,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${t} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:o,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot repair its cwd`,received:o,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(T(l.cwd))throw new y({error:"cwd_still_present",message:`${t} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:o,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!x(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const h=P(o);if(!T(h))throw new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ne(h).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${h}`,received:o,field:"cwd",next:"Send an existing absolute directory."})}catch(u){throw u instanceof y?u:new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return await W(async()=>{await E(t,{cwd:h}),await Xe(t)}),await C(e,t,["cwd"]),{status:200,body:await b(t)}}let a=await m(t);const c=i.listen===void 0?void 0:qt(i.listen);if(i.scopes!==void 0){const o=we(i.scopes),l=a.grantee==="app:terminal"?await ct():a.grant_id?await st(a.grant_id):null;if(!o.every(f=>O(a.scopes,f)&&l!==null&&O(l.resolved,f)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:o,field:"scopes",next:"Send only scopes the node currently holds."});if(o.includes("crtr:act")&&!O(o,"crtr:llm"))throw new p(400,"invalid_scope","crtr:act requires crtr:llm");a=await E(t,{scopes:o})}if(i.situational_context!==void 0&&await Ce(t,Ee(i.situational_context)),i.model!==void 0){const o=(await le(a.cwd,a.profile_id??null)).modelLadders,l=$n(i.model,o),f=await ut(a.grant_id,i.model,l===void 0),h=f?{family:ft,strength:f.strength}:l,u=f?f.model:Cn(i.model,o);await V({kind:"concrete",spec:u},{cwd:a.cwd,profileId:a.profile_id??null},n.modelRegistry);const S=D();let _=!1;if(await S.isClaimed(t)&&await ce(t,S.get(t)?.handle.exited)&&(_=await Tn(t,u,h).then(()=>!0,v=>{if(v instanceof Pn)return!1;throw v})),!_){if(await S.isClaimed(t)){const v=`${t}'s broker did not accept the model switch; the model was not changed`;throw new p(409,"broker_not_ready",v,{error:"broker_not_ready",message:v,received:i.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!u.includes("/"))throw w(`model must resolve to a provider/id spec: ${i.model}`);await Nn(t,u,h)}a=await m(t)}if(i.kind!==void 0||i.mode!==void 0||i.lifecycle!==void 0){i.kind!==void 0&&await Ie(i.kind);const o=i.kind??a.kind,l=i.mode??a.mode,f=i.lifecycle??a.lifecycle;let h;l==="orchestrator"&&!await In(t)&&(h=d(async()=>{const u=await kn(t);await Rn(t,u!==null&&u.trim()!==""?{goal:u.trim()}:{})},"beforePersist")),a=await J(t,{...i.kind!==void 0?{kind:o}:{},...i.mode!==void 0?{mode:l}:{},...i.lifecycle!==void 0?{lifecycle:f}:{}},h)}i.name!==void 0&&(a=await E(t,{name:i.name}),a.window&&On(a.window,Wn(a)));const s=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(o=>i[o]!==void 0);return await C(e,t,s,c===void 0?void 0:async o=>{await o.prepare("UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(c,t)}),{status:200,body:await b(t)}}d(ei,"handleConfig");async function Re(){return(await le(process.cwd(),Ae()||null)).kinds}d(Re,"daemonKinds");async function Ie(e){const n=Object.keys(await Re());if(!n.includes(e))throw w(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${n.sort().join(", ")}.`})}d(Ie,"assertKindServer");async function ni(){const e=await Re();return{status:200,body:{kinds:Object.keys(e).sort().map(t=>({kind:t,when_to_use:e[t]?.whenToUse??null,available_to:e[t]?.availableTo??null}))}}}d(ni,"handleListKinds");const kr=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:Rt},{method:"GET",pattern:"/v1/nodes",handler:$t},{method:"GET",pattern:"/v1/kinds",handler:d(()=>ni(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:Xt},{method:"GET",pattern:"/v1/nodes/:id",handler:Ct},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:Et},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:Nt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:Pt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:Dt},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:Lt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:jt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Gt},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Bt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:xt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Kt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:Vt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Wt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:zt},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Jt},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Ht},{method:"GET",pattern:"/v1/nodes/:id/broker/structured-request",handler:Ut},{method:"POST",pattern:"/v1/nodes/:id/broker/goal",handler:Yt},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Qt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:ei}];export{ei as handleConfig,Rt as handleCreate,Gt as handleFork,$t as handleList,Jt as handlePromote,Ht as handleYield,kr as nodeRoutes,Ir as resolveCreateKind};
1
+ var $e=Object.defineProperty;var s=(e,n)=>$e(e,"name",{value:n,configurable:!0});import{envProfileId as Ne}from"../../../shared/env.js";import{pausedCanvasProfiles as Ce}from"../../../core/profiles/manifest.js";import{existsSync as P,realpathSync as ee,statSync as ne}from"node:fs";import{isAbsolute as K,resolve as D}from"node:path";import{appendSituationalContext as Ee,formatSituationalProse as Te}from"../../../core/runtime/situational-context.js";import{closeNode as Pe}from"../../../core/runtime/close.js";import{reviveNode as De}from"../../../core/runtime/revive.js";import{nowIso as x}from"../../../core/fs-utils.js";import{appPaidLaunch as Le,assertLaunchModelRegistered as V,forkNode as je,resolveForkSource as te,spawnChildPrepared as Me}from"../../../core/runtime/spawn.js";import{forkSourceNode as ie,newNodeId as re}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as oe,childrenOf as Ge,completeCreateRequest as ae,findCreateRequest as de,getNode as R,recordCreateRequestNode as Fe,reserveCreateRequest as se,reserveCreateRequestNode as Be,listNodes as Ke,recordRespawnAttempt as xe,subscribersOf as Ve,subscriptionsOf as le,updateNode as C}from"../../../core/canvas/canvas.js";import{armControllerWait as We}from"../../../core/canvas/waits.js";import{withCanvasWrite as W}from"../../../core/canvas/db.js";import{markNodeRead as ze}from"../../../core/canvas/recovery.js";import{nodeObject as Je}from"../../../core/graph/objects.js";import{recordActedOn as Ue}from"../../../core/graph/edges.js";import{publish as Ye}from"../../../core/graph/events.js";import{readerFor as He}from"../reader.js";import{relocateSessionCwd as Qe,unbindSession as Xe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Ze}from"../../../core/canvas/attention.js";import{isSafeNodeId as qe}from"../../../core/canvas/paths.js";import{contextDir as ce,nodeAgentDir as z}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as en,cronRefusalError as nn}from"../../cron/authority.js";import{cronBirthPlacement as tn}from"../../cron/armed-context.js";import{existsBeneath as rn,isAbsentOrRefused as on,isBeneathRefusal as an,readdirBeneath as dn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as sn,readNodeSession as ln,readNodeSnapshot as cn,transcriptMarkdown as un}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as fn}from"../../../core/substrate/subject.js";import{reviveAll as pn}from"../../../core/runtime/revive-all.js";import{promoteAsync as mn,requestYieldAsync as wn,reshapeNodeAsync as J}from"../../../core/runtime/promote.js";import{recycleNode as hn}from"../../../core/runtime/recycle.js";import{relaunchRoot as yn}from"../../../core/runtime/reset.js";import{assertReopenGate as _n}from"../../../core/runtime/reopen.js";import{requireCurrentExecution as gn}from"./broker-recovery.js";import{readOutputRequest as bn}from"../../../core/runtime/output-result.js";import{writeYieldMessage as vn,readGoal as kn,captureGoalIfAbsent as Sn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as Rn,hasRoadmap as In}from"../../../core/runtime/roadmap.js";import{renameWindow as On}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as An,explicitModelIntent as $n,normalizeModel as Nn,readMergedLaunchConfigAsync as ue}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Cn}from"../../../core/model-routes.js";import{persistDormantModel as En,setModelLive as Tn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as fe}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as Pn}from"../../../core/runtime/broker-request.js";import{boundFleet as L}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as Dn}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Ln}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as pe}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as jn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Mn}from"../../../core/human-actions.js";import{parseDurationMs as Gn}from"../../../core/wake.js";import{claimWarmNode as Fn,refillWarmPool as me,resumeWarmClaim as Bn,warmPoolEnabled as Kn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as U,isLaunchKind as xn,resolveLaunchTarget as Vn}from"../../../core/runtime/launch-target.js";import{fullName as Wn}from"../../../core/canvas/labels.js";import{reportsForNode as we}from"./reports.js";import{requireUsableProfile as zn}from"./profiles.js";import{assertProfileActive as Jn,loadExactProfileManifest as Un}from"../../../core/profiles/manifest.js";import{getCron as he}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Yn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Hn}from"../../control.js";import{notFound as E,usage as w}from"../../../core/errors.js";import{assertScope as Qn,validateScopes as ye}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Xn,toNodeDetailDTO as Y,toNodeSummaryDTO as Zn,toReviveResultDTO as qn}from"../map.js";import{ApiError as p}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{actsAsPerson as j,canReadNode as $,mayOnNode as et,readableNodeIds as nt,resolvedScopes as tt}from"../router.js";import{forwardVerb as it,queryWithoutMachine as rt,relayError as ot,unknownError as at,withMachine as dt}from"../../peer/forward.js";import{fileRoot as st}from"../../../core/spaces/file-root.js";import{activeGrant as lt,payerOfGrant as ct}from"../../../core/grants/mirror.js";import{nodeTerminalGrant as ut}from"../../../core/grants/terminal.js";import{appRungForGrant as ft}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as pt}from"../../../core/model-routes.js";import{listProfileEnvNames as mt}from"../../../core/profiles/env-store.js";import{hasConfiguredProviderCredential as wt,NO_PROVIDER_CREDENTIAL_MESSAGE as _e}from"../../../core/runtime/provider-credential-gate.js";import{filterAsync as ht,mapAsync as ge}from"../../../core/async-array.js";async function m(e){const n=await R(e);if(n===null)throw E(`unknown node: ${e}`,{received:e});return n}s(m,"requireMeta");async function H(e){return{subscribesTo:await le(e),subscribers:await Ve(e),children:await Ge(e)}}s(H,"edgesFor");async function b(e){const n=await m(e);return await Y(n,await H(e))}s(b,"detailOf");async function yt(e){let n=(await we(e)).length;try{n+=dn(await z(e),await ce(e)).length}catch(t){if(!on(t))throw t}return n}s(yt,"countFiles");function _t(e){if(typeof e!="object"||e===null)throw w("a node create requires a JSON body");const n=e;if(n.kind!==void 0&&(typeof n.kind!="string"||n.kind.trim()===""))throw w("kind must be a non-empty string when provided");if(n.description!==void 0&&(typeof n.description!="string"||n.description.trim()===""))throw w("description must be a non-empty string when provided");if(n.creator!==void 0&&(typeof n.creator!="string"||n.creator.trim()===""))throw w("creator must be a non-empty node id when provided");if(n.scopes!==void 0&&ye(n.scopes),n.isolated!==void 0&&typeof n.isolated!="boolean")throw new p(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const t=n.root_lifecycle;if(t!==void 0&&t!=="resident"&&t!=="terminal")throw w("root_lifecycle must be 'resident' or 'terminal'");if(n.request_key!==void 0&&(typeof n.request_key!="string"||n.request_key.trim()===""||n.request_key.length>128))throw w("request_key must be a non-empty string of at most 128 characters when provided");return n}s(_t,"parseCreateBody");function gt(e){if(e===void 0)return;const n=Gn(e),t=n===null?null:new Date(Date.now()+n);if(n===null||!Number.isFinite(n)||n<=0||t===null||!Number.isFinite(t.getTime()))throw new p(422,"invalid_deadline","`deadline` must be a positive representable duration");return t.toISOString()}s(gt,"parseDeadline");function bt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new p(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!jn.test(e.action))throw new p(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let n;try{n=JSON.stringify(e.payload)}catch{throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(n===void 0)throw new p(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(n,"utf8")>pe)throw new p(413,"payload_too_large",`serialized payload exceeds ${pe} bytes`)}return e}}s(bt,"parseOutcomeDelivery");function vt(e,n){const t=Mn(e.action,n);if(!("kind"in t))return{actionName:e.action,argv:t.argv,cwd:t.cwd,configOrigin:t.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw t.kind==="unknown_action"?new p(422,"unknown_action",`no action named ${e.action} is declared from ${n}`):new p(422,"invalid_action",`${e.action} is declared in ${t.configOrigin} but unusable: ${t.reason}`,{reason:t.reason,configOrigin:t.configOrigin})}s(vt,"resolveOutcomeDelivery");function kt(e,n,t){const r={kind:e.kind,cwd:t,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),n!==void 0&&(r.parent=n),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=D(e.pin_cwd??e.cwd??t)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}s(kt,"buildRecipe");function St(e,n,t){return!Kn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:n,profileId:t,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}s(St,"warmRequestFor");import{resolveCreateKind as Ar}from"../../../core/runtime/launch-target.js";function be(e){const n=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Cn(e.model,n,e.modelExact===!0)}s(be,"requestFromLaunch");function Rt(e,n){if(n===null)return e;if(e.scopes===void 0)return{...e,scopes:[...n]};const t=e.scopes.filter(r=>!O(n,r));if(t.length===0)return e;throw new p(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${t.join(", ")}`,{scopes:t,ceiling:n})}s(Rt,"withinCeiling");async function ve(e,n,t){const r=(await An(n.kind,n.mode,{lifecycle:n.lifecycle,hasManager:e.parent!==null,model:n.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await V(be(r),{cwd:e.cwd,profileId:e.profile_id??null},t)}s(ve,"assertNodeModelChangeRegistered");async function ke(e,n){const t=e.principal;if(t.class!=="broker"&&t.class!=="cron")return;const r=st({app:t.app,resolved:await tt(t),launched:t.scopes},n,"read");if("root"in r)return;const i="missing"in r?r.missing:null;throw new p(403,"scope_missing",i?`the child's directory ${n} needs missing scope ${i}`:`no permission of this run names the child's directory ${n}`,void 0,void 0,i?{scope:i}:void 0)}s(ke,"assertCallerReaches");const Q=new Map;async function It(e,n={},t={}){const r=Rt(_t(e.body),e.ceiling);if(e.principal.class==="broker"){const d=e.principal;if(r.prefer_warm===!0&&d.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const o=await m(r.parent);if(o.grantee!==d.app)throw new p(403,"other_app_run","cannot create a child under another app's node");if(!await $(d,o.grantee??"app:terminal",r.parent))throw E(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==d.node)throw new p(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let o=null;try{o=await ie(await te(r.fork_from))}catch{}if(o?.grantee!==d.app||!await $(d,o.grantee,o.node_id))throw new p(403,"other_app_run","cannot fork another app's conversation")}r.creator=d.node}if(e.principal.class==="person"&&e.principal.sub!==void 0){const d=r.fork_from===void 0?null:await ie(await te(r.fork_from)).catch(()=>null);for(const o of[r.parent,r.creator,d?.node_id])if(o!=null&&await R(o)!==null&&!await et(e.principal,"edit",o))throw E(`unknown node: ${o}`,{received:o})}if(e.principal.class==="cron"){const d=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new p(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1,r.node_id=await re(),d.isolated&&(r.isolated=!0,r.cwd=await z(r.node_id,d.app));const o=await en({grantee:d.app,sub:d.sub,grant_id:d.grant,scopes:d.scopes,from_exec:d.from_exec},{profile:r.profile,cwd:r.cwd,pin_cwd:r.pin_cwd,kind:r.kind,model:r.model,mode:r.mode});if(!o.allowed)throw nn(o);if(r.scopes!==void 0){const l=r.scopes.find(f=>!O(o.effectiveScopes,f)||!O(d.scopes,f));if(l!==void 0)throw new p(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else d.scopes!==null&&(r.scopes=[...d.scopes])}r.creator!==void 0&&Qn(await m(r.creator),"crtr:act");const i=r.request_key?.trim();if(i===void 0||r.node_id!==void 0&&qe(r.node_id)&&await R(r.node_id)!==null&&(await de(i))?.nodeId!==r.node_id)return M(e,r,n,t);const a=Q.get(i);if(a!==void 0)return a;const c=At(e,r,i,n,t);Q.set(i,c);try{return await c}finally{Q.delete(i)}}s(It,"handleCreate");const Se="create_request_in_progress";async function Ot(e,n,t){const r=Date.now()+1e4;for(;t!==null;){const i=await R(t);if(i!==null){if(!j(e.principal)&&!await $(e.principal,i.grantee??"app:terminal",t))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(t)}}if(Date.now()>=r||(await de(n))?.nodeId!==t)break;await new Promise(a=>setTimeout(a,100))}throw new p(409,Se,"another create with this request_key is in progress; retry it")}s(Ot,"awaitForeignCreate");async function At(e,n,t,r,i){const a=await se(t);if(a.nodeId!==null&&await R(a.nodeId)!==null){if(a.state!=="warm_claimed"){const c=await R(a.nodeId);if(!j(e.principal)&&!await $(e.principal,c.grantee??"app:terminal",a.nodeId))throw new p(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:await b(a.nodeId)}}return M(e,n,r,i,a)}try{return await M(e,n,r,i,a)}catch(c){if(c instanceof p&&c.code===Se)throw c;const d=await se(t);throw(d.nodeId===null||await R(d.nodeId)===null)&&await oe(t,d.nodeId),c}}s(At,"handleKeyedCreateRequest");async function M(e,n,t,r,i=void 0){const a=r.deadlineAt??gt(n.deadline),c=bt(n.outcome_delivery),d=e.principal.class==="cron"?await tn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:e.principal.kind==="exec"?null:(await he(e.principal.cron))?.created_by??null},n.node_id):null;d!==null&&(n.root=d.root===!0);const o=d?.parent??n.parent??void 0;if(o==null&&n.root!==!0)throw w("a node create requires a parent (or root: true for an independent root)");let l=null;if(n.output_schema!==void 0){try{l=JSON.parse(n.output_schema)}catch{throw w("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw w("output_schema must be a JSON schema object");await Ln(l)}const{profileId:f,kind:h,cwd:u,launch:S}=await Vn(n,{validateKind:Ae});await ke(e,u),n.worktree!==void 0&&await ke(e,D(n.pin_cwd??n.cwd??u));const _={...n,kind:h},v=c===void 0?void 0:vt(c,u),Z=("grant"in e.principal?e.principal.grant:null)??(o==null?null:(await R(o))?.grant_id??null);if(await V(be(await Le(S,Z,n.model)),{cwd:u,profileId:f},t.modelRegistry),await ct(Z)!=="app"&&!await wt(f===null?[]:await mt(f)))throw new p(412,"no_provider_credential",_e,{error:"no_provider_credential",message:_e,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let F=null;{const A=i===void 0||i.nodeId===null||i.state==="warm_claimed"?St(_,u,f):null,B=l===null&&r.beforeBrokerLaunch===void 0?void 0:async g=>{l!==null&&await Dn(g,"terminal",l),r.beforeBrokerLaunch?.(g)};if(i?.state==="warm_claimed"&&i.nodeId!==null){const g=A===null?null:await Bn(A,i.nodeId,B);if(g===null)throw await oe(i.requestKey,i.nodeId),new p(503,"create_resume_failed",`could not resume warm claim ${i.nodeId}; retry the create`);return await ae(i.requestKey,g),{status:201,body:await b(g)}}if(A!==null){const g=await Fn(A,{...a===void 0?{}:{deadlineAt:a},...v===void 0?{}:{outcomeDelivery:v},...i===void 0?{}:{requestKey:i.requestKey}},B);if(g!==null)return i!==void 0&&await ae(i.requestKey,g),me(A),{status:201,body:await b(g)};F=A}const T=i?.nodeId??n.node_id??(i===void 0?void 0:await re());if(i!==void 0&&i.nodeId===null){const g=await Be(i.requestKey,T);if(g!==T)return await Ot(e,i.requestKey,g)}const I=kt(T===void 0?_:{..._,node_id:T},o,u);d!==null&&(d.rootLifecycle!==void 0&&(I.rootLifecycle=d.rootLifecycle),d.scopes!==void 0&&_.scopes===void 0&&(I.scopes=d.scopes),d.run!==void 0&&(I.run=d.run),d.withinCreate!==void 0&&(I.withinCreate=d.withinCreate)),a!==void 0&&(I.deadlineAt=a),v!==void 0&&(I.outcomeDelivery=v),I.readiness=n.root===!0?"await":"launch";const q=await Me(I,B,()=>{F!==null&&me(F)});return i!==void 0&&await Fe(i.requestKey,q.node.node_id),{status:201,body:await b(q.node.node_id)}}}s(M,"handleCreateRequest");function k(e,n){const t=e.query.getAll(n);if(t.length>1)throw w(`${n} must appear at most once`);return t[0]}s(k,"singleQueryValue");function X(e,n){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw w(`${n} must be true or false`)}}s(X,"optionalBoolean");function G(e,n,t){if(e!==void 0){if(t.includes(e))return e;throw w(`${n} must be one of: ${t.join(", ")}`)}}s(G,"oneOf");function $t(e){const n=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","under_inclusive","hanging","include"]);for(const[_]of e.query)if(!n.has(_))throw w(`unknown nodes query parameter: ${_}`);const t=G(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=G(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),i=k(e,"kind"),a=G(k(e,"mode"),"mode",["base","orchestrator"]),c=k(e,"profile_id"),d=k(e,"profile_prefix"),o=k(e,"parent"),l=X(k(e,"top_level"),"top_level"),f=k(e,"under"),h=X(k(e,"under_inclusive"),"under_inclusive"),u=X(k(e,"hanging"),"hanging"),S=G(k(e,"include"),"include",["activity"]);if(o!==void 0&&l===!0)throw w("parent and top_level=true cannot be combined");return{...t!==void 0?{status:t}:{},...r!==void 0?{lifecycle:r}:{},...i!==void 0?{kind:i}:{},...a!==void 0?{mode:a}:{},...c!==void 0?{profile_id:c}:{},...d!==void 0?{profile_prefix:d}:{},...o!==void 0?{parent:o}:{},...l!==void 0?{top_level:l}:{},...f!==void 0?{under:f}:{},...h!==void 0?{under_inclusive:h}:{},...u!==void 0?{hanging:u}:{},...S!==void 0?{include:S}:{}}}s($t,"parseListQuery");async function Nt(e){const n=$t(e);let t=await Ke({...n.status!==void 0?{status:n.status}:{},...n.lifecycle!==void 0?{lifecycle:n.lifecycle}:{},...n.kind!==void 0?{kind:n.kind}:{},...n.mode!==void 0?{mode:n.mode}:{},...n.profile_id!==void 0?{profileId:n.profile_id}:{},...n.profile_prefix!==void 0?{profilePrefix:n.profile_prefix}:{},...n.parent!==void 0?{parent:n.parent}:{},...n.top_level===!0?{topLevel:!0}:{},...n.under!==void 0?{under:n.under}:{},...n.under_inclusive===!0?{underInclusive:!0}:{},...n.hanging===!0?{hanging:!0}:{}});const r=await nt(e.principal);r!==null&&(t=t.filter(d=>r.has(d.node_id)));const i=n.include==="activity"?await Ze(t.map(d=>d.node_id)):null,a=t.length>0?Ce():new Set;return{status:200,body:await ge(t,async d=>{const o=await Zn(d,d.profile_id!==null&&a.has(d.profile_id));if(i!==null){const l=await we(d.node_id);o.activity={latest_report:l[0]??null,final_report:d.final_report===null?null:l.find(f=>f.name===d.final_report)??null,pending_human_count:i[d.node_id]??0}}return o})}}s(Nt,"handleList");async function Ct(e){const n=e.params.id,t=await it(e,n,{method:"GET",path:`/v1/nodes/${encodeURIComponent(n)}`,query:rt(e)});if(t.kind==="unknown")throw at(n,t.unreachable);if(t.kind==="remote"){if(t.status>=400)throw ot(t.status,t.body);return{status:t.status,body:dt(t.body,t.machine)}}return await m(n),{status:200,body:await b(n)}}s(Ct,"handleDetail");async function Et(e){const n=e.params.id;await m(n);const t=await cn(n);return{status:200,body:{node_id:n,snapshot:{messages:t.snapshot.messages,...t.snapshot.messageIds===void 0?{}:{messageIds:t.snapshot.messageIds},messageVisibility:t.snapshot.messageVisibility,turnVisibility:t.snapshot.turnVisibility,stats:t.snapshot.stats,state:t.snapshot.state,display:t.snapshot.display,...t.snapshot.queued===void 0?{}:{queued:t.snapshot.queued},...t.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:t.snapshot.toolGroupSummaries},...t.snapshot.turnReplies===void 0?{}:{turnReplies:t.snapshot.turnReplies},...t.snapshot.workingActivity===void 0?{}:{workingActivity:t.snapshot.workingActivity}},commands:t.commands.map(i=>({name:i.name,description:i.description,source:i.source})),captured_at:x()}}}s(Et,"handleSnapshot");async function Tt(e){const n=e.params.id,t=await fn(n);if(t===null)throw E(`unknown node: ${n}`,{received:n});return{status:200,body:t}}s(Tt,"handleSubject");function Pt(e){for(const[a]of e.query)if(a!=="cursor"&&a!=="limit")throw w(`unknown messages query parameter: ${a}`);const n=e.query.getAll("cursor"),t=e.query.getAll("limit");if(n.length>1)throw w("cursor must appear at most once");if(t.length>1)throw w("limit must appear at most once");if(t.length===0)return n.length===0?{}:{cursor:n[0]};const r=t[0],i=Number(r);if(!Number.isSafeInteger(i)||r==="")throw w("limit must be an integer from 1 through 500");return n.length===0?{limit:i}:{cursor:n[0],limit:i}}s(Pt,"parseMessagesQuery");async function Dt(e){const n=e.params.id,t=await sn(n,Pt(e));return{status:200,body:{node_id:n,messages:t.messages,...t.messageIds===void 0?{}:{message_ids:t.messageIds},message_visibility:t.messageVisibility,next_cursor:t.nextCursor,captured_at:x()}}}s(Dt,"handleMessages");async function Lt(e){const n=e.params.id;await m(n);const t=await ln(n);return{status:200,body:{node_id:n,session_file:t.sessionFile,session_jsonl:t.sessionJsonl,system_prompt:t.systemPrompt,captured_at:x()}}}s(Lt,"handleSession");async function jt(e){const n=e.params.id;return await m(n),{status:200,body:{node_id:n,markdown:await un(n)}}}s(jt,"handleTranscript");async function Mt(e){const n=e.params.id;await m(n);const t=s(async(i,a)=>({node_id:i,label:(await R(i))?.name??i,dir:await ce(i),self:a,files:await yt(i)}),"root"),r=await ht([await t(n,!0),...await ge(await le(n),async i=>await t(i.node_id,!1))],async i=>await Gt(i.node_id,i.dir)||i.files>0);return{status:200,body:{node_id:n,roots:r}}}s(Mt,"handleContext");async function Gt(e,n){try{return rn(await z(e),n)}catch(t){if(an(t))return!1;throw t}}s(Gt,"hasDir");async function Ft(e){const n=await m(e.params.id),t=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=t===null?void 0:n.scopes==null?[...t]:[...new Set([...n.scopes.filter(a=>O(t,a)),...t.filter(a=>O(n.scopes,a))])],i=await je(n.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:await b(i.node.node_id)}}s(Ft,"handleFork");const Bt=1e4;async function Kt(e){const n=e.params.id;await m(n);const t=e.body,r=t?.resume??!0,i=t?.reopen??!1;await _n(n,i,e.principal.class==="broker"?e.principal.node:null);const a=!r&&t?.cron_id!==void 0?await he(t.cron_id):null,c=await De(n,{resume:r,capacity:"refuse",...a!==null?{wakeReason:await Yn(a,"schedule_revive")}:{}});c.outcome!=="already-live"&&await xe(n,{failures:0,notBefore:null});const d=(await R(n))?.status??"active",o=(c.launch??L().get(n)?.handle)?.exited,l=c.outcome!=="frozen"&&await fe(n,o,Bt);return{status:200,body:qn(n,c,d,l)}}s(Kt,"handleRevive");async function xt(e){const n=e.params.id;return{status:200,body:{newNodeId:(await yn(n))?.newNodeId??null}}}s(xt,"handleRelaunchRoot");async function Vt(e){const n=e.params.id;await m(n);const t=e.body;if(t?.caller_pid!==void 0&&(!Number.isInteger(t.caller_pid)||t.caller_pid<=0))throw w("caller_pid must be a positive integer when provided");const r=Hn(),i=new Promise(c=>{e.res.once("close",()=>c())}),a=await Pe(n,{teardownAfter:i,rootEvent:t?.finish===!0?"finish":"cancel",callerPid:t?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Xn(a)}}s(Vt,"handleClose");async function Wt(e){if(!j(e.principal))throw new p(403,"permission_error","only the person marks a conversation read");const n=e.params.id;return await m(n),await ze(n),{status:204}}s(Wt,"handleMarkRead");async function zt(e){const n=e.params.id;await m(n);const t=await hn(n);return{status:200,body:{recycled:t.recycled,finalized:t.finalized,new_root:t.newRoot,delivered:t.delivered}}}s(zt,"handleRecycle");async function Jt(e){const n=e.params.id;return await m(n),await J(n,{lifecycle:"terminal"}),await N(e,n,["lifecycle"]),{status:200,body:await b(n)}}s(Jt,"handleDemote");async function Ut(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:"orchestrator",lifecycle:i.resident===!0?"resident":r.lifecycle,model:i.model},n.modelRegistry);const a=await mn(t,{...i.kind!==void 0?{kind:i.kind}:{},...i.resident===!0?{resident:!0}:{},...i.model!==void 0?{model:i.model}:{}});await N(e,t,["mode",...i.kind!==void 0?["kind"]:[],...i.resident===!0?["lifecycle"]:[],...i.model!==void 0?["model"]:[]]);const c=await Y(a.meta,await H(t));return c.roadmap_written=a.roadmapWritten,c.roadmap_ref=a.roadmapRef,c.goal_path=a.goalPath,{status:200,body:c}}s(Ut,"handlePromote");async function Yt(e){const n=e.params.id;return await m(n),{status:200,body:{request:await bn(n)}}}s(Yt,"handleBrokerStructuredRequest");async function Ht(e){const n=e.params.id,t=e.body??{};if(await gn(n,t.expected_execution_id),typeof t.text!="string")throw new p(400,"invalid_request","text must be a string");return await m(n),{status:200,body:{captured:await Sn(n,t.text)}}}s(Ht,"handleBrokerGoal");async function Qt(e,n={}){const t=e.params.id,r=await m(t),i=e.body??{};i.kind!==void 0&&await U(i.kind,r.cwd,r.profile_id??null),i.model!==void 0&&await ve(r,{kind:i.kind??r.kind,mode:i.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:i.model},n.modelRegistry);const a=i.note??"Refresh: continue against your roadmap or goal.";await vn(t,a);const c=await wn(t,{...i.promote===!0?{promote:!0}:{},...i.kind!==void 0?{kind:i.kind}:{},...i.model!==void 0?{model:i.model}:{}});return{status:200,body:await Y(c.meta,await H(t))}}s(Qt,"handleYield");async function Xt(e){const n=e.params.id;await m(n);const t=e.body;if(t===void 0||typeof t.controller!="string"||t.controller.trim()==="")throw w("a wait requires a controller node id");const r=await R(t.controller);if(r===null)throw E(`unknown controller: ${t.controller}`,{received:t.controller});if(r.status!=="active"&&r.status!=="idle")throw new p(422,"unprocessable",`controller ${t.controller} is ${r.status}`);return await We(n,t.controller),{status:200,body:await b(n)}}s(Xt,"handleWait");async function Zt(e){const n=e.principal,t=await pn(n.class==="broker"?async i=>i.grantee===n.app&&await $(n,i.grantee,i.node_id):n.class==="person"&&!j(n)?async i=>await $(n,i.grantee??"app:terminal",i.node_id):void 0);return{status:200,body:{revived:[...t.revived],failed:[...t.failed],frozen:[...t.frozen]}}}s(Zt,"handleReviveAll");const qt=new Set(["interrupt","steer","after-turn","next-turn"]);function ei(e){if(e===null)return null;const n=s(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return n("listen must be an object or null");const t=Object.entries(e);if(t.length===0)return n("listen must name at least one level");for(const[r,i]of t)/^(?:[1-9]|10)$/.test(r)||n(`listen level must be 1..10: ${r}`),(typeof i!="string"||!qt.has(i))&&n(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(i)}`);return JSON.stringify(Object.fromEntries(t))}s(ei,"listenJson");async function N(e,n,t,r){t.length===0&&r===void 0||await W(async i=>{if(r?.(i),t.length===0)return;const a=await Je(i,n),c=await He(i,e),d=c.class==="person"?c.person:c.class==="app"?c.app:c.node;await Ue(i,d,a),await Ye(i,{event:"configured",object:a,actor:d,attrs:{changed:t.join(",")}})})}s(N,"recordConfigured");function Re(e){const n=L().get(e);if(n===void 0)return!1;try{return process.kill(n.pid,"SIGTERM"),!0}catch{return!1}}s(Re,"restartLiveBroker");function Ie(e,n){try{return ee(e)===ee(n)}catch{return!1}}s(Ie,"sameDirectory");async function ni(e,n={}){const t=e.params.id,r=e.body;let i;if(r===void 0)i={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))i=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(i.profile!==void 0){if(typeof i.profile!="string"||i.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:i.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(i).some(h=>h!=="profile"&&h!=="restart"&&i[h]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const o=await m(t),l=await zn(e,i.profile);Jn(l.profileId);const f=Un(l.profileId).manifest.grantee??"app:terminal";if(f!==(o.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${f}, node ${t} to ${o.grantee}`,received:i.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(o.profile_id??null)!==l.profileId&&(xn(o.kind)?(await U(o.kind,o.cwd,l.profileId),await J(t,{profileId:l.profileId})):await C(t,{profile_id:l.profileId}),await N(e,t,["profile"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(Object.prototype.hasOwnProperty.call(i,"cwd")){const o=i.cwd;if(typeof o!="string"||o==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:o,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(i).some(u=>u!=="cwd"&&u!=="keep_session"&&u!=="restart"&&i[u]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:i,field:"cwd",next:"Send cwd as the only config field."});const l=await m(t),f=P(l.cwd);if(i.keep_session===!0||f&&K(o)&&P(o)&&Ie(l.cwd,o)){if(!K(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const u=D(o);let S=!1;try{S=ne(u).isDirectory()}catch{}if(!S)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${u}`,received:o,field:"cwd",next:"Send an existing absolute directory."});if(f&&!Ie(l.cwd,u))throw new y({error:"cwd_not_same_directory",message:`${u} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:o,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot relocate its cwd`,received:o,field:"cwd",next:"Reconcile the managed worktree first."});const _=l.cwd;return _!==u&&(await W(async v=>{await C(t,{cwd:u}),await v.prepare("UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(u,t,_),await Qe(t,_,u)}),await N(e,t,["cwd"])),i.restart===!0&&Re(t),{status:200,body:await b(t)}}if(await L().has(t)){const u=`${t} cannot repair its cwd while its broker is live`;throw new p(409,"cwd_node_live",u,{error:"cwd_node_live",message:u,received:o,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${t} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:o,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${t} owns an open managed worktree and cannot repair its cwd`,received:o,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(P(l.cwd))throw new y({error:"cwd_still_present",message:`${t} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:o,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!K(o))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${o}`,received:o,field:"cwd",next:"Send an absolute path."});const h=D(o);if(!P(h))throw new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ne(h).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${h}`,received:o,field:"cwd",next:"Send an existing absolute directory."})}catch(u){throw u instanceof y?u:new y({error:"cwd_missing",message:`cwd does not exist: ${h}`,received:o,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return await W(async()=>{await C(t,{cwd:h}),await Xe(t)}),await N(e,t,["cwd"]),{status:200,body:await b(t)}}let a=await m(t);const c=i.listen===void 0?void 0:ei(i.listen);if(i.scopes!==void 0){const o=ye(i.scopes),l=a.grantee==="app:terminal"?await ut(a):a.grant_id?await lt(a.grant_id):null;if(!o.every(f=>O(a.scopes,f)&&l!==null&&O(l.resolved,f)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:o,field:"scopes",next:"Send only scopes the node currently holds."});if(o.includes("crtr:act")&&!O(o,"crtr:llm"))throw new p(400,"invalid_scope","crtr:act requires crtr:llm");a=await C(t,{scopes:o})}if(i.situational_context!==void 0&&await Ee(t,Te(i.situational_context)),i.model!==void 0){const o=(await ue(a.cwd,a.profile_id??null)).modelLadders,l=$n(i.model,o),f=await ft(a.grant_id,i.model,l===void 0),h=f?{family:pt,strength:f.strength}:l,u=f?f.model:Nn(i.model,o);await V({kind:"concrete",spec:u},{cwd:a.cwd,profileId:a.profile_id??null},n.modelRegistry);const S=L();let _=!1;if(await S.isClaimed(t)&&await fe(t,S.get(t)?.handle.exited)&&(_=await Tn(t,u,h).then(()=>!0,v=>{if(v instanceof Pn)return!1;throw v})),!_){if(await S.isClaimed(t)){const v=`${t}'s broker did not accept the model switch; the model was not changed`;throw new p(409,"broker_not_ready",v,{error:"broker_not_ready",message:v,received:i.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!u.includes("/"))throw w(`model must resolve to a provider/id spec: ${i.model}`);await En(t,u,h)}a=await m(t)}if(i.kind!==void 0||i.mode!==void 0||i.lifecycle!==void 0){i.kind!==void 0&&await Ae(i.kind);const o=i.kind??a.kind,l=i.mode??a.mode,f=i.lifecycle??a.lifecycle;let h;l==="orchestrator"&&!await In(t)&&(h=s(async()=>{const u=await kn(t);await Rn(t,u!==null&&u.trim()!==""?{goal:u.trim()}:{})},"beforePersist")),a=await J(t,{...i.kind!==void 0?{kind:o}:{},...i.mode!==void 0?{mode:l}:{},...i.lifecycle!==void 0?{lifecycle:f}:{}},h)}i.name!==void 0&&(a=await C(t,{name:i.name}),a.window&&On(a.window,Wn(a)));const d=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(o=>i[o]!==void 0);return await N(e,t,d,c===void 0?void 0:async o=>{await o.prepare("UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(c,t)}),{status:200,body:await b(t)}}s(ni,"handleConfig");async function Oe(){return(await ue(process.cwd(),Ne()||null)).kinds}s(Oe,"daemonKinds");async function Ae(e){const n=Object.keys(await Oe());if(!n.includes(e))throw w(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${n.sort().join(", ")}.`})}s(Ae,"assertKindServer");async function ti(){const e=await Oe();return{status:200,body:{kinds:Object.keys(e).sort().map(t=>({kind:t,when_to_use:e[t]?.whenToUse??null,available_to:e[t]?.availableTo??null}))}}}s(ti,"handleListKinds");const Rr=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:It},{method:"GET",pattern:"/v1/nodes",handler:Nt},{method:"GET",pattern:"/v1/kinds",handler:s(()=>ti(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:Zt},{method:"GET",pattern:"/v1/nodes/:id",handler:Ct},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:Et},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:Tt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:Dt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:Lt},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:jt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:Mt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Ft},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Kt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:xt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Vt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:Wt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:zt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Jt},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Ut},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Qt},{method:"GET",pattern:"/v1/nodes/:id/broker/structured-request",handler:Yt},{method:"POST",pattern:"/v1/nodes/:id/broker/goal",handler:Ht},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Xt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:ni}];export{ni as handleConfig,It as handleCreate,Ft as handleFork,Nt as handleList,Ut as handlePromote,Qt as handleYield,Rr as nodeRoutes,Ar as resolveCreateKind};
@@ -1 +1 @@
1
- var p=Object.defineProperty;var d=(n,r)=>p(n,"name",{value:r,configurable:!0});import{rmSync as g}from"node:fs";import{claimDaemonAction as h,dueDaemonActions as w,settleDaemonAction as _}from"../../core/canvas/daemon-actions.js";import{getNode as y}from"../../core/canvas/canvas.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{createPageRequest as I,getRequest as u}from"../../core/human/requests.js";import{synthesizedPageDocument as v,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as b}from"../../core/config.js";import{spawnChild as q}from"../../core/runtime/spawn.js";import{isStartRefusal as D}from"../../core/runtime/start-check.js";import{runDelivery as P}from"../delivery/run-delivery.js";import{deliveryDaemonInstanceId as m}from"./delivery-lane.js";import{cronBirthPlacement as S}from"../cron/armed-context.js";import{checkCronBirth as N}from"../cron/authority.js";async function o(n,r,e){await _(n.actionId,n.attempts,r,e,Date.now())}d(o,"settle");async function f(n,r,e){await o(n,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:e}})}d(f,"failed");async function z(n,r,e){const i=await y(e.nodeId);if(i!==null){if(i.frozen_at!==null||i.pi_session_id!==null||i.status==="idle"||i.status==="done"||i.status==="canceled"){await o(n,r,{state:"acknowledged"});return}await f(n,r,i.status==="dead"?`cron spawn ${e.nodeId} recorded a failed birth`:`cron spawn ${e.nodeId} found an incomplete birth`);return}const t=e.principal;if(t===void 0){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:e.cronId??null,action_id:n.actionId,reason:"grant_missing",stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:"grant_missing: the queued birth carries no cron principal"}});return}const a=await N(t,{kind:e.kind,cwd:e.cwd,profile:e.profile});if(!a.allowed){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:t.cron_id,action_id:n.actionId,grant_id:t.grant_id,reason:a.reason,stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:`${a.reason}: ${a.message}`}});return}try{await q({nodeId:e.nodeId,kind:e.kind,cwd:e.cwd,prompt:e.prompt,...await S(t,e.nodeId),readiness:"launch",profile:e.profile,isolated:e.isolated===!0,wakeOrigin:e.wakeOrigin}),await o(n,r,{state:"acknowledged"})}catch(s){if(D(s)){await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:s.message}});return}await f(n,r,`cron spawn ${e.nodeId} failed: ${s instanceof Error?s.message:String(s)}`),c.fresh(()=>l({level:"error",event:"delivery.cron_spawn_failed",node_id:e.nodeId,error:s,fields:{action_id:n.actionId}}))}}d(z,"deliverSpawn");function A(n,r){const e=k(v(n.title,n.summary,r,!1));try{return $({sourceFile:e.path,source:{sessionName:n.sessionName,...n.profileName===null?{}:{profileName:n.profileName}},productKinds:b(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(e.dir,{recursive:!0,force:!0})}}d(A,"preparedCronPage");async function C(n,r,e){if(await u(e.requestId)!==null){await o(n,r,{state:"acknowledged"});return}const i=n.body,t=typeof i?.stdout=="string"?i.stdout:null;if(t===null){await f(n,r,`cron human ${e.requestId} has no frozen stdout`);return}try{await I({request_id:e.requestId,prepared:A(e,t)}),await o(n,r,{state:"acknowledged"})}catch(a){await f(n,r,`cron human ${e.requestId} failed: ${a instanceof Error?a.message:String(a)}`)}}d(C,"deliverHuman");async function E(n,r){const e=n.adapter;if(n.body===null){await f(n,r,`daemon action ${n.actionId} has no body`);return}if(e.adapter==="subprocess"){let i=e.node_id;if(i===void 0){const t=n.idempotencyKey;if(!t.startsWith("human-action:"))throw new Error(`daemon action ${n.actionId} has no originating app`);const a=await u(t.slice(13));if(!a)throw new Error(`daemon action ${n.actionId} has no originating human request`);i=a.requester_node_id}await P({argv:e.argv,cwd:e.cwd,document:n.body,attempt:n.attempts,nodeId:i,...e.app?{app:e.app}:{}},async t=>await o(n,r,t));return}if(e.adapter==="cron_spawn"){await z(n,r,e);return}if(e.adapter==="cron_human"){await C(n,r,e);return}await f(n,r,`daemon action ${n.actionId} has unknown adapter ${String(e.adapter)}`)}d(E,"deliverAction");class V{static{d(this,"ActionLaneReconciler")}async run(r,e){if(!e.lifecycle.acceptsDetachedWork())return;let i;try{i=await w(r)}catch(t){c.fresh(()=>l({level:"error",event:"daemon_action.scan_failed",error:t}));return}for(const t of i)try{const a=await h(t.actionId,r,m);if(a===null)continue;e.lifecycle.registerDetached(E(a,m).catch(s=>{c.fresh(()=>l({level:"error",event:"daemon_action.failed",error:s,fields:{action_id:a.actionId}}))}))}catch(a){c.fresh(()=>l({level:"error",event:"daemon_action.claim_failed",error:a,fields:{action_id:t.actionId}}))}}}export{V as ActionLaneReconciler};
1
+ var p=Object.defineProperty;var d=(n,r)=>p(n,"name",{value:r,configurable:!0});import{rmSync as g}from"node:fs";import{claimDaemonAction as w,dueDaemonActions as h,settleDaemonAction as _}from"../../core/canvas/daemon-actions.js";import{getNode as y}from"../../core/canvas/canvas.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as c}from"../../core/events/operation-id.js";import{createPageRequest as I,getRequest as u}from"../../core/human/requests.js";import{synthesizedPageDocument as v,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as b}from"../../core/config.js";import{spawnChild as q}from"../../core/runtime/spawn.js";import{isStartRefusal as D}from"../../core/runtime/start-check.js";import{runDelivery as P}from"../delivery/run-delivery.js";import{deliveryDaemonInstanceId as m}from"./delivery-lane.js";import{cronBirthPlacement as S}from"../cron/armed-context.js";import{asPerson as N}from"./node-lifecycle/node-person.js";import{checkCronBirth as z}from"../cron/authority.js";async function o(n,r,e){await _(n.actionId,n.attempts,r,e,Date.now())}d(o,"settle");async function f(n,r,e){await o(n,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:e}})}d(f,"failed");async function A(n,r,e){const i=await y(e.nodeId);if(i!==null){if(i.frozen_at!==null||i.pi_session_id!==null||i.status==="idle"||i.status==="done"||i.status==="canceled"){await o(n,r,{state:"acknowledged"});return}await f(n,r,i.status==="dead"?`cron spawn ${e.nodeId} recorded a failed birth`:`cron spawn ${e.nodeId} found an incomplete birth`);return}const t=e.principal;if(t===void 0){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:e.cronId??null,action_id:n.actionId,reason:"grant_missing",stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:"grant_missing: the queued birth carries no cron principal"}});return}const a=await z(t,{kind:e.kind,cwd:e.cwd,profile:e.profile});if(!a.allowed){c.fresh(()=>l({level:"warn",event:"cron.birth.refused",node_id:e.nodeId,fields:{cron_id:t.cron_id,action_id:n.actionId,grant_id:t.grant_id,reason:a.reason,stage:"delivery"}})),await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:`${a.reason}: ${a.message}`}});return}try{await N(t.sub,async()=>await q({nodeId:e.nodeId,kind:e.kind,cwd:e.cwd,prompt:e.prompt,...await S(t,e.nodeId),readiness:"launch",profile:e.profile,isolated:e.isolated===!0,wakeOrigin:e.wakeOrigin})),await o(n,r,{state:"acknowledged"})}catch(s){if(D(s)){await o(n,r,{state:"permanent_failed",failure:{kind:"grant_refused",message:s.message}});return}await f(n,r,`cron spawn ${e.nodeId} failed: ${s instanceof Error?s.message:String(s)}`),c.fresh(()=>l({level:"error",event:"delivery.cron_spawn_failed",node_id:e.nodeId,error:s,fields:{action_id:n.actionId}}))}}d(A,"deliverSpawn");function C(n,r){const e=k(v(n.title,n.summary,r,!1));try{return $({sourceFile:e.path,source:{sessionName:n.sessionName,...n.profileName===null?{}:{profileName:n.profileName}},productKinds:b(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(e.dir,{recursive:!0,force:!0})}}d(C,"preparedCronPage");async function E(n,r,e){if(await u(e.requestId)!==null){await o(n,r,{state:"acknowledged"});return}const i=n.body,t=typeof i?.stdout=="string"?i.stdout:null;if(t===null){await f(n,r,`cron human ${e.requestId} has no frozen stdout`);return}try{await I({request_id:e.requestId,prepared:C(e,t)}),await o(n,r,{state:"acknowledged"})}catch(a){await f(n,r,`cron human ${e.requestId} failed: ${a instanceof Error?a.message:String(a)}`)}}d(E,"deliverHuman");async function R(n,r){const e=n.adapter;if(n.body===null){await f(n,r,`daemon action ${n.actionId} has no body`);return}if(e.adapter==="subprocess"){let i=e.node_id;if(i===void 0){const t=n.idempotencyKey;if(!t.startsWith("human-action:"))throw new Error(`daemon action ${n.actionId} has no originating app`);const a=await u(t.slice(13));if(!a)throw new Error(`daemon action ${n.actionId} has no originating human request`);i=a.requester_node_id}await P({argv:e.argv,cwd:e.cwd,document:n.body,attempt:n.attempts,nodeId:i,...e.app?{app:e.app}:{}},async t=>await o(n,r,t));return}if(e.adapter==="cron_spawn"){await A(n,r,e);return}if(e.adapter==="cron_human"){await E(n,r,e);return}await f(n,r,`daemon action ${n.actionId} has unknown adapter ${String(e.adapter)}`)}d(R,"deliverAction");class Y{static{d(this,"ActionLaneReconciler")}async run(r,e){if(!e.lifecycle.acceptsDetachedWork())return;let i;try{i=await h(r)}catch(t){c.fresh(()=>l({level:"error",event:"daemon_action.scan_failed",error:t}));return}for(const t of i)try{const a=await w(t.actionId,r,m);if(a===null)continue;e.lifecycle.registerDetached(R(a,m).catch(s=>{c.fresh(()=>l({level:"error",event:"daemon_action.failed",error:s,fields:{action_id:a.actionId}}))}))}catch(a){c.fresh(()=>l({level:"error",event:"daemon_action.claim_failed",error:a,fields:{action_id:t.actionId}}))}}}export{Y as ActionLaneReconciler};
@@ -1 +1 @@
1
- var g=Object.defineProperty;var s=(i,e)=>g(i,"name",{value:e,configurable:!0});import{clearFrozen as p,getNode as h,getRow as y}from"../../../core/canvas/index.js";import{openDb as c}from"../../../core/canvas/db.js";import{fullName as k}from"../../../core/canvas/labels.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as S}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as D}from"../../../core/canvas/deliveries.js";import{publishNotice as N}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{isStartRefusal as E}from"../../../core/runtime/start-check.js";import{EnvironmentImagePending as R}from"./remote-wake.js";import{commitReopenResident as z}from"../../../core/runtime/reopen.js";import{reviveNode as m}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as T}from"../../../core/canvas/recovery.js";import{mapAsync as L}from"../../../core/async-array.js";const f=6,C=10*6e4,b=2e4;async function I(i){const e=await(await c()).prepare("SELECT idle_release_attempts, idle_release_last_attempt_at, idle_release_acked_count FROM nodes WHERE node_id = ?").get(i);return{attempts:Number(e?.idle_release_attempts??0),acknowledgedCount:Number(e?.idle_release_acked_count??0),lastAttempt:e?.idle_release_last_attempt_at==null?void 0:Date.parse(e.idle_release_last_attempt_at)}}s(I,"readEpisode");async function M(i,e,a,t,r){const n=await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ? AND idle_release_attempts = ?").run(a,new Date(r).toISOString(),t,i,e);return Number(n.changes)===1}s(M,"claimAttempt");async function O(i,e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ?").run(e.attempts,e.lastAttempt===void 0?null:new Date(e.lastAttempt).toISOString(),e.acknowledgedCount,i)}s(O,"writeEpisode");function P(i,e){if(e)return 2;const a=i.launched_at;if(a==null)return 1;const t=i.last_settled_at;return t==null?2:Date.parse(t)>Date.parse(a)?1:2}s(P,"thawTier");function U(i,e){const a=i.row.frozen_at,t=e.row.frozen_at;return a==null?t==null?0:1:t==null?-1:Date.parse(a)-Date.parse(t)}s(U,"compareThaw");class te{static{s(this,"FreezeLaneReconciler")}async endEpisode(e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = 0, idle_release_last_attempt_at = NULL, idle_release_acked_count = 0 WHERE node_id = ? AND (idle_release_attempts <> 0 OR idle_release_last_attempt_at IS NOT NULL OR idle_release_acked_count <> 0)").run(e)}async run(e,a){const t=await L(a.candidates,async n=>({...n,tier:P(n.row,await v(n.row.node_id))}));t.sort(U);const r={stalled:0,waitingOnMail:0};for(const n of t)await S.fresh(()=>this.enact(e,n,a.fleet))==="frozen"&&(n.tier===1?r.stalled+=1:r.waitingOnMail+=1);return r}async enact(e,a,t){const r=a.row.node_id;try{return a.enact==="thaw"?await this.enactThaw(a.row):a.enact==="reopen"?await this.enactReopen(a.row):a.enact==="idle-release"?await this.enactIdleRelease(e,a.row):(await t.applyDeadRowPolicy(r),await t.has(r)?"launched":(await y(r))?.frozen_at!=null?"frozen":"skipped")}catch(n){return _({level:"error",event:"node.lifecycle.enact_failed",...d(r)?{node_id:r}:{},error:n,fields:{...d(r)?{}:{affected_node_id:r},enact:a.enact}}),"skipped"}}async enactReopen(e){await z(e.node_id);try{return(await m(e.node_id,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":"launched"}catch(a){if(E(a)||a instanceof R)return await this.settleRefusedStart(e.node_id,a,"reopen");throw a}}async settleRefusedStart(e,a,t){return await u(e,"release"),await p(e),_({level:"warn",event:"node.start.refused",node_id:e,error:a,fields:{enact:t}}),"skipped"}async enactThaw(e){const a=(await T(e.node_id))?.interrupted===!0;if(!a&&e.lifecycle==="resident"&&(await h(e.node_id))?.pi_session_id!=null&&!await v(e.node_id))return await u(e.node_id,"release"),await p(e.node_id),"skipped";try{return(await m(e.node_id,{resume:!0,capacity:"freeze",recovery:!0,...a?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(t){if(E(t)||t instanceof R)return await this.settleRefusedStart(e.node_id,t,"thaw");const r=await h(e.node_id);throw r!==null&&(r.status==="active"||r.status==="idle")&&(await u(e.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t instanceof Error?t.message:String(t)}}}),await p(e.node_id)),t}}async enactIdleRelease(e,a){const t=a.node_id,r=await D(t),n=await I(t),l=n.attempts===0||n.acknowledgedCount!==r,o=l?0:n.attempts;if(o>=f)return await this.endEpisode(t),_({level:"warn",event:"broker.idle_release.exhausted",...d(t)?{node_id:t}:{},fields:{...d(t)?{}:{affected_node_id:t},attempts:o,max_attempts:f}}),await u(t,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:o}}}),await N(t,"notice.crash",`Child crashed \u2014 ${k(a)} (${t}) failed to relaunch after ${o} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${t}\`.`,{reason:"child-crashed",child:t}),"skipped";const w=l?void 0:n.lastAttempt,A=Math.min(b*2**o,C);return w!==void 0&&e-w<A||!await M(t,n.attempts,o+1,r,e)?"skipped":(await m(t,{resume:!0,capacity:"freeze"})).outcome==="frozen"?(await O(t,{attempts:l?0:o,lastAttempt:l?void 0:n.lastAttempt,acknowledgedCount:r}),"frozen"):(_({level:"info",event:"broker.revive.idle_release",...d(t)?{node_id:t}:{},attempt:o+1,fields:{...d(t)?{}:{affected_node_id:t},attempts:o+1,max_attempts:f}}),"launched")}}export{te as FreezeLaneReconciler,U as compareThaw,P as thawTier};
1
+ var g=Object.defineProperty;var s=(i,e)=>g(i,"name",{value:e,configurable:!0});import{clearFrozen as p,getNode as h,getRow as y}from"../../../core/canvas/index.js";import{openDb as c}from"../../../core/canvas/db.js";import{fullName as k}from"../../../core/canvas/labels.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{emitEvent as _}from"../../../core/events/emit.js";import{operationIdContext as S}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as N}from"../../../core/canvas/deliveries.js";import{publishNotice as D}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{isStartRefusal as E}from"../../../core/runtime/start-check.js";import{EnvironmentImagePending as R}from"./remote-wake.js";import{asNodePerson as z}from"./node-person.js";import{commitReopenResident as T}from"../../../core/runtime/reopen.js";import{reviveNode as m}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as L}from"../../../core/canvas/recovery.js";import{mapAsync as C}from"../../../core/async-array.js";const f=6,b=10*6e4,I=2e4;async function M(i){const e=await(await c()).prepare("SELECT idle_release_attempts, idle_release_last_attempt_at, idle_release_acked_count FROM nodes WHERE node_id = ?").get(i);return{attempts:Number(e?.idle_release_attempts??0),acknowledgedCount:Number(e?.idle_release_acked_count??0),lastAttempt:e?.idle_release_last_attempt_at==null?void 0:Date.parse(e.idle_release_last_attempt_at)}}s(M,"readEpisode");async function O(i,e,a,t,r){const n=await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ? AND idle_release_attempts = ?").run(a,new Date(r).toISOString(),t,i,e);return Number(n.changes)===1}s(O,"claimAttempt");async function P(i,e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = ?, idle_release_last_attempt_at = ?, idle_release_acked_count = ? WHERE node_id = ?").run(e.attempts,e.lastAttempt===void 0?null:new Date(e.lastAttempt).toISOString(),e.acknowledgedCount,i)}s(P,"writeEpisode");function U(i,e){if(e)return 2;const a=i.launched_at;if(a==null)return 1;const t=i.last_settled_at;return t==null?2:Date.parse(t)>Date.parse(a)?1:2}s(U,"thawTier");function x(i,e){const a=i.row.frozen_at,t=e.row.frozen_at;return a==null?t==null?0:1:t==null?-1:Date.parse(a)-Date.parse(t)}s(x,"compareThaw");class re{static{s(this,"FreezeLaneReconciler")}async endEpisode(e){await(await c()).prepare("UPDATE nodes SET idle_release_attempts = 0, idle_release_last_attempt_at = NULL, idle_release_acked_count = 0 WHERE node_id = ? AND (idle_release_attempts <> 0 OR idle_release_last_attempt_at IS NOT NULL OR idle_release_acked_count <> 0)").run(e)}async run(e,a){const t=await C(a.candidates,async n=>({...n,tier:U(n.row,await v(n.row.node_id))}));t.sort(x);const r={stalled:0,waitingOnMail:0};for(const n of t)await S.fresh(()=>z(n.row,()=>this.enact(e,n,a.fleet)))==="frozen"&&(n.tier===1?r.stalled+=1:r.waitingOnMail+=1);return r}async enact(e,a,t){const r=a.row.node_id;try{return a.enact==="thaw"?await this.enactThaw(a.row):a.enact==="reopen"?await this.enactReopen(a.row):a.enact==="idle-release"?await this.enactIdleRelease(e,a.row):(await t.applyDeadRowPolicy(r),await t.has(r)?"launched":(await y(r))?.frozen_at!=null?"frozen":"skipped")}catch(n){return _({level:"error",event:"node.lifecycle.enact_failed",...d(r)?{node_id:r}:{},error:n,fields:{...d(r)?{}:{affected_node_id:r},enact:a.enact}}),"skipped"}}async enactReopen(e){await T(e.node_id);try{return(await m(e.node_id,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":"launched"}catch(a){if(E(a)||a instanceof R)return await this.settleRefusedStart(e.node_id,a,"reopen");throw a}}async settleRefusedStart(e,a,t){return await u(e,"release"),await p(e),_({level:"warn",event:"node.start.refused",node_id:e,error:a,fields:{enact:t}}),"skipped"}async enactThaw(e){const a=(await L(e.node_id))?.interrupted===!0;if(!a&&e.lifecycle==="resident"&&(await h(e.node_id))?.pi_session_id!=null&&!await v(e.node_id))return await u(e.node_id,"release"),await p(e.node_id),"skipped";try{return(await m(e.node_id,{resume:!0,capacity:"freeze",recovery:!0,...a?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(t){if(E(t)||t instanceof R)return await this.settleRefusedStart(e.node_id,t,"thaw");const r=await h(e.node_id);throw r!==null&&(r.status==="active"||r.status==="idle")&&(await u(e.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t instanceof Error?t.message:String(t)}}}),await p(e.node_id)),t}}async enactIdleRelease(e,a){const t=a.node_id,r=await N(t),n=await M(t),l=n.attempts===0||n.acknowledgedCount!==r,o=l?0:n.attempts;if(o>=f)return await this.endEpisode(t),_({level:"warn",event:"broker.idle_release.exhausted",...d(t)?{node_id:t}:{},fields:{...d(t)?{}:{affected_node_id:t},attempts:o,max_attempts:f}}),await u(t,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:o}}}),await D(t,"notice.crash",`Child crashed \u2014 ${k(a)} (${t}) failed to relaunch after ${o} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${t}\`.`,{reason:"child-crashed",child:t}),"skipped";const w=l?void 0:n.lastAttempt,A=Math.min(I*2**o,b);return w!==void 0&&e-w<A||!await O(t,n.attempts,o+1,r,e)?"skipped":(await m(t,{resume:!0,capacity:"freeze"})).outcome==="frozen"?(await P(t,{attempts:l?0:o,lastAttempt:l?void 0:n.lastAttempt,acknowledgedCount:r}),"frozen"):(_({level:"info",event:"broker.revive.idle_release",...d(t)?{node_id:t}:{},attempt:o+1,fields:{...d(t)?{}:{affected_node_id:t},attempts:o+1,max_attempts:f}}),"launched")}}export{re as FreezeLaneReconciler,x as compareThaw,U as thawTier};
@@ -0,0 +1 @@
1
+ export declare function recordLaunchFailure(executionId: string, error: unknown): Promise<void>;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var n=(i,e)=>s(i,"name",{value:e,configurable:!0});import{openDb as t}from"../../../core/canvas/db.js";import{exitDiagnosticJson as o}from"../../../core/canvas/recovery.js";async function r(i,e){const a=e instanceof Error?`${e.name}: ${e.message}`:String(e);await(await t()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(o({launch_failure:{message:a.slice(0,2e3)}}),i)}n(r,"recordLaunchFailure");export{r as recordLaunchFailure};
@@ -0,0 +1,9 @@
1
+ import type { NodeRow } from '../../../core/canvas/types.js';
2
+ /** A cloud-role node with no `sub` whose profile names no person: no one may be borrowed for it, so the lane leaves it untouched. */
3
+ export declare class NodePersonUnresolvedError extends Error {
4
+ readonly code = "node_person_unresolved";
5
+ constructor(nodeId: string);
6
+ }
7
+ /** Run `fn` as `sub` with that person's settings loaded, as an API request does from its token. */
8
+ export declare function asPerson<T>(sub: string, fn: () => Promise<T>): Promise<T>;
9
+ export declare function asNodePerson<T>(row: Pick<NodeRow, 'node_id' | 'sub' | 'profile_id'>, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var r=(e,n)=>i(e,"name",{value:n,configurable:!0});import{openDb as s}from"../../../core/canvas/db.js";import{isCloudRole as t,runAsPerson as a}from"../../../core/canvas/person.js";import{loadPersonSettings as u}from"../../../core/scoped-state/person-rows.js";import{personHasSnapshot as d}from"../../../core/scoped-state/person-store.js";class p extends Error{static{r(this,"NodePersonUnresolvedError")}code="node_person_unresolved";constructor(n){super(`node ${n} has no person: its row carries no sub and its profile names none`),this.name="NodePersonUnresolvedError"}}async function l(e){if(e.sub!=null&&e.sub!=="")return e.sub;if(!t())return null;const n=e.profile_id==null?void 0:await(await s()).prepare("SELECT person FROM profiles WHERE id = ?").get(e.profile_id);if(n===void 0||n.person==="")throw new p(e.node_id);return await(await s()).prepare("UPDATE nodes SET sub = ? WHERE node_id = ? AND (sub IS NULL OR sub = '')").run(n.person,e.node_id),n.person}r(l,"personOf");async function f(e,n){return await a(e,async()=>(d()||await u(e),await n()))}r(f,"asPerson");async function P(e,n){const o=await l(e);return o===null?await n():await f(o,n)}r(P,"asNodePerson");export{p as NodePersonUnresolvedError,P as asNodePerson,f as asPerson};
@@ -7,8 +7,6 @@ export declare const LAUNCH_DEADLINE_MS: number;
7
7
  export declare const LAUNCH_LOST_GRACE_MS = 120000;
8
8
  /** The release the control plane runs, which is the release a wake names. */
9
9
  export declare const acceptedRelease: () => string;
10
- /** The Blaxel environment the node's profile points at, or null when it runs on a machine. Reads rows only, so it is safe before any environment is registered. */
11
- export declare function blaxelEnvironmentOf(profileId: string | null): Promise<string | null>;
12
10
  /** Step 2: the `funding bill` check. A refusal writes `nodes.spend_refusal` and one refused `sandbox` row per node, limit and month,
13
11
  * then throws `402 cap_exhausted`; no execution row is written and no runner is called. A pass clears `spend_refusal`. */
14
12
  export declare function checkBilledWake(meta: NodeMeta): Promise<void>;
@@ -1 +1 @@
1
- var p=Object.defineProperty;var a=(e,t)=>p(e,"name",{value:t,configurable:!0});import{liveExecutionForNode as m,endExecution as d,recordExecutionAwake as w,endLaunchingExecution as s,requestExecutionStop as h}from"../../../core/canvas/executions.js";import{openDb as c}from"../../../core/canvas/db.js";import{emitEvent as u}from"../../../core/events/emit.js";import{findRefusal as _,refusalError as x,refusedMark as E,writeCharge as g}from"../../../core/ledger/index.js";import{transition as f}from"../../../core/runtime/lifecycle.js";import{runnerForExecution as l}from"../../../core/runtime/runner/index.js";import{startCandidateOf as b}from"../../../core/runtime/start-check.js";import{settleSandboxBeforeWake as v}from"../ledger-sandbox.js";import{crtrVersion as k}from"../../../shared/crtr-version.js";import{resolveEnvironmentImage as I}from"../recipe-image.js";const S=45*6e4,y=12e4,N=a(()=>k(),"acceptedRelease");async function j(e){return e===null?null:(await(await c()).prepare("SELECT e.object AS object FROM profiles p JOIN environments e ON e.object = p.environment_id WHERE p.id = ? AND e.kind = 'blaxel'").get(e))?.object??null}a(j,"blaxelEnvironmentOf");async function F(e){const t=await b(e);if(t===null)return;const n={scope:"call",payer:t.payer,funding:"bill",sub:t.sub,grantee:t.grantee,provider:"blaxel"},r=await _(n),o=await c();if(r===null){await o.prepare("UPDATE nodes SET spend_refusal = NULL WHERE node_id = ? AND spend_refusal IS NOT NULL").run(e.node_id);return}throw await o.prepare("UPDATE nodes SET spend_refusal = ? WHERE node_id = ?").run(JSON.stringify({limit:r.limit.id,usd:r.usd,reset_at:r.reset_at,at:new Date().toISOString()}),e.node_id),await g({id:`refused:sandbox:${e.node_id}:${r.limit.id}:${r.month}`,kind:"sandbox",what:"wake",usd:null,payer:n.payer,funding:"bill",sub:n.sub,grantee:n.grantee,node:e.node_id,run:e.run_id??null,provider:"blaxel",refused:E(r)}),x(r)}a(F,"checkBilledWake");class M extends Error{static{a(this,"EnvironmentImagePending")}environmentId;imageError;constructor(t,n){super(`environment ${t} has no built image yet${n===null?"":` (${n})`}; the wake waits for the build.`),this.environmentId=t,this.imageError=n,this.name="EnvironmentImagePending"}}async function P(e){return await I(e)}a(P,"imageForWake");async function B(e){return e.release!==N()&&await h(e.nodeId,{afterTurn:!1,reason:"release"}),await l(e.runner).wake(e)==="no_broker"?(await d(e.executionId,{reason:"lost"}),"lost"):(await v(e.executionId,Date.now()),await w(e.executionId),"woken")}a(B,"wakeResident");async function G(e){const t=await l(e.runner).status(e);if(t.state!=="gone"&&t.state!=="failed")return!1;const n=await d(e.executionId,{reason:"lost"});return n&&u({level:"warn",event:"execution.lost",node_id:e.nodeId}),n}a(G,"endRemoteExecutionIfGone");async function J(e,t){const n=await m(e);if(n===null||n.state!=="launching"||n.runner==="process")return;const r=l(n.runner),o=t-Date.parse(n.startedAt),i=await r.status(n);if(i.state!=="unknown"){if(i.state==="running"){if(o<=S||!await s(n.executionId,{reason:"launch_timeout"}))return;await r.stop(n,{reason:"launch_timeout"}),await f(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:"the sandbox launch did not report within the launch deadline"}}}),u({level:"warn",event:"execution.launch_timeout",node_id:e});return}if(i.state==="failed"){if(!await s(n.executionId,{reason:"launch_failed"}))return;await f(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:`the sandbox start script failed: ${i.reason}`}}});return}if(o>y){if(!await s(n.executionId,{reason:"launch_lost"}))return;u({level:"warn",event:"execution.launch_lost",node_id:e})}}}a(J,"recoverLaunching");export{M as EnvironmentImagePending,S as LAUNCH_DEADLINE_MS,y as LAUNCH_LOST_GRACE_MS,N as acceptedRelease,j as blaxelEnvironmentOf,F as checkBilledWake,G as endRemoteExecutionIfGone,P as imageForWake,J as recoverLaunching,B as wakeResident};
1
+ var f=Object.defineProperty;var a=(e,n)=>f(e,"name",{value:n,configurable:!0});import{liveExecutionForNode as m,endExecution as l,recordExecutionAwake as p,endLaunchingExecution as s,requestExecutionStop as w}from"../../../core/canvas/executions.js";import{openDb as h}from"../../../core/canvas/db.js";import{emitEvent as u}from"../../../core/events/emit.js";import{findRefusal as _,refusalError as x,refusedMark as g,writeCharge as E}from"../../../core/ledger/index.js";import{transition as c}from"../../../core/runtime/lifecycle.js";import{runnerForExecution as d}from"../../../core/runtime/runner/index.js";import{startCandidateOf as v}from"../../../core/runtime/start-check.js";import{settleSandboxBeforeWake as b}from"../ledger-sandbox.js";import{crtrVersion as k}from"../../../shared/crtr-version.js";import{resolveEnvironmentImage as I}from"../recipe-image.js";const y=45*6e4,S=12e4,L=a(()=>k(),"acceptedRelease");async function P(e){const n=await v(e);if(n===null)return;const t={scope:"call",payer:n.payer,funding:"bill",sub:n.sub,grantee:n.grantee,provider:"blaxel"},r=await _(t),o=await h();if(r===null){await o.prepare("UPDATE nodes SET spend_refusal = NULL WHERE node_id = ? AND spend_refusal IS NOT NULL").run(e.node_id);return}throw await o.prepare("UPDATE nodes SET spend_refusal = ? WHERE node_id = ?").run(JSON.stringify({limit:r.limit.id,usd:r.usd,reset_at:r.reset_at,at:new Date().toISOString()}),e.node_id),await E({id:`refused:sandbox:${e.node_id}:${r.limit.id}:${r.month}`,kind:"sandbox",what:"wake",usd:null,payer:t.payer,funding:"bill",sub:t.sub,grantee:t.grantee,node:e.node_id,run:e.run_id??null,provider:"blaxel",refused:g(r)}),x(r)}a(P,"checkBilledWake");class F extends Error{static{a(this,"EnvironmentImagePending")}environmentId;imageError;constructor(n,t){super(`environment ${n} has no built image yet${t===null?"":` (${t})`}; the wake waits for the build.`),this.environmentId=n,this.imageError=t,this.name="EnvironmentImagePending"}}async function M(e){return await I(e)}a(M,"imageForWake");async function B(e){return e.release!==L()&&await w(e.nodeId,{afterTurn:!1,reason:"release"}),await d(e.runner).wake(e)==="no_broker"?(await l(e.executionId,{reason:"lost"}),"lost"):(await b(e.executionId,Date.now()),await p(e.executionId),"woken")}a(B,"wakeResident");async function G(e){const n=await d(e.runner).status(e);if(n.state!=="gone"&&n.state!=="failed")return!1;const t=await l(e.executionId,{reason:"lost"});return t&&u({level:"warn",event:"execution.lost",node_id:e.nodeId}),t}a(G,"endRemoteExecutionIfGone");async function q(e,n){const t=await m(e);if(t===null||t.state!=="launching"||t.runner==="process")return;const r=d(t.runner),o=n-Date.parse(t.startedAt),i=await r.status(t);if(i.state!=="unknown"){if(i.state==="running"){if(o<=y||!await s(t.executionId,{reason:"launch_timeout"}))return;await r.stop(t,{reason:"launch_timeout"}),await c(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:"the sandbox launch did not report within the launch deadline"}}}),u({level:"warn",event:"execution.launch_timeout",node_id:e});return}if(i.state==="failed"){if(!await s(t.executionId,{reason:"launch_failed"}))return;await c(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:`the sandbox start script failed: ${i.reason}`}}});return}if(o>S){if(!await s(t.executionId,{reason:"launch_lost"}))return;u({level:"warn",event:"execution.launch_lost",node_id:e})}}}a(q,"recoverLaunching");export{F as EnvironmentImagePending,y as LAUNCH_DEADLINE_MS,S as LAUNCH_LOST_GRACE_MS,L as acceptedRelease,P as checkBilledWake,G as endRemoteExecutionIfGone,M as imageForWake,q as recoverLaunching,B as wakeResident};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var l=(r,t)=>k(r,"name",{value:t,configurable:!0});import{clearFrozen as m,endLiveExecution as h,getNode as R}from"../../../core/canvas/index.js";import{isSafeNodeId as b}from"../../../core/canvas/paths.js";import{recordedPidLiveness as _}from"../../../core/canvas/pid.js";import{hasObservedExit as E,hasAbsorbedProfilePauseStop as L}from"../../../core/canvas/executions.js";import{emitEvent as y}from"../../../core/events/emit.js";import{operationIdContext as z}from"../../../core/events/operation-id.js";import{readInterruptedTurn as I}from"../../../core/canvas/recovery.js";import{isProfilePaused as d}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as v}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as p}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as g,isParkedResident as w}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as M}from"../../fleet.js";import{applyParkEvent as N,hasPendingWake as F,parkEvent as x}from"../live-obligation.js";import{FreezeLaneReconciler as A}from"./freeze-lane.js";import{isInBackoff as P}from"./respawn-policy.js";import{handleTerminatingRow as C}from"./terminating.js";import{wantsExecution as D}from"./wants-execution.js";import{enactRequestedStops as S}from"./requested-stops.js";import{endRemoteExecutionIfGone as T,recoverLaunching as G,wakeResident as H}from"./remote-wake.js";import{liveExecutionForNode as U}from"../../../core/canvas/executions.js";function W(r){return r.status==="done"||r.status==="canceled"||r.status==="dead"}l(W,"isTerminal");const q=12e4;function B(r,t){const e=Math.max(...[r.created,r.launched_at].map(a=>a==null?0:Date.parse(a)||0));return e>0&&t-e<q}l(B,"isLaunchInFlight");class pe{static{l(this,"NodeLifecycleReconciler")}freezeLane=new A;async run(t,e){const a=[];await S(t);for(const n of e.rows)await z.fresh(async()=>{try{await this.classifyRow(t,n,e,a)}catch(i){const s=n.node_id;y({level:"error",event:"node.lifecycle.classify_failed",...b(s)?{node_id:s}:{fields:{affected_node_id:s}},error:i})}});return this.freezeLane.run(t,{fleet:e.fleet,candidates:a})}async classifyRow(t,e,a,n){const i=e.node_id;if(W(e)){if(C(e,await a.fleet.has(i)))return;if(w(e)&&!await a.fleet.has(i)&&!d(e.profile_id)&&!await v(i)&&!P(e,t)&&await p(i)){n.push({row:e,enact:"reopen"});return}e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead"&&await h(i,{reason:"observed-dead"}),e.frozen_at!=null&&(e.final_report!=null||e.status==="dead"?await m(i):n.push({row:e,enact:"thaw"}));return}if(await a.fleet.has(i)){const f=await U(i);if(f?.runner==="blaxel"&&f.state==="running"&&!d(e.profile_id)&&await p(i)){if(await H(f)==="lost")return}else f?.runner==="blaxel"&&f.state==="running"&&await T(f);if(await a.fleet.has(i)){d(e.profile_id)?await a.fleet.interruptForProfilePause(i):await this.thawMark(e);return}}if(await G(i,t),d(e.profile_id)){await this.freezeLane.endEpisode(i);return}if(await v(i))return;const s=e.pi_pid==null&&await E(i),u=e.pi_pid==null&&!s&&await L(i),c=s||u||e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead";if(c&&!await a.fleet.hasProfilePauseInterruption(i)&&await h(i,{reason:"observed-dead"}),!await D(e)){await this.thawMark(e),await this.settleParked(e);return}if(P(e,t))return;if(e.status==="idle"&&g(e)&&await p(i)){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null&&(!s||e.frozen_at!=null)&&!u){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){n.push({row:e,enact:"thaw"});return}if(await a.fleet.isClaimed(i)||B(e,t))return;y({level:"warn",event:"node.lifecycle.stranded_launch",node_id:i}),n.push({row:e,enact:"thaw"});return}if(!c)return;const o=M(await R(i),(await I(i))?.interrupted===!0,await F(i));if(o==="respawn-fresh"||o==="respawn-cycle"||o==="respawn-resume"){n.push({row:e,enact:"policy"});return}await a.fleet.applyDeadRowPolicy(i),await this.thawMark(e)}async thawMark(t){t.frozen_at!=null&&await m(t.node_id)}async settleParked(t){if(t.status!=="idle")return;await this.freezeLane.endEpisode(t.node_id);const e=await x(t.node_id,t.lifecycle);e!=="release"&&await N(t.node_id,e)}}export{q as LAUNCH_GRACE_MS,pe as NodeLifecycleReconciler,B as isLaunchInFlight};
1
+ var E=Object.defineProperty;var l=(r,t)=>E(r,"name",{value:t,configurable:!0});import{clearFrozen as m,endLiveExecution as h,getNode as R}from"../../../core/canvas/index.js";import{isSafeNodeId as b}from"../../../core/canvas/paths.js";import{recordedPidLiveness as _}from"../../../core/canvas/pid.js";import{hasObservedExit as L,hasAbsorbedProfilePauseStop as z}from"../../../core/canvas/executions.js";import{emitEvent as y}from"../../../core/events/emit.js";import{operationIdContext as I}from"../../../core/events/operation-id.js";import{readInterruptedTurn as g}from"../../../core/canvas/recovery.js";import{isProfilePaused as d}from"../../../core/profiles/manifest.js";import{isRecoveryHeld as v}from"../../../core/runtime/recovery-hold.js";import{hasUnseenWakeMail as p}from"../../../core/canvas/deliveries.js";import{hasIdleReleaseIntent as w,isParkedResident as N}from"../../../core/runtime/lifecycle.js";import{classifyDeadNode as M}from"../../fleet.js";import{applyParkEvent as F,hasPendingWake as x,parkEvent as A}from"../live-obligation.js";import{FreezeLaneReconciler as C}from"./freeze-lane.js";import{isInBackoff as P}from"./respawn-policy.js";import{asNodePerson as D,NodePersonUnresolvedError as k}from"./node-person.js";import{handleTerminatingRow as S}from"./terminating.js";import{wantsExecution as T}from"./wants-execution.js";import{enactRequestedStops as U}from"./requested-stops.js";import{endRemoteExecutionIfGone as G,recoverLaunching as H,wakeResident as W}from"./remote-wake.js";import{liveExecutionForNode as q}from"../../../core/canvas/executions.js";function B(r){return r.status==="done"||r.status==="canceled"||r.status==="dead"}l(B,"isTerminal");const O=12e4;function j(r,t){const e=Math.max(...[r.created,r.launched_at].map(a=>a==null?0:Date.parse(a)||0));return e>0&&t-e<O}l(j,"isLaunchInFlight");class me{static{l(this,"NodeLifecycleReconciler")}freezeLane=new C;async run(t,e){const a=[];await U(t);for(const n of e.rows)await I.fresh(async()=>{try{await D(n,()=>this.classifyRow(t,n,e,a))}catch(i){const s=n.node_id;y({level:i instanceof k?"warn":"error",event:i instanceof k?"node.lifecycle.person_unresolved":"node.lifecycle.classify_failed",...b(s)?{node_id:s}:{fields:{affected_node_id:s}},error:i})}});return this.freezeLane.run(t,{fleet:e.fleet,candidates:a})}async classifyRow(t,e,a,n){const i=e.node_id;if(B(e)){if(S(e,await a.fleet.has(i)))return;if(N(e)&&!await a.fleet.has(i)&&!d(e.profile_id)&&!await v(i)&&!P(e,t)&&await p(i)){n.push({row:e,enact:"reopen"});return}e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead"&&await h(i,{reason:"observed-dead"}),e.frozen_at!=null&&(e.final_report!=null||e.status==="dead"?await m(i):n.push({row:e,enact:"thaw"}));return}if(await a.fleet.has(i)){const f=await q(i);if(f?.runner==="blaxel"&&f.state==="running"&&!d(e.profile_id)&&await p(i)){if(await W(f)==="lost")return}else f?.runner==="blaxel"&&f.state==="running"&&await G(f);if(await a.fleet.has(i)){d(e.profile_id)?await a.fleet.interruptForProfilePause(i):await this.thawMark(e);return}}if(await H(i,t),d(e.profile_id)){await this.freezeLane.endEpisode(i);return}if(await v(i))return;const s=e.pi_pid==null&&await L(i),u=e.pi_pid==null&&!s&&await z(i),c=s||u||e.pi_pid!=null&&_(e.pi_pid,e.pi_pid_identity)==="dead";if(c&&!await a.fleet.hasProfilePauseInterruption(i)&&await h(i,{reason:"observed-dead"}),!await T(e)){await this.thawMark(e),await this.settleParked(e);return}if(P(e,t))return;if(e.status==="idle"&&w(e)&&await p(i)){n.push({row:e,enact:"idle-release"});return}if(e.pi_pid==null&&(!s||e.frozen_at!=null)&&!u){if(e.respawn_not_before!=null){n.push({row:e,enact:"policy"});return}if(e.frozen_at!=null){n.push({row:e,enact:"thaw"});return}if(await a.fleet.isClaimed(i)||j(e,t))return;y({level:"warn",event:"node.lifecycle.stranded_launch",node_id:i}),n.push({row:e,enact:"thaw"});return}if(!c)return;const o=M(await R(i),(await g(i))?.interrupted===!0,await x(i));if(o==="respawn-fresh"||o==="respawn-cycle"||o==="respawn-resume"){n.push({row:e,enact:"policy"});return}await a.fleet.applyDeadRowPolicy(i),await this.thawMark(e)}async thawMark(t){t.frozen_at!=null&&await m(t.node_id)}async settleParked(t){if(t.status!=="idle")return;await this.freezeLane.endEpisode(t.node_id);const e=await A(t.node_id,t.lifecycle);e!=="release"&&await F(t.node_id,e)}}export{O as LAUNCH_GRACE_MS,me as NodeLifecycleReconciler,j as isLaunchInFlight};
@@ -1,2 +1,2 @@
1
- var H=Object.defineProperty;var l=(s,t)=>H(s,"name",{value:t,configurable:!0});import{envInboxBetweenTurns as U,envNodeId as q,envProfileId as B,envWatcherDebounceMs as J,envWatcherTickMs as W,envWatcherBackstopMs as $}from"../shared/env.js";import{coalesceBrokerInbox as G,entryCards as X}from"../core/runtime/broker/inbox.js";import{acknowledgeBrokerMail as j,claimBrokerMail as z,brokerExtensionState as F}from"../core/runtime/broker/daemon-ops.js";import{materializeSpilledBody as L}from"../core/runtime/broker/spilled-body.js";import{brokerSignalClient as S}from"../core/runtime/broker/signal-stream.js";import{wasTurnRefused as V}from"../core/runtime/broker/extension-abort.js";import{isDaemonTransportApiError as R}from"../api/errors.js";import{announceMessageOrigin as Q,messageSignature as v}from"../core/runtime/stamp/channel.js";import{captureGoalIfAbsent as Y,generateAndCommitInitialName as K}from"./broker-local.js";import{emitEvent as N}from"../core/events/emit.js";import{errorClassFromError as Z}from"../core/events/errors.js";import{operationIdContext as m}from"../core/events/operation-id.js";import{SITUATIONAL_CONTEXT_CUSTOM_TYPE as _}from"../shared/generated-context.js";import{isProfilePaused as ee}from"../core/profiles/manifest.js";import{brokerDisposeAndExit as te,brokerIdleTurnStart as ie,brokerRunTurnBusy as ne,HELD_DEFERRED_INBOX_PROMPT_JOIN as re}from"../core/runtime/broker/held-deferred-inbox.js";const b=64,D=16;let p,se=0;class P extends Error{static{l(this,"WatcherFatalError")}constructor(t,e){super(t,{cause:e}),this.name="WatcherFatalError"}}function ae(){return{tickMs:W(),debounceMs:J()}}l(ae,"resolveCadence");function I(){const s=q();return s===void 0||s.trim()===""?void 0:s}l(I,"currentNodeId");function A(){const s=B();return s!==void 0&&s!==""&&ee(s)}l(A,"profilePaused");function E(s){try{return Z(s)}catch{return{class:"unknown"}}}l(E,"safeErrorClass");function w(s){try{N(s)}catch{}}l(w,"emitBestEffort");function C(s){try{m.fresh(t=>{w({...s,operation_id:t})})}catch{}}l(C,"emitFreshBestEffort");function k(s,t){try{m.run(s,()=>{w({...t,operation_id:s})})}catch{}}l(k,"emitStoredBestEffort");function de(s){return s.kind==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:s.entries.map(t=>({...t.from===null?{}:{from:t.from},...t.from_name===void 0?{}:{fromName:t.from_name},kind:t.kind,tier:t.tier,...t.ref===void 0?{}:{ref:t.ref}}))}}l(de,"deliveryOrigin");function x(s,t){if(s.length===0)throw new Error(`cannot create an empty ${t} delivery`);const e=[...new Set(s.map(r=>r.operation_id))].sort(),i=e.length-D;return{channel:t,entryIds:s.map(r=>r.entry_id),throughEntryId:s.at(-1).entry_id,sourceOperationIds:e.slice(0,D),...i>0?{sourceOperationIdsOmitted:i}:{}}}l(x,"deliveryFacts");function y(s){return{channel:s.channel,entry_ids:s.entryIds,through_entry_id:s.throughEntryId,source_operation_ids:s.sourceOperationIds,...s.sourceOperationIdsOmitted===void 0?{}:{source_operation_ids_omitted:s.sourceOperationIdsOmitted}}}l(y,"deliveryFields");function oe(s){k(s.operationId,{level:"info",event:"inbox.delivery.completed",outcome:"succeeded",fields:y(s)})}l(oe,"emitDeliveryCompleted");function T(s,t,e,i){k(s,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:e,...y(t)}})}l(T,"emitDeliveryFailure");function M(s,t){k(s.operationId,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error_class:{class:"unknown"},fields:{stage:"abandoned",reason:t,...y(s)}})}l(M,"emitDeliveryAbandoned");function fe(s){return typeof s=="string"?s:Array.isArray(s)?s.filter(t=>typeof t=="object"&&t!==null&&typeof t.text=="string").map(t=>t.text).join(`
2
- `):""}l(fe,"messageText");function O(s){return s==="quit"||s==="reload"||s==="new"||s==="resume"||s==="fork"}l(O,"isSessionShutdownReason");function le(s){switch(s){case"quit":return"shutdown";case"reload":case"new":case"resume":case"fork":return"reload";default:return s}}l(le,"disposalReasonForShutdown");function he(s){return typeof s=="string"?s.slice(0,128):s===null?"null":s===void 0?"undefined":typeof s=="number"||typeof s=="boolean"||typeof s=="bigint"?String(s).slice(0,128):typeof s}l(he,"boundedRuntimeReason");class ue{static{l(this,"CanvasInboxWatcher")}pi;cadence;generation;timer;backstop;debounceTimer;signalUnsubscribers=[];rerun=!1;retryNeeded=!1;armed=!1;lastCtx;streaming=!1;runNode=U();nodeId;claims=new Map;reportBodies=new Map;tickInFlight;buffer=[];lastArrival=0;pendingHandoffs=[];pendingCommit;promptJoinInFlight=!1;replayUnseenInherited=!1;seeded=!1;disposed=!1;disposalReason;fatalError;fatalEscaped=!1;constructor(t,e,i){this.pi=t,this.cadence=e,this.generation=i}start(){const t=l((e,i)=>{this.canMutate()&&this.captureCtx(e,i)},"capture");this.pi.on("session_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.arm())}),this.pi.on("turn_end",t),this.pi.on("agent_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!0)}),this.pi.on("agent_end",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!1)}),this.pi.on("message_end",e=>{if(!this.canMutate())return;const i=e?.message;if(i?.role!=="user"&&i?.role!=="custom"||!this.pendingHandoffs.some(d=>d.awaitingDequeue!==void 0))return;const r=v(fe(i.content)),n=this.pendingHandoffs.find(d=>d.awaitingDequeue===r);n!==void 0&&delete n.awaitingDequeue}),this.pi.on("agent_settled",async(e,i)=>{if(!this.canMutate())return;this.captureCtx(e,i);const r=I();if(r!==void 0)try{this.assertNodeOwnership(r,"settle"),await this.tickInFlight,this.seeded||await this.claimMail(r);const n=await this.settle(r,i,!1,!0);n==="refresh_held"&&this.dispose("refresh",!1),this.runNode&&n==="settled"&&this.canMutate()&&this.buffer.length>0&&await this.flushOrdinary(r),this.syncTimers()}catch(n){this.dispose("shutdown",!1,void 0,{error:n,stage:"settle"})}}),this.pi.on("session_shutdown",async e=>{if(!this.canMutate())return;let i;try{i=e?.reason}catch{i=void 0}const r=O(i)?le(i):"reload";O(i)||C({level:"warn",event:"inbox.lifecycle.unknown_shutdown_reason",outcome:"failed",fields:{reason:he(i)}});try{await this.disposeAtSettlement(r,this.lastCtx)}catch(n){this.dispose(r,!1,void 0,{error:n,stage:"settle"})}})}arm(){if(this.armed)return;this.armed=!0;const t=S();this.signalUnsubscribers.push(t.subscribe("state",()=>this.syncTimers()),t.subscribe("mail",()=>this.runTick("schedule")),t.subscribe("resync",()=>this.runTick("schedule"))),this.syncTimers(),t.state!=="connected"&&this.runTick("schedule")}async disposeAtSettlement(t,e){const i=I();if(i===void 0){this.dispose(t,!1);return}try{this.assertNodeOwnership(i,"settle");const r=await this.settle(i,e,t!=="refresh");this.dispose(r==="refresh_held"?"refresh":t,!1)}catch(r){this.dispose(t,!1,void 0,{error:r,stage:"settle"})}}dispose(t,e,i,r){if(this.disposed)return;this.disposed=!0,this.disposalReason=t,this.clearTimer();for(const d of this.signalUnsubscribers.splice(0))d();const n=r;{const d=[...new Set([...this.pendingCommit?.handoffs??[],...this.pendingHandoffs.splice(0)])];this.buffer.length=0,this.claims.clear(),this.reportBodies.clear(),this.pendingCommit=void 0,this.promptJoinInFlight=!1,this.replayUnseenInherited=!1,this.nodeId=void 0,this.lastCtx=void 0,this.lastArrival=0,this.streaming=!1,this.seeded=!1,this.ownsCurrentGeneration()&&(p=void 0);for(const a of d)M(a,t)}if(n!==void 0){this.scheduleHandlerFatal(n.error,n.stage);return}}ownsCurrentGeneration(){return p===this&&p.generation===this.generation}canMutate(){return this.ownsCurrentGeneration()&&!this.disposed&&this.fatalError===void 0}captureCtx(t,e){e!==void 0&&(this.lastCtx=e)}clearTimer(){this.timer!==void 0&&clearInterval(this.timer),this.backstop!==void 0&&clearInterval(this.backstop),this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer),this.timer=this.backstop=this.debounceTimer=void 0}syncTimers(){if(!this.armed||!this.canMutate())return;const t=S().state==="connected",e=!t||this.buffer.length>0||this.pendingCommit!==void 0||this.retryNeeded;e&&this.timer===void 0?(this.timer=setInterval(()=>this.runTick("schedule"),this.cadence.tickMs),this.timer.unref?.()):!e&&this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0),t&&this.backstop===void 0?(this.backstop=setInterval(()=>this.runTick("schedule"),$()),this.backstop.unref?.()):!t&&this.backstop!==void 0&&(clearInterval(this.backstop),this.backstop=void 0),this.buffer.length===0&&this.debounceTimer!==void 0&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0)}armDebounce(){this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer);const t=Math.max(0,this.lastArrival+this.cadence.debounceMs-Date.now());this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.runTick("schedule")},t),this.debounceTimer.unref?.()}isIdle(){if(this.runNode&&ne())return!1;try{if(typeof this.lastCtx?.isIdle=="function")return this.lastCtx.isIdle()===!0}catch{}return!this.streaming}assertNodeOwnership(t,e){!this.seeded||this.nodeId===void 0||this.nodeId===t||this.raiseReadFatal(e,new Error(`watcher node changed from ${this.nodeId} to ${t}`))}raiseFatal(t,e,i,r){throw this.fatalError===void 0&&(this.fatalError=new P(e,i),this.clearTimer(),C({level:"error",event:t,outcome:"failed",error:i,error_class:E(i),fields:r})),this.fatalError}raiseReadFatal(t,e){return this.raiseFatal("inbox.read.failed",`inbox ${t} state is corrupt`,e,{stage:t})}raiseSituationalFatal(t,e){return this.raiseFatal("inbox.situational_context.missing","situational context marker has no readable sidecar",e,{entry_id:t})}escapeFatal(t,e){if(!this.fatalEscaped){if(this.fatalEscaped=!0,e==="throw")throw t;queueMicrotask(()=>{throw t})}}scheduleHandlerFatal(t,e){let i;if(t instanceof P)i=t;else try{this.raiseReadFatal(e,t)}catch(r){i=r}this.escapeFatal(i,"schedule")}runTick(t="throw"){if(!this.canMutate())return;if(this.tickInFlight!==void 0){this.rerun=!0;return}const e=this.tick().then(()=>{this.retryNeeded=!1}).catch(i=>{if(this.canMutate()){if(R(i)){this.retryNeeded=!0,C({level:"warn",event:"inbox.read.failed",outcome:"failed",error:i,error_class:E(i),fields:{stage:"poll"}});return}this.scheduleHandlerFatal(i,"poll")}}).finally(()=>{this.tickInFlight===e&&(this.tickInFlight=void 0),this.syncTimers(),this.rerun&&this.canMutate()&&(this.rerun=!1,this.runTick("schedule"))});this.tickInFlight=e}async claimMail(t){this.assertNodeOwnership(t,"poll");let e;try{e=await z(t,"wake",this.reportBodies)}catch(a){throw R(a)&&(this.replayUnseenInherited=!0),a}if(!this.canMutate()||e.action==="hold")return!1;const i=this.replayUnseenInherited;this.replayUnseenInherited=!1,this.nodeId=t,this.seeded=!0;const r=new Set(e.deliveries.map(a=>a.entry.entry_id)),n=this.buffer.filter(a=>!r.has(a.entry_id));for(const a of n)this.claims.delete(a.entry_id);if(this.buffer.splice(0,this.buffer.length,...this.buffer.filter(a=>r.has(a.entry_id))),n.length>0){const a=globalThis[Symbol.for("@crouton-kit/crtr:watcher-cancel-probe")];typeof a=="function"&&a(n.map(f=>f.entry_id),process.hrtime.bigint())}let d=!1;for(const a of e.deliveries){const f=a.entry.entry_id;this.claims.has(f)||(a.entry=L(a.entry),this.claims.set(f,a),a.handoff==="inherited"&&!i?m.fresh(o=>{this.pendingHandoffs.push({...x([a.entry],"visible"),operationId:o,settleAtAgentSettled:!0})}):(this.buffer.push(a.entry),this.lastArrival=Date.now(),d=!0))}return d&&this.armDebounce(),this.syncTimers(),!0}async tick(){const t=I();if(t!==void 0){if(this.pendingCommit!==void 0){await this.retryPendingCommit(t)==="refresh_held"&&this.canMutate()&&this.dispose("refresh",!1);return}this.promptJoinInFlight||A()||this.pendingHandoffs.length>=b||await this.claimMail(t)&&this.buffer.length>0&&(!this.runNode||this.isIdle()||this.buffer.some(e=>e.tier==="critical"))&&Date.now()-this.lastArrival>=this.cadence.debounceMs&&await this.flushOrdinary(t)}}missingChannelEntries(t){const e=t.filter(n=>this.claims.has(n.entry_id)),i=this.coveredEntryIds("hidden"),r=this.coveredEntryIds("visible");return{hiddenEntries:e.filter(n=>(n.data?.situational===!0||n.data?.situationalOnly===!0)&&!i.has(n.entry_id)),visibleEntries:e.filter(n=>n.data?.situationalOnly!==!0&&!r.has(n.entry_id))}}visibleRoute(t){return t.length===0?"none":this.isIdle()?"idle":this.runNode?t.some(e=>e.tier==="critical")?"critical":"none":t.some(e=>e.tier==="critical")?"critical":t.some(e=>e.tier==="urgent"||e.kind==="final")?"steer":"followUp"}buildPlan(t){const{hiddenEntries:e,visibleEntries:i}=this.missingChannelEntries(t),r=new Set(e.map(u=>u.entry_id)),n=new Set(i.map(u=>u.entry_id)),d=t.filter(u=>r.has(u.entry_id)||n.has(u.entry_id)),a=this.isIdle()&&d.length>0&&d.every(u=>u.tier==="deferred"),f=this.visibleRoute(i)==="critical",o=!a&&!f&&e.length>0,c=!a&&!f&&i.length>0;return{hiddenEntries:e,visibleEntries:i,deferredHold:a,sendCount:Number(o)+Number(c)}}ordinaryPlan(){return this.buildPlan(this.buffer)}async contextCards(t,e){const i=[];if(e.some(r=>r.data?.situational===!0)){const r=e.at(-1).entry_id;let n;try{n=(await F(t)).situational_card}catch(d){this.raiseSituationalFatal(r,d)}n===null&&this.raiseSituationalFatal(r,new Error(`missing situational context for entry ${r}`)),i.push(n)}for(const r of e)r.data?.situationalOnly===!0&&i.push(...X(r));return i}digest(t,e){try{return G(t)}catch(i){this.raiseReadFatal(e,i)}}sendDelivery(t,e,i,r,n){this.pendingHandoffs.length>=b&&this.raiseReadFatal(r,new Error(`pending handoff capacity exceeded before ${t} send`));let d;try{d=x(e,t)}catch(o){this.raiseReadFatal(r,o)}let a;try{m.fresh(o=>{a=o,w({level:"info",event:"inbox.delivery.started",operation_id:o,fields:y(d)}),i()})}catch(o){return a===void 0&&this.raiseReadFatal(r,o),T(a,d,"send",o),"failed"}a===void 0&&this.raiseReadFatal(r,new Error(`${t} delivery returned without an operation id`));const f={operationId:a,...d,...n===void 0?{}:{awaitingDequeue:n}};return this.canMutate()?(this.pendingHandoffs.push(f),"handed-off"):(this.disposed&&this.disposalReason!==void 0&&M(f,this.disposalReason),"inactive")}sendContext(t,e,i,r,n,d){const a=r==="steer"||r==="followUp"?r:this.isIdle()?void 0:"followUp",f=a===void 0||i.length===0?void 0:v(i.at(-1));return this.sendDelivery("hidden",e,()=>{this.runNode&&n&&this.pi.appendEntry("crtr-turn-input",{message_ids:e.map(o=>o.entry_id)}),i.forEach((o,c)=>{const u=n&&c===i.length-1;this.pi.sendMessage({customType:_,content:o,display:!0,details:{nodeId:t}},a!==void 0?{deliverAs:a}:u?{deliverAs:"followUp",triggerTurn:!0}:{})})},d,f)}sendVisible(t,e,i,r,n,d){return this.sendDelivery("visible",t,()=>{if(n!=="idle"&&n!=="steer"&&n!=="followUp")throw new Error(`visible send requested for non-send route ${n}`);for(const a of e)this.pi.sendMessage({customType:_,content:a,display:!0},n==="idle"?{}:{deliverAs:n});if(Q(i,r),n==="idle"){const a=ie();if(a===void 0)throw new Error("broker idle-turn admission is unavailable");a(i,this.runNode?t.map(f=>f.entry_id):[])}else this.pi.sendUserMessage(i,{deliverAs:n})},d,n==="steer"||n==="followUp"?v(i):void 0)}abortCritical(){try{this.lastCtx?.abort?.()}catch{}}requeueFromBatch(t,e){if(e.size===0)return;const i=t.filter(d=>e.has(d.entry_id)),r=new Set(i.map(d=>d.entry_id)),n=this.buffer.filter(d=>!r.has(d.entry_id));this.buffer.splice(0,this.buffer.length,...i,...n)}async executePlan(t,e,i){const r=new Set,n=this.visibleRoute(e.visibleEntries);if(n==="critical"){if(this.abortCritical(),!this.canMutate())return{inactive:!0,requeueEntryIds:r};for(const o of e.visibleEntries)r.add(o.entry_id);for(const o of e.hiddenEntries)r.add(o.entry_id);return{inactive:!1,requeueEntryIds:r}}if(this.runNode&&n==="none")return{inactive:!1,requeueEntryIds:new Set([...e.hiddenEntries,...e.visibleEntries].map(o=>o.entry_id))};const d=e.visibleEntries.length>0?this.digest(e.visibleEntries,i):[],[a,...f]=d;for(const o of f)for(const c of o.entries)r.add(c.entry_id);if(e.hiddenEntries.length>0){const o=await this.contextCards(t,e.hiddenEntries),c=this.sendContext(t,e.hiddenEntries,o,n,a===void 0,i);if(c==="inactive")return{inactive:!0,requeueEntryIds:r};if(c==="failed")for(const u of e.hiddenEntries)r.add(u.entry_id)}if(!this.canMutate())return{inactive:!0,requeueEntryIds:r};if(a!==void 0){const o=this.sendVisible(a.entries,a.cards,a.text,de(a),n,i);if(o==="inactive")return{inactive:!0,requeueEntryIds:r};if(o==="failed")for(const c of a.entries)r.add(c.entry_id);else a.kind==="human"&&(await Y(t,a.text).catch(()=>{}),K(t,a.text))}return{inactive:!1,requeueEntryIds:r}}async flushOrdinary(t){if(this.buffer.length===0)return"empty";const e=this.ordinaryPlan();if(e.deferredHold)return"held";if(this.pendingHandoffs.length+e.sendCount>b)return"capacity-blocked";const i=[...this.buffer],r=await this.executePlan(t,e,"poll");return r.inactive||(this.buffer.splice(0,i.length),this.requeueFromBatch(i,r.requeueEntryIds)),"attempted"}async prependHeldDeferredInbox(t){if(!this.canMutate()||this.nodeId===void 0||A())return;const e=this.ordinaryPlan();if(!e.deferredHold)return;const i=e.visibleEntries.length===0?[]:this.digest(e.visibleEntries,"poll"),r=+(e.hiddenEntries.length>0)+i.length;if(this.pendingHandoffs.length+r>b)return;const n=[...this.buffer];this.promptJoinInFlight=!0;try{this.runNode&&this.pi.appendEntry("crtr-turn-input",{message_ids:[...e.hiddenEntries,...e.visibleEntries].map(d=>d.entry_id)}),e.hiddenEntries.length>0&&await this.sendPromptJoinDelivery(t,"hidden",e.hiddenEntries,await this.contextCards(this.nodeId,e.hiddenEntries));for(const d of i)await this.sendPromptJoinDelivery(t,"visible",d.entries,[...d.cards,d.text]);if(!this.canMutate())return;this.buffer.splice(0,n.length)}finally{this.promptJoinInFlight=!1}}async sendPromptJoinDelivery(t,e,i,r){let n;try{n=x(i,e)}catch(f){this.raiseReadFatal("poll",f)}let d;try{await m.fresh(async f=>{d=f,w({level:"info",event:"inbox.delivery.started",operation_id:f,fields:y(n)});for(const o of r)await t.sendCustomMessage({customType:_,content:o,display:!0})})}catch(f){throw d===void 0&&this.raiseReadFatal("poll",f),T(d,n,"send",f),f}d===void 0&&this.raiseReadFatal("poll",new Error(`${e} prompt-join delivery returned without an operation id`));const a={operationId:d,...n,settleAtAgentSettled:!0};if(!this.canMutate()){this.disposed&&this.disposalReason!==void 0&&M(a,this.disposalReason);return}this.pendingHandoffs.push(a)}coveredEntryIds(t){const e=new Set;for(const i of this.pendingHandoffs)if(i.channel===t)for(const r of i.entryIds)e.add(r);return e}retryPendingCommit(t){const e=this.pendingCommit;if(e===void 0)return Promise.resolve("settled");if(e.attempt!==void 0)return e.attempt;const i=this.attemptPendingCommit(t,e).finally(()=>{e.attempt===i&&(e.attempt=void 0)});return e.attempt=i,i}async attemptPendingCommit(t,e){let i=!1;try{const n=await j(t,e.receipts);if(n.action==="hold")return"refresh_held";for(const d of e.receipts){const a=n.results.find(f=>f.delivery_id===d.delivery_id);if(a?.outcome!==d.disposition&&a?.outcome!=="stale")throw new Error("daemon returned no terminal mail settlement outcome")}i=n.results.every(d=>d.outcome==="acknowledged")}catch(n){if(this.pendingCommit===e)for(const d of e.handoffs)T(d.operationId,d,"receipt_commit",n);return String(n?.message).startsWith("conversation_write_failed")&&(N({level:"error",event:"broker.exited",node_id:t,error:n,fields:{fault:"conversation_write_failed"}}),te()?.("conversation_write_failed",1)),"held"}if(this.pendingCommit!==e)return"settled";for(const n of e.entryIds)this.claims.delete(n);if(e.receipts.some(n=>n.disposition==="released")){const n=new Set(e.entryIds);this.buffer.splice(0,this.buffer.length,...this.buffer.filter(d=>!n.has(d.entry_id)))}this.pendingCommit=void 0;const r=this.detachPending(n=>n.entryIds.every(d=>!this.claims.has(d)));for(const n of r)i&&oe(n);return"settled"}async settle(t,e,i,r=!1){if(i)try{if(e?.hasPendingMessages?.()===!0)return"held"}catch{}if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const n=V(),d=!n&&this.pendingHandoffs.some(h=>h.awaitingDequeue!==void 0)&&await this.nodeRefreshing(t);if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const a=new Set(this.buffer.map(h=>h.entry_id)),f=new Set(d?this.pendingHandoffs.filter(h=>h.awaitingDequeue!==void 0).flatMap(h=>[...h.entryIds]):[]),o=this.pendingHandoffs.filter(h=>(r||h.settleAtAgentSettled!==!0)&&h.entryIds.every(g=>!f.has(g))),c=new Set(o.flatMap(h=>[...h.entryIds])),u=[...this.claims.keys()].filter(h=>n||c.has(h)&&!a.has(h));return u.length===0?"settled":(this.pendingCommit={handoffs:o,entryIds:u,receipts:u.map(h=>{const g=this.claims.get(h);return{delivery_id:g.delivery_id,attempts:g.attempts,disposition:n?"released":"acknowledged"}})},this.retryPendingCommit(t))}async nodeRefreshing(t){try{return(await F(t)).node.intent==="refresh"}catch{return!0}}detachPending(t){const e=[];for(let i=this.pendingHandoffs.length-1;i>=0;i-=1){const r=this.pendingHandoffs[i];t(r)&&e.push(...this.pendingHandoffs.splice(i,1))}return e.reverse(),e}}function ce(s,t){p?.dispose("reload",!1);const e=new ue(s,t,++se);p=e;const i=l(r=>e.prependHeldDeferredInbox(r),"promptJoin");globalThis[re]=i;try{e.start()}catch(r){throw e.dispose("reload",!1),r}return e}l(ce,"installWatcher");function me(s){const t=ce(s,ae());return()=>t.dispose("shutdown",!1)}l(me,"registerCanvasInboxWatcher");var Re=me;export{Re as default,me as registerCanvasInboxWatcher};
1
+ var U=Object.defineProperty;var f=(s,t)=>U(s,"name",{value:t,configurable:!0});import{envInboxBetweenTurns as q,envNodeId as B,envProfileId as J,envWatcherDebounceMs as W,envWatcherTickMs as $,envWatcherBackstopMs as G}from"../shared/env.js";import{coalesceBrokerInbox as X,entryCards as j}from"../core/runtime/broker/inbox.js";import{acknowledgeBrokerMail as z,claimBrokerMail as L,brokerExtensionState as F}from"../core/runtime/broker/daemon-ops.js";import{materializeSpilledBody as V}from"../core/runtime/broker/spilled-body.js";import{brokerSignalClient as S}from"../core/runtime/broker/signal-stream.js";import{wasTurnRefused as Q}from"../core/runtime/broker/extension-abort.js";import{isDaemonTransportApiError as R,isTokenRevokedApiError as Y}from"../api/errors.js";import{announceMessageOrigin as K,messageSignature as _}from"../core/runtime/stamp/channel.js";import{captureGoalIfAbsent as Z,generateAndCommitInitialName as ee}from"./broker-local.js";import{emitEvent as O}from"../core/events/emit.js";import{errorClassFromError as te}from"../core/events/errors.js";import{operationIdContext as m}from"../core/events/operation-id.js";import{SITUATIONAL_CONTEXT_CUSTOM_TYPE as I}from"../shared/generated-context.js";import{isProfilePaused as ie}from"../core/profiles/manifest.js";import{brokerDisposeAndExit as N,brokerIdleTurnStart as ne,brokerRunTurnBusy as re,HELD_DEFERRED_INBOX_PROMPT_JOIN as se}from"../core/runtime/broker/held-deferred-inbox.js";const b=64,A=16;let p,ae=0;class D extends Error{static{f(this,"WatcherFatalError")}constructor(t,e){super(t,{cause:e}),this.name="WatcherFatalError"}}function de(){return{tickMs:$(),debounceMs:W()}}f(de,"resolveCadence");function E(){const s=B();return s===void 0||s.trim()===""?void 0:s}f(E,"currentNodeId");function P(){const s=J();return s!==void 0&&s!==""&&ie(s)}f(P,"profilePaused");function k(s){try{return te(s)}catch{return{class:"unknown"}}}f(k,"safeErrorClass");function v(s){try{O(s)}catch{}}f(v,"emitBestEffort");function w(s){try{m.fresh(t=>{v({...s,operation_id:t})})}catch{}}f(w,"emitFreshBestEffort");function C(s,t){try{m.run(s,()=>{v({...t,operation_id:s})})}catch{}}f(C,"emitStoredBestEffort");function oe(s){return s.kind==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:s.entries.map(t=>({...t.from===null?{}:{from:t.from},...t.from_name===void 0?{}:{fromName:t.from_name},kind:t.kind,tier:t.tier,...t.ref===void 0?{}:{ref:t.ref}}))}}f(oe,"deliveryOrigin");function x(s,t){if(s.length===0)throw new Error(`cannot create an empty ${t} delivery`);const e=[...new Set(s.map(r=>r.operation_id))].sort(),i=e.length-A;return{channel:t,entryIds:s.map(r=>r.entry_id),throughEntryId:s.at(-1).entry_id,sourceOperationIds:e.slice(0,A),...i>0?{sourceOperationIdsOmitted:i}:{}}}f(x,"deliveryFacts");function y(s){return{channel:s.channel,entry_ids:s.entryIds,through_entry_id:s.throughEntryId,source_operation_ids:s.sourceOperationIds,...s.sourceOperationIdsOmitted===void 0?{}:{source_operation_ids_omitted:s.sourceOperationIdsOmitted}}}f(y,"deliveryFields");function le(s){C(s.operationId,{level:"info",event:"inbox.delivery.completed",outcome:"succeeded",fields:y(s)})}f(le,"emitDeliveryCompleted");function T(s,t,e,i){C(s,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error:i,error_class:k(i),fields:{stage:e,...y(t)}})}f(T,"emitDeliveryFailure");function M(s,t){C(s.operationId,{level:"error",event:"inbox.delivery.failed",outcome:"failed",error_class:{class:"unknown"},fields:{stage:"abandoned",reason:t,...y(s)}})}f(M,"emitDeliveryAbandoned");function fe(s){return typeof s=="string"?s:Array.isArray(s)?s.filter(t=>typeof t=="object"&&t!==null&&typeof t.text=="string").map(t=>t.text).join(`
2
+ `):""}f(fe,"messageText");function H(s){return s==="quit"||s==="reload"||s==="new"||s==="resume"||s==="fork"}f(H,"isSessionShutdownReason");function he(s){switch(s){case"quit":return"shutdown";case"reload":case"new":case"resume":case"fork":return"reload";default:return s}}f(he,"disposalReasonForShutdown");function ue(s){return typeof s=="string"?s.slice(0,128):s===null?"null":s===void 0?"undefined":typeof s=="number"||typeof s=="boolean"||typeof s=="bigint"?String(s).slice(0,128):typeof s}f(ue,"boundedRuntimeReason");class ce{static{f(this,"CanvasInboxWatcher")}pi;cadence;generation;timer;backstop;debounceTimer;signalUnsubscribers=[];rerun=!1;retryNeeded=!1;polledOk=!1;armed=!1;lastCtx;streaming=!1;runNode=q();nodeId;claims=new Map;reportBodies=new Map;tickInFlight;buffer=[];lastArrival=0;pendingHandoffs=[];pendingCommit;promptJoinInFlight=!1;replayUnseenInherited=!1;seeded=!1;disposed=!1;disposalReason;fatalError;fatalEscaped=!1;constructor(t,e,i){this.pi=t,this.cadence=e,this.generation=i}start(){const t=f((e,i)=>{this.canMutate()&&this.captureCtx(e,i)},"capture");this.pi.on("session_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.arm())}),this.pi.on("turn_end",t),this.pi.on("agent_start",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!0)}),this.pi.on("agent_end",(e,i)=>{this.canMutate()&&(this.captureCtx(e,i),this.streaming=!1)}),this.pi.on("message_end",e=>{if(!this.canMutate())return;const i=e?.message;if(i?.role!=="user"&&i?.role!=="custom"||!this.pendingHandoffs.some(d=>d.awaitingDequeue!==void 0))return;const r=_(fe(i.content)),n=this.pendingHandoffs.find(d=>d.awaitingDequeue===r);n!==void 0&&delete n.awaitingDequeue}),this.pi.on("agent_settled",async(e,i)=>{if(!this.canMutate())return;this.captureCtx(e,i);const r=E();if(r!==void 0)try{this.assertNodeOwnership(r,"settle"),await this.tickInFlight,this.seeded||await this.claimMail(r);const n=await this.settle(r,i,!1,!0);n==="refresh_held"&&this.dispose("refresh",!1),this.runNode&&n==="settled"&&this.canMutate()&&this.buffer.length>0&&await this.flushOrdinary(r),this.syncTimers()}catch(n){this.dispose("shutdown",!1,void 0,{error:n,stage:"settle"})}}),this.pi.on("session_shutdown",async e=>{if(!this.canMutate())return;let i;try{i=e?.reason}catch{i=void 0}const r=H(i)?he(i):"reload";H(i)||w({level:"warn",event:"inbox.lifecycle.unknown_shutdown_reason",outcome:"failed",fields:{reason:ue(i)}});try{await this.disposeAtSettlement(r,this.lastCtx)}catch(n){this.dispose(r,!1,void 0,{error:n,stage:"settle"})}})}arm(){if(this.armed)return;this.armed=!0;const t=S();this.signalUnsubscribers.push(t.subscribe("state",()=>this.syncTimers()),t.subscribe("mail",()=>this.runTick("schedule")),t.subscribe("resync",()=>this.runTick("schedule"))),this.syncTimers(),t.state!=="connected"&&this.runTick("schedule")}async disposeAtSettlement(t,e){const i=E();if(i===void 0){this.dispose(t,!1);return}try{this.assertNodeOwnership(i,"settle");const r=await this.settle(i,e,t!=="refresh");this.dispose(r==="refresh_held"?"refresh":t,!1)}catch(r){this.dispose(t,!1,void 0,{error:r,stage:"settle"})}}dispose(t,e,i,r){if(this.disposed)return;this.disposed=!0,this.disposalReason=t,this.clearTimer();for(const d of this.signalUnsubscribers.splice(0))d();const n=r;{const d=[...new Set([...this.pendingCommit?.handoffs??[],...this.pendingHandoffs.splice(0)])];this.buffer.length=0,this.claims.clear(),this.reportBodies.clear(),this.pendingCommit=void 0,this.promptJoinInFlight=!1,this.replayUnseenInherited=!1,this.nodeId=void 0,this.lastCtx=void 0,this.lastArrival=0,this.streaming=!1,this.seeded=!1,this.ownsCurrentGeneration()&&(p=void 0);for(const a of d)M(a,t)}if(n!==void 0){this.scheduleHandlerFatal(n.error,n.stage);return}}ownsCurrentGeneration(){return p===this&&p.generation===this.generation}canMutate(){return this.ownsCurrentGeneration()&&!this.disposed&&this.fatalError===void 0}captureCtx(t,e){e!==void 0&&(this.lastCtx=e)}clearTimer(){this.timer!==void 0&&clearInterval(this.timer),this.backstop!==void 0&&clearInterval(this.backstop),this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer),this.timer=this.backstop=this.debounceTimer=void 0}syncTimers(){if(!this.armed||!this.canMutate())return;const t=S().state==="connected",e=!t||this.buffer.length>0||this.pendingCommit!==void 0||this.retryNeeded;e&&this.timer===void 0?(this.timer=setInterval(()=>this.runTick("schedule"),this.cadence.tickMs),this.timer.unref?.()):!e&&this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0),t&&this.backstop===void 0?(this.backstop=setInterval(()=>this.runTick("schedule"),G()),this.backstop.unref?.()):!t&&this.backstop!==void 0&&(clearInterval(this.backstop),this.backstop=void 0),this.buffer.length===0&&this.debounceTimer!==void 0&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0)}armDebounce(){this.debounceTimer!==void 0&&clearTimeout(this.debounceTimer);const t=Math.max(0,this.lastArrival+this.cadence.debounceMs-Date.now());this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.runTick("schedule")},t),this.debounceTimer.unref?.()}isIdle(){if(this.runNode&&re())return!1;try{if(typeof this.lastCtx?.isIdle=="function")return this.lastCtx.isIdle()===!0}catch{}return!this.streaming}assertNodeOwnership(t,e){!this.seeded||this.nodeId===void 0||this.nodeId===t||this.raiseReadFatal(e,new Error(`watcher node changed from ${this.nodeId} to ${t}`))}raiseFatal(t,e,i,r){throw this.fatalError===void 0&&(this.fatalError=new D(e,i),this.clearTimer(),w({level:"error",event:t,outcome:"failed",error:i,error_class:k(i),fields:r})),this.fatalError}raiseReadFatal(t,e){return this.raiseFatal("inbox.read.failed",`inbox ${t} state is corrupt`,e,{stage:t})}raiseSituationalFatal(t,e){return this.raiseFatal("inbox.situational_context.missing","situational context marker has no readable sidecar",e,{entry_id:t})}escapeFatal(t,e){if(!this.fatalEscaped){if(this.fatalEscaped=!0,e==="throw")throw t;queueMicrotask(()=>{throw t})}}scheduleHandlerFatal(t,e){let i;if(t instanceof D)i=t;else try{this.raiseReadFatal(e,t)}catch(r){i=r}this.escapeFatal(i,"schedule")}runTick(t="throw"){if(!this.canMutate())return;if(this.tickInFlight!==void 0){this.rerun=!0;return}const e=this.tick().then(()=>{this.retryNeeded=!1,this.polledOk=!0}).catch(i=>{if(this.canMutate()){if(R(i)){this.retryNeeded=!0,w({level:"warn",event:"inbox.read.failed",outcome:"failed",error:i,error_class:k(i),fields:{stage:"poll"}});return}if(this.polledOk&&Y(i)){this.clearTimer(),w({level:"info",event:"inbox.poll.token_revoked",outcome:"succeeded",fields:{stage:"poll"}}),N()?.("token-revoked");return}this.scheduleHandlerFatal(i,"poll")}}).finally(()=>{this.tickInFlight===e&&(this.tickInFlight=void 0),this.syncTimers(),this.rerun&&this.canMutate()&&(this.rerun=!1,this.runTick("schedule"))});this.tickInFlight=e}async claimMail(t){this.assertNodeOwnership(t,"poll");let e;try{e=await L(t,"wake",this.reportBodies)}catch(a){throw R(a)&&(this.replayUnseenInherited=!0),a}if(!this.canMutate()||e.action==="hold")return!1;const i=this.replayUnseenInherited;this.replayUnseenInherited=!1,this.nodeId=t,this.seeded=!0;const r=new Set(e.deliveries.map(a=>a.entry.entry_id)),n=this.buffer.filter(a=>!r.has(a.entry_id));for(const a of n)this.claims.delete(a.entry_id);if(this.buffer.splice(0,this.buffer.length,...this.buffer.filter(a=>r.has(a.entry_id))),n.length>0){const a=globalThis[Symbol.for("@crouton-kit/crtr:watcher-cancel-probe")];typeof a=="function"&&a(n.map(l=>l.entry_id),process.hrtime.bigint())}let d=!1;for(const a of e.deliveries){const l=a.entry.entry_id;this.claims.has(l)||(a.entry=V(a.entry),this.claims.set(l,a),a.handoff==="inherited"&&!i?m.fresh(o=>{this.pendingHandoffs.push({...x([a.entry],"visible"),operationId:o,settleAtAgentSettled:!0})}):(this.buffer.push(a.entry),this.lastArrival=Date.now(),d=!0))}return d&&this.armDebounce(),this.syncTimers(),!0}async tick(){const t=E();if(t!==void 0){if(this.pendingCommit!==void 0){await this.retryPendingCommit(t)==="refresh_held"&&this.canMutate()&&this.dispose("refresh",!1);return}this.promptJoinInFlight||P()||this.pendingHandoffs.length>=b||await this.claimMail(t)&&this.buffer.length>0&&(!this.runNode||this.isIdle()||this.buffer.some(e=>e.tier==="critical"))&&Date.now()-this.lastArrival>=this.cadence.debounceMs&&await this.flushOrdinary(t)}}missingChannelEntries(t){const e=t.filter(n=>this.claims.has(n.entry_id)),i=this.coveredEntryIds("hidden"),r=this.coveredEntryIds("visible");return{hiddenEntries:e.filter(n=>(n.data?.situational===!0||n.data?.situationalOnly===!0)&&!i.has(n.entry_id)),visibleEntries:e.filter(n=>n.data?.situationalOnly!==!0&&!r.has(n.entry_id))}}visibleRoute(t){return t.length===0?"none":this.isIdle()?"idle":this.runNode?t.some(e=>e.tier==="critical")?"critical":"none":t.some(e=>e.tier==="critical")?"critical":t.some(e=>e.tier==="urgent"||e.kind==="final")?"steer":"followUp"}buildPlan(t){const{hiddenEntries:e,visibleEntries:i}=this.missingChannelEntries(t),r=new Set(e.map(u=>u.entry_id)),n=new Set(i.map(u=>u.entry_id)),d=t.filter(u=>r.has(u.entry_id)||n.has(u.entry_id)),a=this.isIdle()&&d.length>0&&d.every(u=>u.tier==="deferred"),l=this.visibleRoute(i)==="critical",o=!a&&!l&&e.length>0,c=!a&&!l&&i.length>0;return{hiddenEntries:e,visibleEntries:i,deferredHold:a,sendCount:Number(o)+Number(c)}}ordinaryPlan(){return this.buildPlan(this.buffer)}async contextCards(t,e){const i=[];if(e.some(r=>r.data?.situational===!0)){const r=e.at(-1).entry_id;let n;try{n=(await F(t)).situational_card}catch(d){this.raiseSituationalFatal(r,d)}n===null&&this.raiseSituationalFatal(r,new Error(`missing situational context for entry ${r}`)),i.push(n)}for(const r of e)r.data?.situationalOnly===!0&&i.push(...j(r));return i}digest(t,e){try{return X(t)}catch(i){this.raiseReadFatal(e,i)}}sendDelivery(t,e,i,r,n){this.pendingHandoffs.length>=b&&this.raiseReadFatal(r,new Error(`pending handoff capacity exceeded before ${t} send`));let d;try{d=x(e,t)}catch(o){this.raiseReadFatal(r,o)}let a;try{m.fresh(o=>{a=o,v({level:"info",event:"inbox.delivery.started",operation_id:o,fields:y(d)}),i()})}catch(o){return a===void 0&&this.raiseReadFatal(r,o),T(a,d,"send",o),"failed"}a===void 0&&this.raiseReadFatal(r,new Error(`${t} delivery returned without an operation id`));const l={operationId:a,...d,...n===void 0?{}:{awaitingDequeue:n}};return this.canMutate()?(this.pendingHandoffs.push(l),"handed-off"):(this.disposed&&this.disposalReason!==void 0&&M(l,this.disposalReason),"inactive")}sendContext(t,e,i,r,n,d){const a=r==="steer"||r==="followUp"?r:this.isIdle()?void 0:"followUp",l=a===void 0||i.length===0?void 0:_(i.at(-1));return this.sendDelivery("hidden",e,()=>{this.runNode&&n&&this.pi.appendEntry("crtr-turn-input",{message_ids:e.map(o=>o.entry_id)}),i.forEach((o,c)=>{const u=n&&c===i.length-1;this.pi.sendMessage({customType:I,content:o,display:!0,details:{nodeId:t}},a!==void 0?{deliverAs:a}:u?{deliverAs:"followUp",triggerTurn:!0}:{})})},d,l)}sendVisible(t,e,i,r,n,d){return this.sendDelivery("visible",t,()=>{if(n!=="idle"&&n!=="steer"&&n!=="followUp")throw new Error(`visible send requested for non-send route ${n}`);for(const a of e)this.pi.sendMessage({customType:I,content:a,display:!0},n==="idle"?{}:{deliverAs:n});if(K(i,r),n==="idle"){const a=ne();if(a===void 0)throw new Error("broker idle-turn admission is unavailable");a(i,this.runNode?t.map(l=>l.entry_id):[])}else this.pi.sendUserMessage(i,{deliverAs:n})},d,n==="steer"||n==="followUp"?_(i):void 0)}abortCritical(){try{this.lastCtx?.abort?.()}catch{}}requeueFromBatch(t,e){if(e.size===0)return;const i=t.filter(d=>e.has(d.entry_id)),r=new Set(i.map(d=>d.entry_id)),n=this.buffer.filter(d=>!r.has(d.entry_id));this.buffer.splice(0,this.buffer.length,...i,...n)}async executePlan(t,e,i){const r=new Set,n=this.visibleRoute(e.visibleEntries);if(n==="critical"){if(this.abortCritical(),!this.canMutate())return{inactive:!0,requeueEntryIds:r};for(const o of e.visibleEntries)r.add(o.entry_id);for(const o of e.hiddenEntries)r.add(o.entry_id);return{inactive:!1,requeueEntryIds:r}}if(this.runNode&&n==="none")return{inactive:!1,requeueEntryIds:new Set([...e.hiddenEntries,...e.visibleEntries].map(o=>o.entry_id))};const d=e.visibleEntries.length>0?this.digest(e.visibleEntries,i):[],[a,...l]=d;for(const o of l)for(const c of o.entries)r.add(c.entry_id);if(e.hiddenEntries.length>0){const o=await this.contextCards(t,e.hiddenEntries),c=this.sendContext(t,e.hiddenEntries,o,n,a===void 0,i);if(c==="inactive")return{inactive:!0,requeueEntryIds:r};if(c==="failed")for(const u of e.hiddenEntries)r.add(u.entry_id)}if(!this.canMutate())return{inactive:!0,requeueEntryIds:r};if(a!==void 0){const o=this.sendVisible(a.entries,a.cards,a.text,oe(a),n,i);if(o==="inactive")return{inactive:!0,requeueEntryIds:r};if(o==="failed")for(const c of a.entries)r.add(c.entry_id);else a.kind==="human"&&(await Z(t,a.text).catch(()=>{}),ee(t,a.text))}return{inactive:!1,requeueEntryIds:r}}async flushOrdinary(t){if(this.buffer.length===0)return"empty";const e=this.ordinaryPlan();if(e.deferredHold)return"held";if(this.pendingHandoffs.length+e.sendCount>b)return"capacity-blocked";const i=[...this.buffer],r=await this.executePlan(t,e,"poll");return r.inactive||(this.buffer.splice(0,i.length),this.requeueFromBatch(i,r.requeueEntryIds)),"attempted"}async prependHeldDeferredInbox(t){if(!this.canMutate()||this.nodeId===void 0||P())return;const e=this.ordinaryPlan();if(!e.deferredHold)return;const i=e.visibleEntries.length===0?[]:this.digest(e.visibleEntries,"poll"),r=+(e.hiddenEntries.length>0)+i.length;if(this.pendingHandoffs.length+r>b)return;const n=[...this.buffer];this.promptJoinInFlight=!0;try{this.runNode&&this.pi.appendEntry("crtr-turn-input",{message_ids:[...e.hiddenEntries,...e.visibleEntries].map(d=>d.entry_id)}),e.hiddenEntries.length>0&&await this.sendPromptJoinDelivery(t,"hidden",e.hiddenEntries,await this.contextCards(this.nodeId,e.hiddenEntries));for(const d of i)await this.sendPromptJoinDelivery(t,"visible",d.entries,[...d.cards,d.text]);if(!this.canMutate())return;this.buffer.splice(0,n.length)}finally{this.promptJoinInFlight=!1}}async sendPromptJoinDelivery(t,e,i,r){let n;try{n=x(i,e)}catch(l){this.raiseReadFatal("poll",l)}let d;try{await m.fresh(async l=>{d=l,v({level:"info",event:"inbox.delivery.started",operation_id:l,fields:y(n)});for(const o of r)await t.sendCustomMessage({customType:I,content:o,display:!0})})}catch(l){throw d===void 0&&this.raiseReadFatal("poll",l),T(d,n,"send",l),l}d===void 0&&this.raiseReadFatal("poll",new Error(`${e} prompt-join delivery returned without an operation id`));const a={operationId:d,...n,settleAtAgentSettled:!0};if(!this.canMutate()){this.disposed&&this.disposalReason!==void 0&&M(a,this.disposalReason);return}this.pendingHandoffs.push(a)}coveredEntryIds(t){const e=new Set;for(const i of this.pendingHandoffs)if(i.channel===t)for(const r of i.entryIds)e.add(r);return e}retryPendingCommit(t){const e=this.pendingCommit;if(e===void 0)return Promise.resolve("settled");if(e.attempt!==void 0)return e.attempt;const i=this.attemptPendingCommit(t,e).finally(()=>{e.attempt===i&&(e.attempt=void 0)});return e.attempt=i,i}async attemptPendingCommit(t,e){let i=!1;try{const n=await z(t,e.receipts);if(n.action==="hold")return"refresh_held";for(const d of e.receipts){const a=n.results.find(l=>l.delivery_id===d.delivery_id);if(a?.outcome!==d.disposition&&a?.outcome!=="stale")throw new Error("daemon returned no terminal mail settlement outcome")}i=n.results.every(d=>d.outcome==="acknowledged")}catch(n){if(this.pendingCommit===e)for(const d of e.handoffs)T(d.operationId,d,"receipt_commit",n);return String(n?.message).startsWith("conversation_write_failed")&&(O({level:"error",event:"broker.exited",node_id:t,error:n,fields:{fault:"conversation_write_failed"}}),N()?.("conversation_write_failed",1)),"held"}if(this.pendingCommit!==e)return"settled";for(const n of e.entryIds)this.claims.delete(n);if(e.receipts.some(n=>n.disposition==="released")){const n=new Set(e.entryIds);this.buffer.splice(0,this.buffer.length,...this.buffer.filter(d=>!n.has(d.entry_id)))}this.pendingCommit=void 0;const r=this.detachPending(n=>n.entryIds.every(d=>!this.claims.has(d)));for(const n of r)i&&le(n);return"settled"}async settle(t,e,i,r=!1){if(i)try{if(e?.hasPendingMessages?.()===!0)return"held"}catch{}if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const n=Q(),d=!n&&this.pendingHandoffs.some(h=>h.awaitingDequeue!==void 0)&&await this.nodeRefreshing(t);if(this.pendingCommit!==void 0)return this.retryPendingCommit(t);const a=new Set(this.buffer.map(h=>h.entry_id)),l=new Set(d?this.pendingHandoffs.filter(h=>h.awaitingDequeue!==void 0).flatMap(h=>[...h.entryIds]):[]),o=this.pendingHandoffs.filter(h=>(r||h.settleAtAgentSettled!==!0)&&h.entryIds.every(g=>!l.has(g))),c=new Set(o.flatMap(h=>[...h.entryIds])),u=[...this.claims.keys()].filter(h=>n||c.has(h)&&!a.has(h));return u.length===0?"settled":(this.pendingCommit={handoffs:o,entryIds:u,receipts:u.map(h=>{const g=this.claims.get(h);return{delivery_id:g.delivery_id,attempts:g.attempts,disposition:n?"released":"acknowledged"}})},this.retryPendingCommit(t))}async nodeRefreshing(t){try{return(await F(t)).node.intent==="refresh"}catch{return!0}}detachPending(t){const e=[];for(let i=this.pendingHandoffs.length-1;i>=0;i-=1){const r=this.pendingHandoffs[i];t(r)&&e.push(...this.pendingHandoffs.splice(i,1))}return e.reverse(),e}}function me(s,t){p?.dispose("reload",!1);const e=new ce(s,t,++ae);p=e;const i=f(r=>e.prependHeldDeferredInbox(r),"promptJoin");globalThis[se]=i;try{e.start()}catch(r){throw e.dispose("reload",!1),r}return e}f(me,"installWatcher");function pe(s){const t=me(s,de());return()=>t.dispose("shutdown",!1)}f(pe,"registerCanvasInboxWatcher");var Oe=pe;export{Oe as default,pe as registerCanvasInboxWatcher};
@@ -7,6 +7,13 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
+ ## 0.3.572
11
+
12
+ `POST /v1/runs` works on a cloud role (a runtime started with `--role api` or `--role reconcile`). It answered `500 server_failure` because the role has no root launcher and the run start tried to prepare an app OS user and folder. Behavior on a person's Mac and on a hosted guest with a launcher is unchanged.
13
+
14
+ - A run whose profile points at a Blaxel environment is created dormant and started by the node-lifecycle lane through the Blaxel runner, with the prompt as its first turn, within about one lifecycle tick. `POST /v1/nodes` follows the same rule: it no longer fails `400 broker_launch_failed` for such a profile, and answers with the node frozen until the lane starts it.
15
+ - A provider call that returns a file result is refused `storage_unavailable` on a cloud role, which has no folder to put the file in.
16
+
10
17
  ## 0.3.562
11
18
 
12
19
  A cloud role's runtime (one with `CRTR_DIRECTORY_URL` and `CRTR_PUBLIC_API_URL` set) accepts a directory person bearer on its TCP listener: the caller acts as that person and reads only the nodes that person may read; schedules, charges, files and provider calls are refused `403 permission_error` to it. Any other listener still refuses a person bearer `401`, now with the code `person_bearer_not_supported` (was `person_bearer_not_supported_on_cloud_role`). A cloud role also answers `GET /v1/runtime/vendor-status` and `POST /v1/runtime/vendor-account-remove` for the person the directory's token names, and refuses a token that names no person `401`.