@north-light/cli 0.3.594 → 0.3.596

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 (32) hide show
  1. package/dist/api/client.js +3 -3
  2. package/dist/clients/attach/viewer.js +345 -345
  3. package/dist/commands/pkg/app-installs.js +2 -2
  4. package/dist/core/command-plugins/transport/http-plan.d.ts +4 -0
  5. package/dist/core/command-plugins/transport/http-plan.js +1 -1
  6. package/dist/core/io.js +4 -4
  7. package/dist/core/providers/call.js +1 -1
  8. package/dist/core/runs/initial-input.d.ts +15 -0
  9. package/dist/core/runs/initial-input.js +1 -0
  10. package/dist/core/runs/operations.js +5 -5
  11. package/dist/core/runtime/broker/model-adapter.d.ts +3 -3
  12. package/dist/core/runtime/broker/model-adapter.js +3 -3
  13. package/dist/core/runtime/broker/spilled-body.d.ts +2 -4
  14. package/dist/core/runtime/broker/spilled-body.js +1 -1
  15. package/dist/core/runtime/broker/turn-cause.d.ts +4 -0
  16. package/dist/core/runtime/broker/turn-cause.js +1 -1
  17. package/dist/core/runtime/headless-pi.d.ts +2 -0
  18. package/dist/core/runtime/headless-pi.js +1 -1
  19. package/dist/core/runtime/naming.d.ts +2 -2
  20. package/dist/core/runtime/naming.js +9 -9
  21. package/dist/core/runtime/recap.d.ts +1 -1
  22. package/dist/core/runtime/recap.js +4 -4
  23. package/dist/core/runtime/revive.js +2 -2
  24. package/dist/core/runtime/spawn.js +2 -2
  25. package/dist/pi-extensions/broker-local.d.ts +3 -1
  26. package/dist/pi-extensions/broker-local.js +1 -1
  27. package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
  28. package/dist/pi-extensions/canvas-recap.js +7 -7
  29. package/docs/ci-runner.md +5 -5
  30. package/package.json +2 -2
  31. package/packages/crouter-identity/package.json +1 -1
  32. package/runtime.lock.json +13 -13
@@ -1,2 +1,2 @@
1
- var x=Object.defineProperty;var a=(n,t)=>x(n,"name",{value:t,configurable:!0});import{ApiError as A}from"../../api/errors.js";import{envGrantee as E}from"../../shared/env.js";import{deriveNameFromUrl as C}from"../../core/git.js";import{notFound as u,usage as O,CrtrError as h}from"../../core/errors.js";import{nowIso as k}from"../../core/fs-utils.js";import{appRevisionOf as P,currentSnapshot as j,writeSettings as R}from"../../core/scoped-state/person-store.js";import{ExitCode as w}from"../../types.js";import{cliClient as y,rethrowAsCliError as m}from"../api-client.js";const v={name:"crouter-official-marketplace",url:"https://github.com/crouton-labs/crouter-official-marketplace.git"},c=a(()=>E()??"app:terminal","appId"),p=a(()=>j().apps[c()]??{plugins:{},marketplaces:{},revision:"absent"},"block");async function d(n){const t=c();await R(r=>{const i=r.apps[t],s=structuredClone({plugins:i?.plugins??{},marketplaces:i?.marketplaces??{}});return n(s),[{op:"app-plugins.replace",app:t,plugins:s.plugins,marketplaces:s.marketplaces,ifRevision:P(i)}]})}a(d,"change");async function $(n){return await b(n).catch(t=>m(t))}a($,"resolve");async function b(n){return await y().documents.reconcilePackages({plugins:n})}a(b,"resolveRaw");async function _(){return await y().documents.reconcilePackages().catch(n=>m(n))}a(_,"resolveAll");function f(n,t){const r={not_public:"installed without documents: the directory reads public marketplaces only",not_found:"installed without documents: the directory does not list it",directory_unreachable:"installed; its documents arrive on the next sync because the directory is unreachable"},i=(n.unavailable??[]).filter(e=>t===void 0||e.plugin===t).map(e=>`${e.plugin}: ${r[e.reason]}`),s=n.invalid.filter(e=>t===void 0||e.path.startsWith(`${t}/`)).map(e=>`${e.path.split("/")[0]}: ${e.path} was not published: ${e.error}`),l=(n.kinds?.refused??[]).filter(e=>t===void 0||e.plugin===t).map(e=>`${e.plugin}: kind ${e.kind} not registered: ${e.message}`);return[...i,...s,...l]}a(f,"unavailableWarnings");async function q(n){const t=n.split("/");if(t.length!==2||t[0]===""||t[1]==="")throw O(`invalid plugin install ref: ${n}
2
- A sandboxed node installs marketplace/plugin from a marketplace added with \`crtr pkg market add\`.`);const[r,i]=t,s=p();if(s.plugins[i]!==void 0)throw new h("conflict",`plugin "${i}" is already installed in ${c()}`,w.GENERAL);const l=s.marketplaces[r]??(r===v.name?{url:v.url,ref:"main",installed_at:k()}:void 0);if(l===void 0)throw u(`marketplace not found: ${r}`);await d(e=>{e.marketplaces[r]=l,e.plugins[i]={enabled:!0,source_marketplace:r}});try{const e=await b([i]),o=f(e,i);return{name:i,app:c(),...o.length>0?{warnings:o}:{}}}catch(e){if(!(e instanceof A)||e.code!=="name_taken"&&e.code!=="not_found")return m(e);throw await d(o=>{delete o.plugins[i],s.marketplaces[r]===void 0&&!Object.values(o.plugins).some(g=>g.source_marketplace===r)&&delete o.marketplaces[r]}),e.code==="not_found"?u(e.message):new h("conflict",`${e.message}; uninstall that marketplace's plugin or pick another`,w.GENERAL,{plugin:i})}}a(q,"installAppPlugin");async function z(n){if(p().plugins[n]===void 0)throw u(`plugin not found: ${n}`);return await d(t=>{delete t.plugins[n]}),{app:c()}}a(z,"removeAppPlugin");async function B(n,t){if(p().plugins[n]===void 0)throw u(`plugin not found: ${n}`);await d(i=>{i.plugins[n]={...i.plugins[n],enabled:t}});const r=t?f(await $([n]),n):[];return{name:n,app:c(),enabled:t,...r.length>0?{warnings:r}:{}}}a(B,"setAppPluginEnabled");async function D(n){const t=Object.keys(p().plugins);if(n!==void 0&&!t.includes(n))throw u(`plugin not found: ${n}`);const r=n===void 0?t:[n],i=r.length===0?void 0:n===void 0?await _():await $(r),s=a(l=>(i?.conflicts??[]).filter(e=>e.plugin===l).map(e=>`${l}: no documents: ${e.message}`),"conflicted");return{updated:r.map(l=>{const e=i===void 0?[]:[...s(l),...f(i,l)];return{name:l,...e.length>0?{warnings:e}:{}}})}}a(D,"updateAppPlugins");async function H(n){const t=Object.entries(p().plugins).filter(([,e])=>n||e.enabled!==!1).sort(([e],[o])=>e.localeCompare(o)),i=t.filter(([,e])=>e.enabled!==!1).map(([e])=>e).length===0?void 0:await _(),s=a(e=>{const o=i?.conflicts.find(g=>g.plugin===e);return o!==void 0?`no documents: ${o.message}`:i===void 0?void 0:f(i,e)[0]},"why"),l=t.map(([e,o])=>({name:e,scope:c(),enabled:o.enabled!==!1,...o.source_marketplace===void 0?{}:{source_marketplace:o.source_marketplace},...o.version===void 0?{}:{version:o.version},...s(e)===void 0?{}:{documents:s(e)}}));return{items:l,next_cursor:null,total:l.length}}a(H,"listAppPlugins");async function J(n,t){const r=C(n);return await d(i=>{i.marketplaces[r]={url:n,ref:t??"main",installed_at:k()}}),{name:r,app:c()}}a(J,"addAppMarketplace");function K(){const n=Object.entries(p().marketplaces).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,scope:c(),url:r.url,ref:r.ref}));return{items:n,next_cursor:null,total:n.length}}a(K,"listAppMarketplaces");async function Q(n){if(p().marketplaces[n]===void 0)throw u(`marketplace not found: ${n}`);return await d(t=>{delete t.marketplaces[n];for(const[r,i]of Object.entries(t.plugins))i.source_marketplace===n&&delete t.plugins[r]}),{app:c()}}a(Q,"removeAppMarketplace");export{J as addAppMarketplace,c as appId,q as installAppPlugin,K as listAppMarketplaces,H as listAppPlugins,Q as removeAppMarketplace,z as removeAppPlugin,B as setAppPluginEnabled,D as updateAppPlugins};
1
+ var x=Object.defineProperty;var i=(n,t)=>x(n,"name",{value:t,configurable:!0});import{ApiError as A}from"../../api/errors.js";import{envGrantee as E}from"../../shared/env.js";import{deriveNameFromUrl as C}from"../../core/git.js";import{notFound as u,usage as O,CrtrError as h}from"../../core/errors.js";import{nowIso as k}from"../../core/fs-utils.js";import{appRevisionOf as P,currentSnapshot as j,writeSettings as R}from"../../core/scoped-state/person-store.js";import{ExitCode as w}from"../../types.js";import{cliClient as y,rethrowAsCliError as m}from"../api-client.js";const b={name:"crouter-official-marketplace",url:"https://github.com/crouton-labs/crouter-official-marketplace.git"},c=i(()=>E()??"app:terminal","appId"),p=i(()=>j().apps[c()]??{plugins:{},marketplaces:{},revision:"absent"},"block");async function d(n){const t=c();await R(r=>{const a=r.apps[t],s=structuredClone({plugins:a?.plugins??{},marketplaces:a?.marketplaces??{}});return n(s),[{op:"app-plugins.replace",app:t,plugins:s.plugins,marketplaces:s.marketplaces,ifRevision:P(a)}]})}i(d,"change");async function v(n){return await $(n).catch(t=>m(t))}i(v,"resolve");async function $(n){return await y().documents.reconcilePackages({plugins:n})}i($,"resolveRaw");async function _(){return await y().documents.reconcilePackages().catch(n=>m(n))}i(_,"resolveAll");function f(n,t){const r={not_public:"installed without documents: the directory reads public marketplaces only",not_found:"installed without documents: the directory does not list it",directory_unreachable:"installed; the directory did not answer this check, so documents already published stay readable and any not yet published arrive on the next package sync"},a=(n.unavailable??[]).filter(e=>t===void 0||e.plugin===t).map(e=>`${e.plugin}: ${r[e.reason]}`),s=n.invalid.filter(e=>t===void 0||e.path.startsWith(`${t}/`)).map(e=>`${e.path.split("/")[0]}: ${e.path} was not published: ${e.error}`),l=(n.kinds?.refused??[]).filter(e=>t===void 0||e.plugin===t).map(e=>`${e.plugin}: kind ${e.kind} not registered: ${e.message}`);return[...a,...s,...l]}i(f,"unavailableWarnings");async function q(n){const t=n.split("/");if(t.length!==2||t[0]===""||t[1]==="")throw O(`invalid plugin install ref: ${n}
2
+ A sandboxed node installs marketplace/plugin from a marketplace added with \`crtr pkg market add\`.`);const[r,a]=t,s=p();if(s.plugins[a]!==void 0)throw new h("conflict",`plugin "${a}" is already installed in ${c()}`,w.GENERAL);const l=s.marketplaces[r]??(r===b.name?{url:b.url,ref:"main",installed_at:k()}:void 0);if(l===void 0)throw u(`marketplace not found: ${r}`);await d(e=>{e.marketplaces[r]=l,e.plugins[a]={enabled:!0,source_marketplace:r}});try{const e=await $([a]),o=f(e,a);return{name:a,app:c(),...o.length>0?{warnings:o}:{}}}catch(e){if(!(e instanceof A)||e.code!=="name_taken"&&e.code!=="not_found")return m(e);throw await d(o=>{delete o.plugins[a],s.marketplaces[r]===void 0&&!Object.values(o.plugins).some(g=>g.source_marketplace===r)&&delete o.marketplaces[r]}),e.code==="not_found"?u(e.message):new h("conflict",`${e.message}; uninstall that marketplace's plugin or pick another`,w.GENERAL,{plugin:a})}}i(q,"installAppPlugin");async function z(n){if(p().plugins[n]===void 0)throw u(`plugin not found: ${n}`);return await d(t=>{delete t.plugins[n]}),{app:c()}}i(z,"removeAppPlugin");async function B(n,t){if(p().plugins[n]===void 0)throw u(`plugin not found: ${n}`);await d(a=>{a.plugins[n]={...a.plugins[n],enabled:t}});const r=t?f(await v([n]),n):[];return{name:n,app:c(),enabled:t,...r.length>0?{warnings:r}:{}}}i(B,"setAppPluginEnabled");async function D(n){const t=Object.keys(p().plugins);if(n!==void 0&&!t.includes(n))throw u(`plugin not found: ${n}`);const r=n===void 0?t:[n],a=r.length===0?void 0:n===void 0?await _():await v(r),s=i(l=>(a?.conflicts??[]).filter(e=>e.plugin===l).map(e=>`${l}: no documents: ${e.message}`),"conflicted");return{updated:r.map(l=>{const e=a===void 0?[]:[...s(l),...f(a,l)];return{name:l,...e.length>0?{warnings:e}:{}}})}}i(D,"updateAppPlugins");async function H(n){const t=Object.entries(p().plugins).filter(([,e])=>n||e.enabled!==!1).sort(([e],[o])=>e.localeCompare(o)),a=t.filter(([,e])=>e.enabled!==!1).map(([e])=>e).length===0?void 0:await _(),s=i(e=>{const o=a?.conflicts.find(g=>g.plugin===e);return o!==void 0?`no documents: ${o.message}`:a===void 0?void 0:f(a,e)[0]},"why"),l=t.map(([e,o])=>({name:e,scope:c(),enabled:o.enabled!==!1,...o.source_marketplace===void 0?{}:{source_marketplace:o.source_marketplace},...o.version===void 0?{}:{version:o.version},...s(e)===void 0?{}:{documents:s(e)}}));return{items:l,next_cursor:null,total:l.length}}i(H,"listAppPlugins");async function J(n,t){const r=C(n);return await d(a=>{a.marketplaces[r]={url:n,ref:t??"main",installed_at:k()}}),{name:r,app:c()}}i(J,"addAppMarketplace");function K(){const n=Object.entries(p().marketplaces).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,scope:c(),url:r.url,ref:r.ref}));return{items:n,next_cursor:null,total:n.length}}i(K,"listAppMarketplaces");async function Q(n){if(p().marketplaces[n]===void 0)throw u(`marketplace not found: ${n}`);return await d(t=>{delete t.marketplaces[n];for(const[r,a]of Object.entries(t.plugins))a.source_marketplace===n&&delete t.plugins[r]}),{app:c()}}i(Q,"removeAppMarketplace");export{J as addAppMarketplace,c as appId,q as installAppPlugin,K as listAppMarketplaces,H as listAppPlugins,Q as removeAppMarketplace,z as removeAppPlugin,B as setAppPluginEnabled,D as updateAppPlugins};
@@ -47,6 +47,10 @@ export declare function buildRequestPlan(spec: HttpInvokerSpec, input: Record<st
47
47
  * Shared by the HTTP-plugin plan and the provider-leaf adapter, so every
48
48
  * transport ships file content and none ships the path string. */
49
49
  export declare function readPathParam(commandLabel: string, param: InputParam, value: unknown): unknown;
50
+ /** Convert an authored kebab param name to the camelCase key parseArgv emits.
51
+ * Must stay identical to command.ts's flagNameToKey so lookups + the presence
52
+ * set line up. */
53
+ export declare function paramKey(name: string): string;
50
54
  /** Map a unary 2xx body to the validated result object, or throw
51
55
  * cli_protocol_error (GENERAL) for bad JSON / a non-object / an output mismatch. */
52
56
  export declare function mapUnary2xx(spec: HttpInvokerSpec, body: string): Record<string, unknown>;
@@ -1 +1 @@
1
- var R=Object.defineProperty;var c=(e,t)=>R(e,"name",{value:t,configurable:!0});import{readFileSync as O,statSync as k}from"node:fs";import{resolve as j}from"node:path";import{validateDeclaredResult as C}from"../../../api/command-manifest/result.js";import{CrtrError as w}from"../../errors.js";import{envelopeClaimsStale as P,staleErrorDetails as z}from"../../manifest-stale.js";import{ExitCode as h}from"../../../types.js";import{isRecord as x}from"../../../shared/predicates.js";import{trimHeaderValue as U}from"./sign.js";import{outboundTraceparent as q}from"../../../shared/traceparent.js";const T=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,I=new Set(["internal","unknown_path","command_collision","cli_protocol_error"]),D=new Set(["authorization","crtr-request-id","crtr-run-id","crtr-approval","crtr-upload-id","crtr-upload-link","accept","content-type","crtr-caller","crtr-signature","traceparent"]),M=new Set(["crtr-caller","crtr-signature","crtr-request-id"]);function ne(e,t,r,n){const i=new Map;for(const o of e.params)i.set(o.name,o);const f=Object.entries(e.rest.params),u=e.baseUrl??new URL(e.registration.endpoint).origin;let y=e.rest.path;for(const[o,a]of f){if(a.in!=="path")continue;const s=t[b(o)];y=y.split(`{${o}}`).join(J(s))}const S=new URL(y,u);for(const[o,a]of f){if(a.in!=="query")continue;const s=b(o);v(i.get(o),s,t,r)&&S.searchParams.append(a.as??o,String(t[s]))}const m=G(e,f,i,t,r,n.fileMode),p=Object.keys(m).length>0?JSON.stringify(m):void 0,l={},d=c((o,a)=>{const s=Object.keys(l).find(g=>g.toLowerCase()===o.toLowerCase());s!==void 0&&delete l[s],l[o]=U(a)},"setHeader");d("Accept","application/json"),d("Crtr-Request-Id",n.requestId),n.authorization!==null&&d("Authorization",n.authorization);for(const[o,a]of f){if(a.in!=="header")continue;const s=b(o);if(!v(i.get(o),s,t,r))continue;const g=a.as;if(M.has(g.toLowerCase())||n.fileMode==="pass-through"&&D.has(g.toLowerCase()))throw new w("invalid_type",`${E(e)}: header "${g}" is reserved for the runtime`,h.USAGE,{field:o,next:"Remove the runtime-owned header mapping from the manifest."});const A=String(t[s]);if(/[\r\n]/.test(A))throw new w("invalid_type",`${E(e)}: header "${g}" value must not contain a newline`,h.USAGE,{field:o,received:"(newline in header value)",next:"Remove newline characters from the value."});d(g,A)}p!==void 0&&d("Content-Type","application/json");for(const[o,a]of Object.entries(n.extraHeaders)){if(n.fileMode==="pass-through"&&/[\r\n]/.test(a))throw new w("invalid_type",`${E(e)}: header "${o}" value must not contain a newline`,h.USAGE);d(o,a)}if(n.fileMode==="pass-through"){if(d("Accept","application/json"),p!==void 0)d("Content-Type","application/json");else{const o=Object.keys(l).find(a=>a.toLowerCase()==="content-type");o!==void 0&&delete l[o]}if(d("Crtr-Request-Id",n.requestId),n.traceId!==void 0&&d("traceparent",q(n.traceId)),n.authorization!==null)d("Authorization",n.authorization);else{const o=Object.keys(l).find(a=>a.toLowerCase()==="authorization");o!==void 0&&delete l[o]}}return{url:S,method:e.rest.method,headers:l,...p!==void 0?{body:p}:{}}}c(ne,"buildRequestPlan");function G(e,t,r,n,i,f){const u=new Map;for(const[m,p]of t){if(p.in!=="body")continue;const l=p.as??m,d=u.get(l);d!==void 0?d.push(m):u.set(l,[m])}const y={};for(const[m,p]of u){const l=p.map(s=>({name:s,param:r.get(s)})),d=l.find(s=>s.param.kind!=="stdin"),o=l.find(s=>s.param.kind==="stdin");let a;d!==void 0&&v(d.param,b(d.name),n,i)?a={param:d.param,value:n[b(d.name)]}:o!==void 0&&v(o.param,b(o.name),n,i)&&(a={param:o.param,value:n[b(o.name)]}),a!==void 0&&(y[m]=H(e,a.param,a.value,f))}const S={...e.rest.body};return e.rest.bodyRoot!==void 0?S[e.rest.bodyRoot]=y:Object.assign(S,y),S}c(G,"assembleBody");function H(e,t,r,n){return n==="pass-through"||t.kind==="context-file"?r:(t.kind==="positional"||t.kind==="flag")&&t.type==="path"?N(E(e),t,r):r}c(H,"materializeBodyValue");function N(e,t,r){if(Array.isArray(r))return r.map(u=>N(e,t,u));const n=String(r),i=j(process.cwd(),n);let f;try{f=k(i)}catch{throw _(e,t.name,n,"no file exists at that path","an existing local file path")}if(!f.isFile())throw _(e,t.name,n,"the path is not a regular file","a regular local file (not a directory, socket, or device)");try{return"encoding"in t&&t.encoding==="base64"?O(i).toString("base64"):O(i,"utf8")}catch{throw _(e,t.name,n,"the file could not be read","a readable local file path")}}c(N,"readPathParam");function _(e,t,r,n,i){return new w("invalid_type",`${e}: cannot read file for "${t}" \u2014 ${n}: ${r}`,h.USAGE,{field:t,received:r,next:`Pass ${i}, relative to the current directory or absolute.`})}c(_,"fileError");function v(e,t,r,n){return n!==void 0?n.providedParams.has(t):Object.prototype.hasOwnProperty.call(r,t)&&r[t]!==void 0}c(v,"isPresent");function J(e){const t=String(e);return t==="."||t===".."?t.replace(/\./g,"%2E"):encodeURIComponent(t)}c(J,"encodePathSegmentValue");function b(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}c(b,"paramKey");function oe(e,t){let r;try{r=JSON.parse(t)}catch{throw $(e,"response body was not valid JSON","a JSON object matching the declared output")}if(!x(r))throw $(e,`response body was not a JSON object (got ${B(r)})`,"a JSON object matching the declared output");const n=C(e.output,r);if(n!==null){const f=e.output.find(u=>u.name===n.field)?.type??"unknown";throw n.receivedType!==void 0?$(e,`output field "${n.field}" has the wrong type`,`${n.field}: ${n.expected??f}`):$(e,`response is missing required output field "${n.field}"`,`a "${n.field}" field of type ${f}`)}return r}c(oe,"mapUnary2xx");function ie(e,t,r){const n=V(t),i=L(r);if(i!==null){const f=T.test(i.code)&&!I.has(i.code);throw new w(f?i.code:"cli_protocol_error",i.message,n,{...i.received!==void 0?{received:i.received}:{},...i.field!==void 0?{field:i.field}:{},...i.manifestStale?z(e.registration.name):{},http_status:t,next:i.next??"Inspect the backend response, then retry if appropriate."})}throw new w("cli_http_error",`${E(e)}: request failed with HTTP ${t}`,n,{http_status:t,next:"Inspect the backend response, then retry if appropriate."})}c(ie,"throwNon2xx");function L(e){let t;try{t=JSON.parse(e)}catch{return null}if(!x(t)||!x(t.error))return null;const r=t.error;return typeof r.code!="string"||typeof r.message!="string"?null:{code:r.code,message:r.message,...typeof r.field=="string"?{field:r.field}:{},...r.received!==void 0?{received:r.received}:{},...typeof r.next=="string"?{next:r.next}:{},manifestStale:P(r),...r.question!==void 0?{question:r.question}:{}}}c(L,"parseHttpError");function V(e){return e===400||e===401||e===403||e===422?h.USAGE:e===404?h.NOT_FOUND:e===409?h.AMBIGUOUS:h.GENERAL}c(V,"deriveExit");function $(e,t,r){return new w("cli_protocol_error",`${E(e)}: ${t}. Expected ${r}.`,h.GENERAL,{received:t,next:`Run \`crtr pkg plugin update ${e.registration.name}\` or inspect the backend response.`})}c($,"protocolError");function E(e){return`HTTP-transport plugin "${e.registration.name}" command \`${e.commandPath.join(" ")}\``}c(E,"label");function B(e){return e===null?"null":Array.isArray(e)?"array":typeof e}c(B,"typeName");export{ne as buildRequestPlan,oe as mapUnary2xx,L as parseHttpError,N as readPathParam,ie as throwNon2xx};
1
+ var R=Object.defineProperty;var c=(e,t)=>R(e,"name",{value:t,configurable:!0});import{readFileSync as O,statSync as k}from"node:fs";import{resolve as j}from"node:path";import{validateDeclaredResult as C}from"../../../api/command-manifest/result.js";import{CrtrError as w}from"../../errors.js";import{envelopeClaimsStale as P,staleErrorDetails as z}from"../../manifest-stale.js";import{ExitCode as h}from"../../../types.js";import{isRecord as x}from"../../../shared/predicates.js";import{trimHeaderValue as U}from"./sign.js";import{outboundTraceparent as q}from"../../../shared/traceparent.js";const T=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,I=new Set(["internal","unknown_path","command_collision","cli_protocol_error"]),D=new Set(["authorization","crtr-request-id","crtr-run-id","crtr-approval","crtr-upload-id","crtr-upload-link","accept","content-type","crtr-caller","crtr-signature","traceparent"]),M=new Set(["crtr-caller","crtr-signature","crtr-request-id"]);function ne(e,t,r,n){const i=new Map;for(const o of e.params)i.set(o.name,o);const f=Object.entries(e.rest.params),u=e.baseUrl??new URL(e.registration.endpoint).origin;let y=e.rest.path;for(const[o,a]of f){if(a.in!=="path")continue;const s=t[b(o)];y=y.split(`{${o}}`).join(J(s))}const S=new URL(y,u);for(const[o,a]of f){if(a.in!=="query")continue;const s=b(o);v(i.get(o),s,t,r)&&S.searchParams.append(a.as??o,String(t[s]))}const m=G(e,f,i,t,r,n.fileMode),p=Object.keys(m).length>0?JSON.stringify(m):void 0,l={},d=c((o,a)=>{const s=Object.keys(l).find(g=>g.toLowerCase()===o.toLowerCase());s!==void 0&&delete l[s],l[o]=U(a)},"setHeader");d("Accept","application/json"),d("Crtr-Request-Id",n.requestId),n.authorization!==null&&d("Authorization",n.authorization);for(const[o,a]of f){if(a.in!=="header")continue;const s=b(o);if(!v(i.get(o),s,t,r))continue;const g=a.as;if(M.has(g.toLowerCase())||n.fileMode==="pass-through"&&D.has(g.toLowerCase()))throw new w("invalid_type",`${E(e)}: header "${g}" is reserved for the runtime`,h.USAGE,{field:o,next:"Remove the runtime-owned header mapping from the manifest."});const A=String(t[s]);if(/[\r\n]/.test(A))throw new w("invalid_type",`${E(e)}: header "${g}" value must not contain a newline`,h.USAGE,{field:o,received:"(newline in header value)",next:"Remove newline characters from the value."});d(g,A)}p!==void 0&&d("Content-Type","application/json");for(const[o,a]of Object.entries(n.extraHeaders)){if(n.fileMode==="pass-through"&&/[\r\n]/.test(a))throw new w("invalid_type",`${E(e)}: header "${o}" value must not contain a newline`,h.USAGE);d(o,a)}if(n.fileMode==="pass-through"){if(d("Accept","application/json"),p!==void 0)d("Content-Type","application/json");else{const o=Object.keys(l).find(a=>a.toLowerCase()==="content-type");o!==void 0&&delete l[o]}if(d("Crtr-Request-Id",n.requestId),n.traceId!==void 0&&d("traceparent",q(n.traceId)),n.authorization!==null)d("Authorization",n.authorization);else{const o=Object.keys(l).find(a=>a.toLowerCase()==="authorization");o!==void 0&&delete l[o]}}return{url:S,method:e.rest.method,headers:l,...p!==void 0?{body:p}:{}}}c(ne,"buildRequestPlan");function G(e,t,r,n,i,f){const u=new Map;for(const[m,p]of t){if(p.in!=="body")continue;const l=p.as??m,d=u.get(l);d!==void 0?d.push(m):u.set(l,[m])}const y={};for(const[m,p]of u){const l=p.map(s=>({name:s,param:r.get(s)})),d=l.find(s=>s.param.kind!=="stdin"),o=l.find(s=>s.param.kind==="stdin");let a;d!==void 0&&v(d.param,b(d.name),n,i)?a={param:d.param,value:n[b(d.name)]}:o!==void 0&&v(o.param,b(o.name),n,i)&&(a={param:o.param,value:n[b(o.name)]}),a!==void 0&&(y[m]=H(e,a.param,a.value,f))}const S={...e.rest.body};return e.rest.bodyRoot!==void 0?S[e.rest.bodyRoot]=y:Object.assign(S,y),S}c(G,"assembleBody");function H(e,t,r,n){return n==="pass-through"||t.kind==="context-file"?r:(t.kind==="positional"||t.kind==="flag")&&t.type==="path"?N(E(e),t,r):r}c(H,"materializeBodyValue");function N(e,t,r){if(Array.isArray(r))return r.map(u=>N(e,t,u));const n=String(r),i=j(process.cwd(),n);let f;try{f=k(i)}catch{throw _(e,t.name,n,"no file exists at that path","an existing local file path")}if(!f.isFile())throw _(e,t.name,n,"the path is not a regular file","a regular local file (not a directory, socket, or device)");try{return"encoding"in t&&t.encoding==="base64"?O(i).toString("base64"):O(i,"utf8")}catch{throw _(e,t.name,n,"the file could not be read","a readable local file path")}}c(N,"readPathParam");function _(e,t,r,n,i){return new w("invalid_type",`${e}: cannot read file for "${t}" \u2014 ${n}: ${r}`,h.USAGE,{field:t,received:r,next:`Pass ${i}, relative to the current directory or absolute.`})}c(_,"fileError");function v(e,t,r,n){return n!==void 0?n.providedParams.has(t):Object.prototype.hasOwnProperty.call(r,t)&&r[t]!==void 0}c(v,"isPresent");function J(e){const t=String(e);return t==="."||t===".."?t.replace(/\./g,"%2E"):encodeURIComponent(t)}c(J,"encodePathSegmentValue");function b(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}c(b,"paramKey");function oe(e,t){let r;try{r=JSON.parse(t)}catch{throw $(e,"response body was not valid JSON","a JSON object matching the declared output")}if(!x(r))throw $(e,`response body was not a JSON object (got ${B(r)})`,"a JSON object matching the declared output");const n=C(e.output,r);if(n!==null){const f=e.output.find(u=>u.name===n.field)?.type??"unknown";throw n.receivedType!==void 0?$(e,`output field "${n.field}" has the wrong type`,`${n.field}: ${n.expected??f}`):$(e,`response is missing required output field "${n.field}"`,`a "${n.field}" field of type ${f}`)}return r}c(oe,"mapUnary2xx");function ie(e,t,r){const n=V(t),i=L(r);if(i!==null){const f=T.test(i.code)&&!I.has(i.code);throw new w(f?i.code:"cli_protocol_error",i.message,n,{...i.received!==void 0?{received:i.received}:{},...i.field!==void 0?{field:i.field}:{},...i.manifestStale?z(e.registration.name):{},http_status:t,next:i.next??"Inspect the backend response, then retry if appropriate."})}throw new w("cli_http_error",`${E(e)}: request failed with HTTP ${t}`,n,{http_status:t,next:"Inspect the backend response, then retry if appropriate."})}c(ie,"throwNon2xx");function L(e){let t;try{t=JSON.parse(e)}catch{return null}if(!x(t)||!x(t.error))return null;const r=t.error;return typeof r.code!="string"||typeof r.message!="string"?null:{code:r.code,message:r.message,...typeof r.field=="string"?{field:r.field}:{},...r.received!==void 0?{received:r.received}:{},...typeof r.next=="string"?{next:r.next}:{},manifestStale:P(r),...r.question!==void 0?{question:r.question}:{}}}c(L,"parseHttpError");function V(e){return e===400||e===401||e===403||e===422?h.USAGE:e===404?h.NOT_FOUND:e===409?h.AMBIGUOUS:h.GENERAL}c(V,"deriveExit");function $(e,t,r){return new w("cli_protocol_error",`${E(e)}: ${t}. Expected ${r}.`,h.GENERAL,{received:t,next:`Run \`crtr pkg plugin update ${e.registration.name}\` or inspect the backend response.`})}c($,"protocolError");function E(e){return`HTTP-transport plugin "${e.registration.name}" command \`${e.commandPath.join(" ")}\``}c(E,"label");function B(e){return e===null?"null":Array.isArray(e)?"array":typeof e}c(B,"typeName");export{ne as buildRequestPlan,oe as mapUnary2xx,b as paramKey,L as parseHttpError,N as readPathParam,ie as throwNon2xx};
package/dist/core/io.js CHANGED
@@ -1,7 +1,7 @@
1
- var _=Object.defineProperty;var i=(e,t)=>_(e,"name",{value:t,configurable:!0});import{appendFileSync as b,statSync as w}from"node:fs";import{CrtrError as c}from"./errors.js";import{ExitCode as a}from"../types.js";import{PREVIEW_RESULT_PATH_ENV as h}from"./preview-result-path.js";import{renderError as A}from"./render.js";import{ApiError as E}from"../api/index.js";let p=!1,f;const v=256*1024;function q(e){const t=process.env[h];f=t===void 0||t===""?void 0:{path:e,jsonl:[]}}i(q,"beginPreview");function y(e){const t=process.env[h];if(t===void 0||t==="")return;const s=`${JSON.stringify({path:f?.path??"",...e})}
2
- `;try{if((w(t,{throwIfNoEntry:!1})?.size??0)+Buffer.byteLength(s,"utf8")>v)return;b(t,s,"utf8")}catch{}}i(y,"publishPreview");function B(e){f!==void 0&&(e!=null?y({result:e}):(f.jsonl.length>0||f.error!==void 0)&&y({...f.jsonl.length>0?{jsonl:f.jsonl}:{},...f.error===void 0?{}:{error:f.error}}))}i(B,"publishPreviewResult");function g(e){f?.jsonl.push(e)}i(g,"recordPreviewLine");function G(e){try{const t=JSON.parse(e);t!==null&&typeof t=="object"&&!Array.isArray(t)&&g(t)}catch{}}i(G,"recordPreviewJsonLine");function K(e){f!==void 0&&(f.error=e)}i(K,"recordPreviewError");function F(e){p=e}i(F,"setJsonOutput");function z(){return p}i(z,"isJsonOutput");class m extends c{static{i(this,"InputError")}payload;constructor(t,s=a.USAGE){super(t.error,t.message,s,{...t}),this.name="InputError",this.payload=t}}async function D(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}i(D,"readStdinRaw");async function V(e=200){return process.stdin.isTTY?"":await new Promise(t=>{const s=[];let n=!1;const r=i(()=>{n||(n=!0,clearTimeout(u),process.stdin.removeListener("data",o),process.stdin.removeListener("end",l),process.stdin.removeListener("error",d),process.stdin.pause(),t(Buffer.concat(s).toString("utf8")))},"finish"),o=i(x=>s.push(x),"onData"),l=i(()=>r(),"onEnd"),d=i(()=>r(),"onError"),u=setTimeout(r,e);process.stdin.on("data",o),process.stdin.on("end",l),process.stdin.on("error",d),process.stdin.resume()})}i(V,"peekStdinRaw");function Y(e){process.stdout.write(JSON.stringify(e,null,2)+`
1
+ var b=Object.defineProperty;var i=(e,t)=>b(e,"name",{value:t,configurable:!0});import{appendFileSync as _,statSync as w}from"node:fs";import{CrtrError as c}from"./errors.js";import{ExitCode as a}from"../types.js";import{PREVIEW_RESULT_PATH_ENV as h}from"./preview-result-path.js";import{renderError as A}from"./render.js";import{ApiError as E}from"../api/index.js";let p=!1,f;const T=256*1024;function q(e){const t=process.env[h];f=t===void 0||t===""?void 0:{path:e,jsonl:[]}}i(q,"beginPreview");function y(e){const t=process.env[h];if(t===void 0||t==="")return;const s=`${JSON.stringify({path:f?.path??"",...e})}
2
+ `;try{if((w(t,{throwIfNoEntry:!1})?.size??0)+Buffer.byteLength(s,"utf8")>T)return;_(t,s,"utf8")}catch{}}i(y,"publishPreview");function B(e){f!==void 0&&(e!=null?y({result:e}):(f.jsonl.length>0||f.error!==void 0)&&y({...f.jsonl.length>0?{jsonl:f.jsonl}:{},...f.error===void 0?{}:{error:f.error}}))}i(B,"publishPreviewResult");function g(e){f?.jsonl.push(e)}i(g,"recordPreviewLine");function G(e){try{const t=JSON.parse(e);t!==null&&typeof t=="object"&&!Array.isArray(t)&&g(t)}catch{}}i(G,"recordPreviewJsonLine");function K(e){f!==void 0&&(f.error=e)}i(K,"recordPreviewError");function F(e){p=e}i(F,"setJsonOutput");function z(){return p}i(z,"isJsonOutput");class m extends c{static{i(this,"InputError")}payload;constructor(t,s=a.USAGE){super(t.error,t.message,s,{...t}),this.name="InputError",this.payload=t}}async function D(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}i(D,"readStdinRaw");async function V(e=200){return process.stdin.isTTY?"":await new Promise(t=>{const s=[];let n=!1;const r=i(()=>{n||(n=!0,clearTimeout(u),process.stdin.removeListener("data",o),process.stdin.removeListener("end",l),process.stdin.removeListener("error",d),process.stdin.pause(),t(Buffer.concat(s).toString("utf8")))},"finish"),o=i(x=>s.push(x),"onData"),l=i(()=>r(),"onEnd"),d=i(()=>r(),"onError"),u=setTimeout(r,e);process.stdin.on("data",o),process.stdin.on("end",l),process.stdin.on("error",d),process.stdin.resume()})}i(V,"peekStdinRaw");function Y(e){process.stdout.write(JSON.stringify(e,null,2)+`
3
3
  `)}i(Y,"emit");function H(e){g(e),process.stdout.write(JSON.stringify(e)+`
4
4
  `)}i(H,"emitLine");function M(e){return new Promise(t=>{let s=!1;const n=i(o=>{o.code==="EPIPE"&&r(!1)},"onErr"),r=i(o=>{s||(s=!0,process.stdout.off("error",n),t(o))},"finish");process.stdout.on("error",n);try{process.stdout.write(e,o=>r(o==null))}catch{r(!1)}})}i(M,"writeStdout");function X(e){process.stderr.write(e+`
5
- `)}i(X,"diag");function S(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}i(S,"isRecord");function T(e){if(e instanceof m)return e.payload;const t=e.details!==void 0?e.details:{},s=t.primaryCompleted===!0&&t.result!==null&&typeof t.result=="object"&&!Array.isArray(t.result)?O(t.result):void 0,n=t.next!==void 0?t.next:"Inspect the error and adjust the call. See -h for the schema.",r={error:e.code,message:e.message,received:t.received,field:t.field,...typeof t.http_status=="number"?{http_status:t.http_status}:{},...typeof t.retry_after_s=="number"?{retry_after_s:t.retry_after_s}:{},...S(t.details)?{details:t.details}:{}};return s===void 0?{...r,next:n}:{...r,primaryCompleted:!0,result:s,next:n}}i(T,"payloadOf");function O(e){const t=new WeakSet;try{const s=JSON.stringify(e,(n,r)=>{if(typeof r=="bigint")return{$crtrType:"bigint",value:r.toString()};if(typeof r=="number"&&!Number.isFinite(r))return{$crtrType:"number",value:String(r)};if(typeof r>"u"||typeof r=="function"||typeof r=="symbol")return{$crtrType:typeof r};if(r!==null&&typeof r=="object"){if(t.has(r))return{$crtrType:"circular"};t.add(r)}return r});if(s!==void 0){const n=JSON.parse(s);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}}catch{}return{$crtrType:"unavailable",message:"The completed primary result could not be represented as JSON."}}i(O,"jsonSafeResult");const N={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"};function R(e,t,s={}){if(e.code==="daemon_restarting")return new c("daemon_restarting",e.message,a.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(e.code==="layout_migration_required")return new c("layout_migration_required",e.message,a.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(e.code==="daemon_unavailable")return new c("daemon_unavailable",e.message,a.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(e.code==="northlight_unreachable"){const d=e.details?.next;return new c("northlight_unreachable",e.message,a.NETWORK,{next:typeof d=="string"&&d!==""?d:"Check this computer's internet connection, then retry."})}if(e.code==="model_sign_in_required"){const d=e.details?.url;return new m({error:e.code,message:e.message,next:typeof d=="string"?`Ask the person to sign in at ${d}, then retry.`:"Ask the person to sign in to an AI subscription on their Northlight account, then retry.",...typeof d=="string"?{details:{url:d}}:{}},a.USAGE)}const n=e.details,r=$(e,n,s.providerCall===!0);if(e.status===503||s.providerCall===!0&&e.status===504&&r.code!==void 0){const d=r.code??e.code,u={next:r.next??t??"Retry the command; if it persists, inspect the unavailable service named in the error."};return r.details!==void 0&&(u.details=r.details),r.code!==void 0&&(r.field!==void 0&&(u.field=r.field),r.received!==void 0&&(u.received=r.received),r.retryAfterS!==void 0&&(u.retry_after_s=r.retryAfterS)),new c(d,e.message,a.NETWORK,u)}const o=Array.isArray(n?.violations)?n.violations.map(d=>`${String(d.field)} ${String(d.problem)}${d.received!==void 0?` (received ${JSON.stringify(d.received)})`:""}`):[],l=n&&typeof n.error=="string"&&typeof n.message=="string"&&typeof n.next=="string"?n:{error:r.code??N[e.status]??e.code,...r.field!==void 0?{field:r.field}:{},...r.received!==void 0?{received:r.received}:{},...r.retryAfterS!==void 0?{retry_after_s:r.retryAfterS}:{},...r.details!==void 0?{details:r.details}:{},message:o.length>0?`${e.message}: ${o.join("; ")}`:e.message.trim()!==""?e.message:`request refused (HTTP ${e.status}, ${e.code}) with no message`,next:r.next??t??(r.retryAfterS!==void 0?`Wait ${r.retryAfterS}s, then retry; do not retry sooner.`:e.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":e.status===404&&r.code===void 0?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new m(l,j(l.error,e.status))}i(R,"apiErrorToCliError");function $(e,t,s){const n=i(o=>typeof o=="string"&&/^[a-z][a-z0-9_]*$/.test(o),"snake");if(s&&e.origin!==void 0&&e.origin!=="provider"&&n(e.code)){const o={code:e.code};return(e.status===503||e.status===504)&&(o.next=e.retryable===!0?"Retry the command; if it persists, the machine or service named in the error is unavailable.":"Read the error before retrying: the action may already have run."),S(e.details)&&(o.details=e.details),e.param!==void 0&&(o.field=e.param),typeof e.retryAfterS=="number"&&(o.retryAfterS=e.retryAfterS),o}if(e.origin!=="provider"||t===void 0||t===null||typeof t!="object")return{};const r={};return typeof t.status=="number"&&n(t.code)&&(r.code=t.code),typeof t.next=="string"&&t.next.trim()!==""&&(r.next=t.next),typeof t.field=="string"&&t.field!==""?r.field=t.field:e.param!==void 0&&(r.field=e.param),t.received!==void 0&&t.received!==null&&(r.received=t.received),typeof e.retryAfterS=="number"&&(r.retryAfterS=e.retryAfterS),r}i($,"providerSupplied");function j(e,t){return e==="not_found"||t===404?a.NOT_FOUND:e==="ambiguous"?a.AMBIGUOUS:a.USAGE}i(j,"exitForCliCode");function P(e){if(e instanceof E){P(R(e));return}if(e instanceof c){const n=T(e);f!==void 0&&y({error:n});const r=p?JSON.stringify(n,null,2):A(n);process.stdout.write(r+`
5
+ `)}i(X,"diag");function S(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}i(S,"isRecord");function v(e){if(e instanceof m)return e.payload;const t=e.details!==void 0?e.details:{},s=t.primaryCompleted===!0&&t.result!==null&&typeof t.result=="object"&&!Array.isArray(t.result)?O(t.result):void 0,n=t.next!==void 0?t.next:"Inspect the error and adjust the call. See -h for the schema.",r={error:e.code,message:e.message,received:t.received,field:t.field,...typeof t.http_status=="number"?{http_status:t.http_status}:{},...typeof t.retry_after_s=="number"?{retry_after_s:t.retry_after_s}:{},...S(t.details)?{details:t.details}:{}};return s===void 0?{...r,next:n}:{...r,primaryCompleted:!0,result:s,next:n}}i(v,"payloadOf");function O(e){const t=new WeakSet;try{const s=JSON.stringify(e,(n,r)=>{if(typeof r=="bigint")return{$crtrType:"bigint",value:r.toString()};if(typeof r=="number"&&!Number.isFinite(r))return{$crtrType:"number",value:String(r)};if(typeof r>"u"||typeof r=="function"||typeof r=="symbol")return{$crtrType:typeof r};if(r!==null&&typeof r=="object"){if(t.has(r))return{$crtrType:"circular"};t.add(r)}return r});if(s!==void 0){const n=JSON.parse(s);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}}catch{}return{$crtrType:"unavailable",message:"The completed primary result could not be represented as JSON."}}i(O,"jsonSafeResult");const N={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"};function R(e,t,s={}){if(e.code==="daemon_restarting")return new c("daemon_restarting",e.message,a.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(e.code==="layout_migration_required")return new c("layout_migration_required",e.message,a.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(e.code==="daemon_unavailable")return new c("daemon_unavailable",e.message,a.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(e.code==="northlight_unreachable"){const d=e.details?.next;return new c("northlight_unreachable",e.message,a.NETWORK,{next:typeof d=="string"&&d!==""?d:"Check this computer's internet connection, then retry."})}if(e.code==="model_sign_in_required"){const d=e.details?.url;return new m({error:e.code,message:e.message,next:typeof d=="string"?`Ask the person to sign in at ${d}, then retry.`:"Ask the person to sign in to an AI subscription on their Northlight account, then retry.",...typeof d=="string"?{details:{url:d}}:{}},a.USAGE)}const n=e.details,r=$(e,n,s.providerCall===!0);if(e.status===503||s.providerCall===!0&&e.status===504&&r.code!==void 0){const d=r.code??e.code,u={next:r.next??t??"Retry the command; if it persists, inspect the unavailable service named in the error."};return r.details!==void 0&&(u.details=r.details),r.code!==void 0&&(r.field!==void 0&&(u.field=r.field),r.received!==void 0&&(u.received=r.received),r.retryAfterS!==void 0&&(u.retry_after_s=r.retryAfterS)),new c(d,e.message,a.NETWORK,u)}const o=Array.isArray(n?.violations)?n.violations.map(d=>`${String(d.field)} ${String(d.problem)}${d.received!==void 0?` (received ${JSON.stringify(d.received)})`:""}`):[],l=n&&typeof n.error=="string"&&typeof n.message=="string"&&typeof n.next=="string"?n:{error:r.code??N[e.status]??e.code,...r.field!==void 0?{field:r.field}:{},...r.received!==void 0?{received:r.received}:{},...r.retryAfterS!==void 0?{retry_after_s:r.retryAfterS}:{},...r.details!==void 0?{details:r.details}:{},message:o.length>0?`${e.message}: ${o.join("; ")}`:e.message.trim()!==""?e.message:`request refused (HTTP ${e.status}, ${e.code}) with no message`,next:r.next??(n?.outcome==="unknown"?"The change may already be applied: check the current state before repeating it, and do not report it failed.":void 0)??t??(r.retryAfterS!==void 0?`Wait ${r.retryAfterS}s, then retry; do not retry sooner.`:e.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":e.status===404&&r.code===void 0?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new m(l,j(l.error,e.status))}i(R,"apiErrorToCliError");function $(e,t,s){const n=i(o=>typeof o=="string"&&/^[a-z][a-z0-9_]*$/.test(o),"snake");if(s&&e.origin!==void 0&&e.origin!=="provider"&&n(e.code)){const o={code:e.code};return(e.status===503||e.status===504)&&(o.next=e.retryable===!0?"Retry the command; if it persists, the machine or service named in the error is unavailable.":"Read the error before retrying: the action may already have run."),S(e.details)&&(o.details=e.details),e.param!==void 0&&(o.field=e.param),typeof e.retryAfterS=="number"&&(o.retryAfterS=e.retryAfterS),o}if(e.origin!=="provider"||t===void 0||t===null||typeof t!="object")return{};const r={};return typeof t.status=="number"&&n(t.code)&&(r.code=t.code),typeof t.next=="string"&&t.next.trim()!==""&&(r.next=t.next),typeof t.field=="string"&&t.field!==""?r.field=t.field:e.param!==void 0&&(r.field=e.param),t.received!==void 0&&t.received!==null&&(r.received=t.received),typeof e.retryAfterS=="number"&&(r.retryAfterS=e.retryAfterS),r}i($,"providerSupplied");function j(e,t){return e==="not_found"||t===404?a.NOT_FOUND:e==="ambiguous"?a.AMBIGUOUS:a.USAGE}i(j,"exitForCliCode");function P(e){if(e instanceof E){P(R(e));return}if(e instanceof c){const n=v(e);f!==void 0&&y({error:n});const r=p?JSON.stringify(n,null,2):A(n);process.stdout.write(r+`
6
6
  `),process.exitCode=e.exitCode;return}const t=e,s=t!=null&&typeof t.message=="string"?t.message:String(e);process.stderr.write(JSON.stringify({error:"internal",message:s,next:"This is a crtr bug, not a bad call. Retry; if it persists, report it."},null,2)+`
7
- `),process.exitCode=a.GENERAL}i(P,"handle");export{m as InputError,v as PREVIEW_RESULT_MAX_BYTES,R as apiErrorToCliError,q as beginPreview,X as diag,Y as emit,H as emitLine,P as handle,z as isJsonOutput,V as peekStdinRaw,B as publishPreviewResult,D as readStdinRaw,K as recordPreviewError,G as recordPreviewJsonLine,g as recordPreviewLine,F as setJsonOutput,M as writeStdout};
7
+ `),process.exitCode=a.GENERAL}i(P,"handle");export{m as InputError,T as PREVIEW_RESULT_MAX_BYTES,R as apiErrorToCliError,q as beginPreview,X as diag,Y as emit,H as emitLine,P as handle,z as isJsonOutput,V as peekStdinRaw,B as publishPreviewResult,D as readStdinRaw,K as recordPreviewError,G as recordPreviewJsonLine,g as recordPreviewLine,F as setJsonOutput,M as writeStdout};
@@ -1 +1 @@
1
- var ue=Object.defineProperty;var m=(e,o)=>ue(e,"name",{value:o,configurable:!0});import{validateDeclaredResult as G}from"../../api/command-manifest/result.js";import{callerAllows as le,requireGroup as pe}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as ce}from"../grants/terminal.js";import{findRefusal as fe,payerOf as me,refusalError as ve,refusedMark as ge,writeCharge as he}from"../ledger/index.js";import{listInstalledPlugins as we}from"../resolver.js";import{emitEvent as ye}from"../events/emit.js";import{ProviderError as l,scopeMissing as be}from"./errors.js";import{resolveProviderRef as _e}from"./roots.js";import{providerToolPath as je}from"../plugin-objects-manifest.js";import{ensureProviderBundle as Ae,refreshProviderBundle as Y,resolveProviderBundle as O,unavailableProviderError as ke}from"./bundles.js";import{prepareFileCall as $e,resignForRetry as Z,resolveFileResult as ee}from"./files.js";import{consumeApproval as Pe,requireProviderApproval as Ee}from"./approval.js";import{outboundToken as qe}from"./mint.js";import{discardFile as Ce}from"./token-cache.js";import{registerProviderCall as Re}from"./inflight.js";import{buildRequestPlan as Me}from"../command-plugins/transport/http-plan.js";import{newTraceId as Te}from"../../shared/traceparent.js";import{sendProviderRequest as Ie,ProviderTransportError as Be}from"./request.js";import{acceptProviderReceipt as Se}from"./receipts.js";import{writeProviderAudit as Ne}from"./audit.js";import{selectDevice as Oe,sendDeviceCall as Fe,deviceFailure as De,deviceUnreachable as re,DEFAULT_DEVICE_REQUEST_MS as Ue}from"./device.js";import{isLibsSearch as te,wantsBundling as Le,callLibsSearch as Je,bundleExec as He,mapLibOutcome as xe,reportLibCalls as Ge}from"./device-libs.js";import{ownMachineId as ze}from"../peer/directory.js";import{directoryIssuer as Qe}from"../directory/issuer.js";import{isCloudRole as Ve}from"../canvas/person-state.js";import{formatCrtrCaller as oe}from"../command-plugins/caller-header.js";import{getNode as We}from"../canvas/canvas.js";import{envelopeForProviderCaller as Ke,EnvelopeError as Xe}from"../peer/envelope.js";const Ye="app:terminal";function ie(e){const o=[],n=m((c,r,i)=>{const u=[...r,c.name],a=i||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)n(v,u,a);return}const A=je(e.roots.length,u);o.push({tool:A,leaf:c,hidden:a})},"walk");for(const c of e.roots)n(c,[],!1);return o}m(ie,"providerLeaves");function ne(e){if(e.kind!=="branch")return null;const o=[];for(const h of e.children)if(h.kind==="branch"){const b=ne(h);b&&o.push(b)}else if("group"in h&&h.group){const{kind:b,name:p,description:_,whenToUse:w,tier:y,summary:k,params:$,output:t,effects:d,group:j}=h;o.push({kind:b,name:p,description:_,whenToUse:w,...y===void 0?{}:{tier:y},summary:k,params:$,output:t,effects:d,group:j})}if(o.length===0)return null;const{kind:n,name:c,description:r,whenToUse:i,tier:u,summary:a,model:A,rootEntry:v}=e;return{kind:n,name:c,description:r,whenToUse:i,...u===void 0?{}:{tier:u},summary:a,...A===void 0?{}:{model:A},...v===void 0?{}:{rootEntry:v},children:o}}m(ne,"providerHelpBranch");async function Sr(e,o){const n=await O(o),c=ie(n.commands),r=we("user").find(i=>i.name===o)?.manifest.description??o;return{provider:o,status:"available",major:n.major,display_name:r,transport:n.transport.kind,groups:n.provider.groups.filter(i=>le(e,`${o}:${i.group}`)).map(i=>({group:i.group,leaves:c.filter(({leaf:u,hidden:a})=>!a&&u.group===i.group).map(({tool:u,leaf:a})=>({tool:u,description:a.description,summary:a.summary,params:a.params,output:a.output}))})),commands:n.commands.roots.flatMap(i=>{const u=ne(i);return u?[u]:[]})}}m(Sr,"providerTools");async function Ze(e){return await Se(e.headers["crtr-receipt"],e)}m(Ze,"onProviderResponse");async function er(e){if(e.class==="person"){const o=(await ce())?.sub;if(!o)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:o,grantee:o}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}m(er,"identity");function rr(e,o){return[`${e.id}:${o.group}`]}m(rr,"callScope");function tr(e,o){const n=ie(e.commands).find(c=>c.tool===o);if(!n)throw new l("not_found",`tool "${o}" is not in provider "${e.id}"`,{param:"tool"});if(!n.leaf.group)throw new l("not_found",`tool "${o}" has no group`,{param:"tool"});return n.leaf}m(tr,"leafFor");function z(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const o=e.error;return!o||typeof o!="object"||Array.isArray(o)?{}:o}m(z,"errorBody");function or(e){const o=Array.isArray(e)?e[0]:e;if(!o)return;const n=Number(o);if(Number.isFinite(n)&&n>=0)return n;const c=Date.parse(o);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}m(or,"retryAfter");function F(e,o,n,c=!1){const r=z(o),i=typeof r.code=="string"?r.code:void 0,u=typeof r.message=="string"?r.message:`provider answered HTTP ${e}`,a=typeof r.field=="string"?r.field:void 0,v={origin:"provider",details:{code:i??null,message:u,...a?{field:a}:{},...typeof r.next=="string"?{next:r.next}:{},...r.received!==void 0?{received:r.received}:{},status:e},...a?{param:a}:{}};return e===429?new l("provider_rate_limited",u,{...v,retry_after_s:or(n["retry-after"])}):e===401||e>=500?new l("provider_unavailable",u,v):e===403&&i==="provider_refused"?new l("provider_refused",u,v):e===403&&i==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",u,{...v,status:e})}m(F,"mapProviderResponse");function se(e,o){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:o.rest,params:o.params,output:o.output})}m(se,"approvalShape");async function ir(e){const o=e.origin!==void 0?oe({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):oe({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await We(e.node_id))?.profile_id??void 0:void 0,machine:Qe()!==null?ze():void 0});return o===""?{}:{"Crtr-Caller":o}}m(ir,"crtrCallerHeader");async function Nr(e,o,n){const c=_e(o.provider);if(c===null)throw new l("not_found",`provider "${o.provider}" is not available`,{param:"provider"});const r={...o,provider:c},i=new AbortController,u=m(()=>i.abort(n.signal.reason),"abort");n.signal.aborted?u():n.signal.addEventListener("abort",u,{once:!0});let a=n.requestId;const A=n.traceId??Te(),v=Re({request_id:a,run_id:e.run_id,node_id:e.node_id,controller:i});let h,b,p,_,w,y,k,$="allowed";try{if(Ve()&&e.class==="person"&&e.resolved!==null&&!e.resolved.some(g=>g.startsWith(`${r.provider}:`)))throw be(`${r.provider}:*`);try{await Ae(r.provider)}catch{throw ke(r.provider)}let t=await O(r.provider,r.version),d=!1,j=!1,P,D,q,Q=!1,V=!1,U,W=0;for(;;){const g=tr(t,r.tool);if(p=`${t.id}:${g.group}`,pe(e,t.id,g.group),t.transport.kind!=="machine"&&r.machine!==void 0)throw new l("invalid_argument",`provider "${t.id}" is not served by a device, so it takes no machine`,{param:"machine"});t.transport.kind==="machine"&&U===void 0&&(U=await Oe(r.machine,void 0,{newest:te(t.major,r.tool)}),W=Date.now()+(t.commands.timeouts?.requestMs??Ue));let L=null;if(r.approval&&!Q){const s=await Pe(e,r,se(t,g));q=s.option,L=s.prepared,k=r.approval,a=s.requestId,Q=!0}const B={params:g.params.filter(s=>"type"in s&&s.type==="file").map(s=>s.name),output:g.output.find(s=>s.type==="file")?.name??null},K=JSON.stringify(B);if(D!==void 0&&D!==K)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=K,L&&(P=await Z(e,B,r.arguments,L,{signal:i.signal})),P??=await $e(e,B,r.arguments,{signal:i.signal});const{sub:M,grantee:S}=await er(e);if(t.transport.kind==="machine"){const s=await nr(e,t,r,g,P,{sub:M,requestId:a,deadlineAt:W,signal:i.signal,machine:U});return y=s.responder,h=s.cleanup,{status:200,body:s.result}}const X=t.transport.endpoint;let C;try{C=await qe({audience:X,sub:M,grantee:S,initiating_app:S,scope:rr(t,g)},{signal:i.signal})}catch(s){if(!(s instanceof l)||s.details?.directory_error!=="invalid_target"||j)throw s;j=!0,await Y(t.id,{conditional:!1,...r.version===void 0?{}:{version:r.version}});const E=await O(t.id,r.version);if(E.transport.kind==="machine"||E.transport.endpoint===X)throw s;t=E;continue}_=C.jti;const J=e.class==="person"?Ye:S,T=me({call:"tool",tokenPayer:C.payer,sub:M}),H=await fe({scope:"call",payer:T.payer,funding:T.funding,sub:M,grantee:J,provider:`app:${t.id}`});if(H!==null)throw await he({request:a,kind:"tool",what:`${t.id}:${r.tool}`,usd:0,payer:T.payer,funding:T.funding,sub:M,grantee:J,node:e.node_id,run:e.run_id,provider:`app:${t.id}`,causedBy:n.causedBy??null,refused:ge(H)}),ve(H);const ae={registration:{name:t.id,endpoint:t.transport.endpoint},...t.commands.baseUrl?{baseUrl:t.commands.baseUrl}:{},...t.commands.timeouts?{timeouts:t.commands.timeouts}:{},params:g.params,rest:g.rest,output:g.output,commandPath:[t.id,...r.tool.split(" ")]},de=Me(ae,P.arguments,void 0,{authorization:`Bearer ${C.access_token}`,requestId:a,traceId:A,fileMode:"pass-through",extraHeaders:{...n.causedBy?{"Crtr-Caused-By":n.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await ir(e),...q?{"Crtr-Approval":q}:{},...P.headers}});b??=Date.now()+(t.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Ie(de,{connectMs:t.commands.timeouts?.connectMs,requestMs:t.commands.timeouts?.requestMs,deadlineAt:b,signal:i.signal}),i.signal.aborted)throw i.signal.reason??new Error("provider call aborted")}catch(s){throw i.signal.aborted?i.signal.reason??s:s instanceof Be?new l("provider_unavailable",s.message,{origin:"provider",details:{status:null,code:s.kind}}):s}if(w??=await Ze({provider:t.id,tool:r.tool,request_id:a,run_id:e.run_id,sub:M,grantee:S,payer:C.payer,ledger_grantee:J,funding:T.funding,node_id:e.node_id,caused_by:n.causedBy??null,jti:C.jti,status:f.status,headers:f.headers}),y=f.headers["crtr-responder"],f.status===401&&Ce(C.key),f.status>=200&&f.status<300){const s=f.body;if(!s||typeof s!="object"||Array.isArray(s))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let E;try{E=await ee(e,P,s,{signal:i.signal})}catch(I){throw I instanceof l&&I.code==="provider_error"?new l("provider_bad_response",I.message,{origin:"provider",details:{status:f.status,message:I.message}}):I}h=E.cleanup;const N=G(g.output,E.result);if(N)throw new l("provider_bad_response",`provider result has an invalid output field "${N.field}"`,{origin:"provider",param:N.field,details:{status:f.status,...N}});if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");return{status:200,body:E.result}}const R=z(f.body);if(f.status===403&&R.code==="approval_required"&&!q&&!V){V=!0;const s=await Ee(e,r,a,R.question,i.signal,se(t,g),P);if(k=s.questionId,q=s.option,P=await Z(e,B,r.arguments,P,{signal:i.signal}),b=void 0,i.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&R.code==="approval_required"&&q)throw F(f.status,f.body,f.headers,!0);const x=f.status===410&&R.code==="unsupported_major"&&r.version===void 0;if(f.status!==401&&(R.manifest_stale===!0||x)&&!d){d=!0;const s=t.major;await Y(t.id,{conditional:!1,...r.version===void 0?{}:{version:r.version}}),t=await O(t.id,r.version),ye({level:"info",event:"daemon.providers.call_retried",fields:{provider:t.id,tool:r.tool,reason:x?"unsupported_major":"manifest_stale",major_before:s,major_after:t.major,...x&&typeof R.received=="number"?{received:R.received}:{}}});continue}throw F(f.status,f.body,f.headers,!!q)}}catch(t){throw t instanceof l&&t.question_id&&(k=t.question_id),y===void 0&&t instanceof l&&typeof t.responder=="string"&&(y=t.responder),$=`refused:${t instanceof l?t.code:"server_error"}`,await h?.(),t}finally{try{await Ne({request_id:a,caller:e,provider:r.provider,tool:r.tool,scope_checked:p,outcome:$,jti:_,receipt_id:w,responder:y,question_id:k})}finally{v()}n.signal.removeEventListener("abort",u)}}m(Nr,"callProvider");async function nr(e,o,n,c,r,i){const{machine:u}=i;let a;try{a=await Ke(e,i.sub)}catch(d){throw d instanceof Xe?new l("invalid_request",d.message,{origin:"runtime"}):d}const A={machine:u,envelope:a,signal:i.signal,deadlineAt:i.deadlineAt,mapFailure:F};if(te(o.major,n.tool)){const d=await Je(A,r.arguments,o.major),j=G(c.output,d);if(j)throw new l("provider_bad_response",`the libraries result has an invalid output field "${j.field}"`,{origin:"provider",param:j.field,details:{status:200,...j}});return{result:d,responder:void 0,cleanup:void 0}}let v=r.arguments,h=null,b="";if(Le(o.major,n.tool,r.arguments)){const d=await He(A,r.arguments,o.major);if(i.deadlineAt-Date.now()<=0)throw re(u,"timeout","");d!==null&&(v=d.arguments,h=d.services,b=d.release)}const p=await Fe(u,{tool:n.tool,arguments:v,version:o.major,requestId:i.requestId,runId:e.run_id,deadlineAt:i.deadlineAt,upload:r.upload===null?null:{id:r.upload.upload_id,link:r.upload.upload_link}},a,i.signal);if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");if("unreachable"in p)throw re(u,p.unreachable.reason,p.unreachable.message);const _=p.headers["crtr-responder"],w=z(p.body);if(p.status<200||p.status>=300){const d=De(u,p.status,typeof w.code=="string"?w.code:void 0,typeof w.message=="string"?w.message:void 0,p.body),j=d===null&&p.status>=500&&typeof w.code=="string"?new l("provider_error",typeof w.message=="string"?w.message:`the device answered HTTP ${p.status}`,{origin:"runtime",status:p.status,details:{code:w.code,status:p.status}}):null;throw Object.assign(d??j??F(p.status,p.body,p.headers),{responder:_})}const y=p.body&&typeof p.body=="object"&&!Array.isArray(p.body)?p.body.result:void 0;if(!y||typeof y!="object"||Array.isArray(y))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:p.status,message:"the device result is not a JSON object"}}),{responder:_});let k=y;if(h!==null){const d=xe(k,h);if(Ge(u,a,b,d.calls),"error"in d)throw Object.assign(d.error,{responder:_});k=d.result}let $;try{$=await ee(e,r,k,{signal:i.signal})}catch(d){throw d instanceof l&&d.code==="provider_error"?Object.assign(new l("provider_bad_response",d.message,{origin:"provider",details:{status:p.status,message:d.message}}),{responder:_}):d}const t=G(c.output,$.result);if(t)throw await $.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${t.field}"`,{origin:"provider",param:t.field,details:{status:p.status,...t}}),{responder:_});return{result:$.result,responder:_,cleanup:$.cleanup}}m(nr,"callDevice");export{Nr as callProvider,ir as crtrCallerHeader,er as identity,F as mapProviderResponse,Ze as onProviderResponse,ie as providerLeaves,Sr as providerTools};
1
+ var ue=Object.defineProperty;var m=(e,t)=>ue(e,"name",{value:t,configurable:!0});import{validateDeclaredResult as G}from"../../api/command-manifest/result.js";import{callerAllows as le,requireGroup as pe}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as ce}from"../grants/terminal.js";import{findRefusal as fe,payerOf as me,refusalError as ve,refusedMark as ge,writeCharge as he}from"../ledger/index.js";import{listInstalledPlugins as we}from"../resolver.js";import{emitEvent as ye}from"../events/emit.js";import{ProviderError as p,scopeMissing as be}from"./errors.js";import{resolveProviderRef as _e}from"./roots.js";import{providerToolPath as je}from"../plugin-objects-manifest.js";import{ensureProviderBundle as Ae,refreshProviderBundle as Y,resolveProviderBundle as S,unavailableProviderError as ke}from"./bundles.js";import{prepareFileCall as $e,resignForRetry as Z,resolveFileResult as ee}from"./files.js";import{consumeApproval as Pe,requireProviderApproval as Ee}from"./approval.js";import{outboundToken as qe}from"./mint.js";import{discardFile as Ce}from"./token-cache.js";import{registerProviderCall as Re}from"./inflight.js";import{buildRequestPlan as Me,paramKey as Te}from"../command-plugins/transport/http-plan.js";import{newTraceId as Ie}from"../../shared/traceparent.js";import{sendProviderRequest as Oe,ProviderTransportError as Be}from"./request.js";import{acceptProviderReceipt as Ne}from"./receipts.js";import{writeProviderAudit as Se}from"./audit.js";import{selectDevice as Fe,sendDeviceCall as De,deviceFailure as Ue,deviceUnreachable as re,DEFAULT_DEVICE_REQUEST_MS as Le}from"./device.js";import{isLibsSearch as te,wantsBundling as Je,callLibsSearch as He,bundleExec as xe,mapLibOutcome as Ge,reportLibCalls as ze}from"./device-libs.js";import{ownMachineId as Ke}from"../peer/directory.js";import{directoryIssuer as Qe}from"../directory/issuer.js";import{isCloudRole as Ve}from"../canvas/person-state.js";import{formatCrtrCaller as oe}from"../command-plugins/caller-header.js";import{getNode as We}from"../canvas/canvas.js";import{envelopeForProviderCaller as Xe,EnvelopeError as Ye}from"../peer/envelope.js";const Ze="app:terminal";function ne(e){const t=[],i=m((u,r,n)=>{const l=[...r,u.name],a=n||u.tier==="hidden";if(u.kind==="branch"){for(const v of u.children)i(v,l,a);return}const A=je(e.roots.length,l);t.push({tool:A,leaf:u,hidden:a})},"walk");for(const u of e.roots)i(u,[],!1);return t}m(ne,"providerLeaves");function ie(e){if(e.kind!=="branch")return null;const t=[];for(const h of e.children)if(h.kind==="branch"){const b=ie(h);b&&t.push(b)}else if("group"in h&&h.group){const{kind:b,name:c,description:_,whenToUse:w,tier:y,summary:k,params:$,output:o,effects:d,group:j}=h;t.push({kind:b,name:c,description:_,whenToUse:w,...y===void 0?{}:{tier:y},summary:k,params:$,output:o,effects:d,group:j})}if(t.length===0)return null;const{kind:i,name:u,description:r,whenToUse:n,tier:l,summary:a,model:A,rootEntry:v}=e;return{kind:i,name:u,description:r,whenToUse:n,...l===void 0?{}:{tier:l},summary:a,...A===void 0?{}:{model:A},...v===void 0?{}:{rootEntry:v},children:t}}m(ie,"providerHelpBranch");async function Sr(e,t){const i=await S(t),u=ne(i.commands),r=we("user").find(n=>n.name===t)?.manifest.description??t;return{provider:t,status:"available",major:i.major,display_name:r,transport:i.transport.kind,groups:i.provider.groups.filter(n=>le(e,`${t}:${n.group}`)).map(n=>({group:n.group,leaves:u.filter(({leaf:l,hidden:a})=>!a&&l.group===n.group).map(({tool:l,leaf:a})=>({tool:l,description:a.description,summary:a.summary,params:a.params,output:a.output}))})),commands:i.commands.roots.flatMap(n=>{const l=ie(n);return l?[l]:[]})}}m(Sr,"providerTools");async function er(e){return await Ne(e.headers["crtr-receipt"],e)}m(er,"onProviderResponse");async function rr(e){if(e.class==="person"){const t=(await ce())?.sub;if(!t)throw new p("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:t,grantee:t}}if(!e.sub||!e.grantee)throw new p("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}m(rr,"identity");function tr(e,t){return[`${e.id}:${t.group}`]}m(tr,"callScope");function or(e,t){const i=ne(e.commands).find(u=>u.tool===t);if(!i)throw new p("not_found",`tool "${t}" is not in provider "${e.id}"`,{param:"tool"});if(!i.leaf.group)throw new p("not_found",`tool "${t}" has no group`,{param:"tool"});return i.leaf}m(or,"leafFor");function z(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t=e.error;return!t||typeof t!="object"||Array.isArray(t)?{}:t}m(z,"errorBody");function nr(e){const t=Array.isArray(e)?e[0]:e;if(!t)return;const i=Number(t);if(Number.isFinite(i)&&i>=0)return i;const u=Date.parse(t);return Number.isFinite(u)?Math.max(0,Math.ceil((u-Date.now())/1e3)):void 0}m(nr,"retryAfter");function F(e,t,i,u=!1){const r=z(t),n=typeof r.code=="string"?r.code:void 0,l=typeof r.message=="string"?r.message:`provider answered HTTP ${e}`,a=typeof r.field=="string"?r.field:void 0,v={origin:"provider",details:{code:n??null,message:l,...a?{field:a}:{},...typeof r.next=="string"?{next:r.next}:{},...r.received!==void 0?{received:r.received}:{},status:e},...a?{param:a}:{}};return e===429?new p("provider_rate_limited",l,{...v,retry_after_s:nr(i["retry-after"])}):e===401||e>=500?new p("provider_unavailable",l,v):e===403&&n==="provider_refused"?new p("provider_refused",l,v):e===403&&n==="approval_required"?new p("provider_error",u?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new p("provider_error",l,{...v,status:e})}m(F,"mapProviderResponse");function se(e,t){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:t.rest,params:t.params,output:t.output})}m(se,"approvalShape");async function ir(e){const t=e.origin!==void 0?oe({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):oe({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await We(e.node_id))?.profile_id??void 0:void 0,machine:Qe()!==null?Ke():void 0});return t===""?{}:{"Crtr-Caller":t}}m(ir,"crtrCallerHeader");async function Fr(e,t,i){const u=_e(t.provider);if(u===null)throw new p("not_found",`provider "${t.provider}" is not available`,{param:"provider"});const r={...t,provider:u},n=new AbortController,l=m(()=>n.abort(i.signal.reason),"abort");i.signal.aborted?l():i.signal.addEventListener("abort",l,{once:!0});let a=i.requestId;const A=i.traceId??Ie(),v=Re({request_id:a,run_id:e.run_id,node_id:e.node_id,controller:n});let h,b,c,_,w,y,k,$="allowed";try{if(Ve()&&e.class==="person"&&e.resolved!==null&&!e.resolved.some(g=>g.startsWith(`${r.provider}:`)))throw be(`${r.provider}:*`);try{await Ae(r.provider)}catch{throw ke(r.provider)}let o=await S(r.provider,r.version),d=!1,j=!1,P,D,q,K=!1,Q=!1,U,V=0;for(;;){const g=or(o,r.tool);if(c=`${o.id}:${g.group}`,pe(e,o.id,g.group),o.transport.kind!=="machine"&&r.machine!==void 0)throw new p("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&U===void 0&&(U=await Fe(r.machine,void 0,{newest:te(o.major,r.tool)}),V=Date.now()+(o.commands.timeouts?.requestMs??Le));let L=null;if(r.approval&&!K){const s=await Pe(e,r,se(o,g));q=s.option,L=s.prepared,k=r.approval,a=s.requestId,K=!0}const O={params:g.params.filter(s=>"type"in s&&s.type==="file").map(s=>s.name),output:g.output.find(s=>s.type==="file")?.name??null},W=JSON.stringify(O);if(D!==void 0&&D!==W)throw new p("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=W,L&&(P=await Z(e,O,r.arguments,L,{signal:n.signal})),P??=await $e(e,O,r.arguments,{signal:n.signal});const{sub:M,grantee:B}=await rr(e);if(o.transport.kind==="machine"){const s=await ar(e,o,r,g,P,{sub:M,requestId:a,deadlineAt:V,signal:n.signal,machine:U});return y=s.responder,h=s.cleanup,{status:200,body:s.result}}const X=o.transport.endpoint;let C;try{C=await qe({audience:X,sub:M,grantee:B,initiating_app:B,scope:tr(o,g)},{signal:n.signal})}catch(s){if(!(s instanceof p)||s.details?.directory_error!=="invalid_target"||j)throw s;j=!0,await Y(o.id,{conditional:!1,...r.version===void 0?{}:{version:r.version}});const E=await S(o.id,r.version);if(E.transport.kind==="machine"||E.transport.endpoint===X)throw s;o=E;continue}_=C.jti;const J=e.class==="person"?Ze:B,T=me({call:"tool",tokenPayer:C.payer,sub:M}),H=await fe({scope:"call",payer:T.payer,funding:T.funding,sub:M,grantee:J,provider:`app:${o.id}`});if(H!==null)throw await he({request:a,kind:"tool",what:`${o.id}:${r.tool}`,usd:0,payer:T.payer,funding:T.funding,sub:M,grantee:J,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:i.causedBy??null,refused:ge(H)}),ve(H);const ae={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:g.params,rest:g.rest,output:g.output,commandPath:[o.id,...r.tool.split(" ")]},de=Me(ae,P.arguments,void 0,{authorization:`Bearer ${C.access_token}`,requestId:a,traceId:A,fileMode:"pass-through",extraHeaders:{...i.causedBy?{"Crtr-Caused-By":i.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await ir(e),...q?{"Crtr-Approval":q}:{},...P.headers}});b??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Oe(de,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:b,signal:n.signal}),n.signal.aborted)throw n.signal.reason??new Error("provider call aborted")}catch(s){throw n.signal.aborted?n.signal.reason??s:s instanceof Be?new p("provider_unavailable",s.message,{origin:"provider",details:{status:null,code:s.kind}}):s}if(w??=await er({provider:o.id,tool:r.tool,request_id:a,run_id:e.run_id,sub:M,grantee:B,payer:C.payer,ledger_grantee:J,funding:T.funding,node_id:e.node_id,caused_by:i.causedBy??null,jti:C.jti,status:f.status,headers:f.headers}),y=f.headers["crtr-responder"],f.status===401&&Ce(C.key),f.status>=200&&f.status<300){const s=f.body;if(!s||typeof s!="object"||Array.isArray(s))throw new p("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let E;try{E=await ee(e,P,s,{signal:n.signal})}catch(I){throw I instanceof p&&I.code==="provider_error"?new p("provider_bad_response",I.message,{origin:"provider",details:{status:f.status,message:I.message}}):I}h=E.cleanup;const N=G(g.output,E.result);if(N)throw new p("provider_bad_response",`provider result has an invalid output field "${N.field}"`,{origin:"provider",param:N.field,details:{status:f.status,...N}});if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");return{status:200,body:E.result}}const R=z(f.body);if(f.status===403&&R.code==="approval_required"&&!q&&!Q){Q=!0;const s=await Ee(e,r,a,R.question,n.signal,se(o,g),P);if(k=s.questionId,q=s.option,P=await Z(e,O,r.arguments,P,{signal:n.signal}),b=void 0,n.signal.aborted)throw new p("user_denied","the approval wait was canceled");continue}if(f.status===403&&R.code==="approval_required"&&q)throw F(f.status,f.body,f.headers,!0);const x=f.status===410&&R.code==="unsupported_major"&&r.version===void 0;if(f.status!==401&&(R.manifest_stale===!0||x)&&!d){d=!0;const s=o.major;await Y(o.id,{conditional:!1,...r.version===void 0?{}:{version:r.version}}),o=await S(o.id,r.version),ye({level:"info",event:"daemon.providers.call_retried",fields:{provider:o.id,tool:r.tool,reason:x?"unsupported_major":"manifest_stale",major_before:s,major_after:o.major,...x&&typeof R.received=="number"?{received:R.received}:{}}});continue}throw F(f.status,f.body,f.headers,!!q)}}catch(o){throw o instanceof p&&o.question_id&&(k=o.question_id),y===void 0&&o instanceof p&&typeof o.responder=="string"&&(y=o.responder),$=`refused:${o instanceof p?o.code:"server_error"}`,await h?.(),o}finally{try{await Se({request_id:a,caller:e,provider:r.provider,tool:r.tool,scope_checked:c,outcome:$,jti:_,receipt_id:w,responder:y,question_id:k})}finally{v()}i.signal.removeEventListener("abort",l)}}m(Fr,"callProvider");function sr(e,t){const i={...t};for(const{name:u}of e.params){const r=Te(u);r===u||!Object.hasOwn(i,r)||(i[u]=i[r],delete i[r])}return i}m(sr,"declaredNames");async function ar(e,t,i,u,r,n){const{machine:l}=n;let a;try{a=await Xe(e,n.sub)}catch(d){throw d instanceof Ye?new p("invalid_request",d.message,{origin:"runtime"}):d}const A={machine:l,envelope:a,signal:n.signal,deadlineAt:n.deadlineAt,mapFailure:F};if(te(t.major,i.tool)){const d=await He(A,r.arguments,t.major),j=G(u.output,d);if(j)throw new p("provider_bad_response",`the libraries result has an invalid output field "${j.field}"`,{origin:"provider",param:j.field,details:{status:200,...j}});return{result:d,responder:void 0,cleanup:void 0}}let v=r.arguments,h=null,b="";if(Je(t.major,i.tool,r.arguments)){const d=await xe(A,r.arguments,t.major);if(n.deadlineAt-Date.now()<=0)throw re(l,"timeout","");d!==null&&(v=d.arguments,h=d.services,b=d.release)}const c=await De(l,{tool:i.tool,arguments:sr(u,v),version:t.major,requestId:n.requestId,runId:e.run_id,deadlineAt:n.deadlineAt,upload:r.upload===null?null:{id:r.upload.upload_id,link:r.upload.upload_link}},a,n.signal);if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");if("unreachable"in c)throw re(l,c.unreachable.reason,c.unreachable.message);const _=c.headers["crtr-responder"],w=z(c.body);if(c.status<200||c.status>=300){const d=Ue(l,c.status,typeof w.code=="string"?w.code:void 0,typeof w.message=="string"?w.message:void 0,c.body),j=d===null&&c.status>=500&&typeof w.code=="string"?new p("provider_error",typeof w.message=="string"?w.message:`the device answered HTTP ${c.status}`,{origin:"runtime",status:c.status,details:{code:w.code,status:c.status}}):null;throw Object.assign(d??j??F(c.status,c.body,c.headers),{responder:_})}const y=c.body&&typeof c.body=="object"&&!Array.isArray(c.body)?c.body.result:void 0;if(!y||typeof y!="object"||Array.isArray(y))throw Object.assign(new p("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:c.status,message:"the device result is not a JSON object"}}),{responder:_});let k=y;if(h!==null){const d=Ge(k,h);if(ze(l,a,b,d.calls),"error"in d)throw Object.assign(d.error,{responder:_});k=d.result}let $;try{$=await ee(e,r,k,{signal:n.signal})}catch(d){throw d instanceof p&&d.code==="provider_error"?Object.assign(new p("provider_bad_response",d.message,{origin:"provider",details:{status:c.status,message:d.message}}),{responder:_}):d}const o=G(u.output,$.result);if(o)throw await $.cleanup?.(),Object.assign(new p("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:c.status,...o}}),{responder:_});return{result:$.result,responder:_,cleanup:$.cleanup}}m(ar,"callDevice");export{Fr as callProvider,ir as crtrCallerHeader,rr as identity,F as mapProviderResponse,er as onProviderResponse,ne as providerLeaves,Sr as providerTools};
@@ -0,0 +1,15 @@
1
+ /** The accepted-message id of an app run's launch prompt. Derived from the run id, so the launch paths can find it
2
+ * again without a second record and a replayed creation can never mint a second one. */
3
+ export declare function initialInputMessageId(runId: string): string;
4
+ /** Gives a run's launch prompt the durable message identity a `run.start` `message` already has, inside the run-creation
5
+ * transaction. The launch prompt reaches the model as the kickoff, so its delivery is written already acknowledged:
6
+ * the inbox never hands it over a second time. Its id is what the first turn's model and tool rows name as their cause. */
7
+ export declare function recordInitialInput(runId: string, grantee: string, prompt: string): Promise<void>;
8
+ /** Puts a run root's launch-prompt message id on its first kickoff's env, where the broker reads the ids of the turn's input.
9
+ * A node that is not a run root, or a run started with a `message` (which joins the first turn through the inbox), has none. */
10
+ export declare function carryInitialInput(inv: {
11
+ env: Record<string, string>;
12
+ }, node: {
13
+ node_id: string;
14
+ run_id?: string | null;
15
+ }): Promise<void>;
@@ -0,0 +1 @@
1
+ var d=Object.defineProperty;var n=(e,i)=>d(e,"name",{value:i,configurable:!0});import{createHash as o}from"node:crypto";import{openDb as u}from"../canvas/db.js";import{enqueueNodeMail as c}from"../feed/messages.js";function t(e){return o("sha256").update(`initial-input:${e}`).digest("hex").slice(0,32)}n(t,"initialInputMessageId");async function m(e,i,a){await c(e,{kind:"message",label:a.slice(0,120),senderNodeId:null,senderName:i,bodyJson:{body:a,start_turn:!1},urgency:"deferred",wake:0,messageId:t(e),withinEnqueue:n(async(r,s)=>{await r.prepare("UPDATE deliveries SET state = 'acknowledged', acknowledged_at = ? WHERE message_id = ?").run(Date.now(),s)},"withinEnqueue")})}n(m,"recordInitialInput");async function E(e,i){if(i.run_id!==i.node_id)return;const a=t(i.node_id);await(await u()).prepare("SELECT 1 FROM messages WHERE message_id = ?").get(a)!==void 0&&(e.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify([a]))}n(E,"carryInitialInput");export{E as carryInitialInput,t as initialInputMessageId,m as recordInitialInput};
@@ -1,14 +1,14 @@
1
- var Me=Object.defineProperty;var c=(e,t)=>Me(e,"name",{value:t,configurable:!0});import{coveredByAny as Ae}from"../../shared/env.js";import{createHash as Q}from"node:crypto";import{ApiError as Ie}from"../../api/errors.js";import{CrtrError as Te}from"../errors.js";import{isCloudRole as Le}from"../canvas/person.js";import{isAbsolute as V,relative as Ce,resolve as ke,sep as xe,join as We}from"node:path";import{SessionManager as Fe}from"@earendil-works/pi-coding-agent";import{covers as P}from"@north-light/identity";import{openDb as B,withCanvasWrite as F}from"../canvas/db.js";import{deleteNodeWithOwned as qe}from"../graph/deletion.js";import{getById as He}from"../graph/objects.js";import{repairRunConversations as Z}from"../canvas/sessions.js";import{getNode as O,nodeFiles as Ue,removeNodeFiles as $e,updateNode as Pe}from"../canvas/canvas.js";import{fullName as Be}from"../canvas/labels.js";import{renameWindow as je}from"../runtime/placement.js";import{liveExecutionForNode as K}from"../canvas/executions.js";import{conversationStore as ee,isConversationNotFound as Je}from"../conversation-store/index.js";import{PARKED_RESIDENT_SQL as Ye}from"../canvas/canvas.js";import{WAKE_MAIL_SQL as Ge}from"../canvas/deliveries.js";import{readNodeRecap as Xe}from"../canvas/node-recap.js";import{enqueueNodeMail as ze}from"../feed/messages.js";import{newestReportBody as Qe}from"../feed/reports.js";import{ensureAppProfile as te,loadExactProfileManifest as ne}from"../profiles/manifest.js";import{stopNodeSandboxes as se}from"../spaces/stop.js";import{BrokerUnreachableError as Ve}from"../runtime/broker-request.js";import{interruptLive as Ze}from"../runtime/interactive-deliver.js";import{isBrokerLive as ae}from"../runtime/model-swap.js";import{newNodeId as Ke}from"../runtime/nodes.js";import{reviveNode as j}from"../runtime/revive.js";import{spawnChildPrepared as et}from"../runtime/spawn.js";import{isPortableModelToken as tt}from"../runtime/launch.js";import{parseDurationMs as nt}from"../wake.js";import{expandModelCandidates as st,parseModelSpec as at}from"../model-routes.js";import{payerOfGrant as J}from"../grants/mirror.js";import{isolatedBrokerLauncherAvailable as it}from"../runtime/host.js";import{blaxelEnvironmentOf as rt}from"../runtime/blaxel-environment.js";import{resolveRunKind as ot,resolveRunModel as dt}from"../runtime/launch-target.js";import{cycleAwareMessages as ct}from"../runtime/session-cycles.js";import{originFor as ie}from"../runtime/stamp/protocol.js";import{readOutputRequest as ut,readOutputResult as re}from"../runtime/output-result.js";import{admitLegacyStructuredOutput as oe}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as mt}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as lt}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as ft}from"../../daemon/runs/observer.js";import{closeNode as de}from"../runtime/close.js";import{parseScope as pt}from"@north-light/identity";import{appendRunEvent as ce,lockRunRoot as _t,subscribeRunEvents as wt}from"./events.js";import{runActivity as gt}from"./activity.js";import{cancelOpenQuestions as ue,openNoticeIds as Et,openQuestionIds as me}from"./questions.js";import{appSpace as Y}from"../layout.js";import{ensureAppSpace as yt}from"../spaces/space.js";import{assertUploadsUsable as le,resolveStorageUrls as ht}from"../storage/attachments.js";import{storageClient as Rt,storageConfig as St}from"../storage/client.js";import{deleteUploadRow as Nt,insertUploadUses as fe,releaseRunUploads as vt,runUsesPath as bt}from"../storage/tables.js";import{abortProviderCalls as pe}from"../providers/inflight.js";import{filterAsync as _e,mapAsync as x}from"../async-array.js";const we=c((e,t,s,n)=>ht(t,e,s,n?{taken:n}:{}),"defaultResolver"),Ot=3e3;class R extends Error{static{c(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,s,n,d,f,r,i=t===503){super(n),this.status=t,this.code=s,this.param=d,this.details=f,this.scope=r,this.retryable=i}}const N=c((e,t)=>new R(400,"invalid_request",e,t),"invalid"),G=c(()=>new R(404,"not_found","run not found"),"missing"),X=c(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),A=c(async()=>await B(),"db");async function q(e,t,s=!1){const n=await O(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!s&&n.deleting_at)throw G();return n}c(q,"ownedRun");const ge=["waiting_on_user","idle","settled"];async function C(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=await(await A()).prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
1
+ var Me=Object.defineProperty;var c=(e,t)=>Me(e,"name",{value:t,configurable:!0});import{coveredByAny as Ie}from"../../shared/env.js";import{createHash as Q}from"node:crypto";import{ApiError as Ae}from"../../api/errors.js";import{CrtrError as Te}from"../errors.js";import{isCloudRole as Le}from"../canvas/person.js";import{isAbsolute as V,relative as Ce,resolve as ke,sep as xe,join as We}from"node:path";import{SessionManager as Fe}from"@earendil-works/pi-coding-agent";import{covers as P}from"@north-light/identity";import{openDb as B,withCanvasWrite as F}from"../canvas/db.js";import{deleteNodeWithOwned as qe}from"../graph/deletion.js";import{getById as He}from"../graph/objects.js";import{repairRunConversations as Z}from"../canvas/sessions.js";import{getNode as O,nodeFiles as Ue,removeNodeFiles as $e,updateNode as Pe}from"../canvas/canvas.js";import{fullName as Be}from"../canvas/labels.js";import{renameWindow as je}from"../runtime/placement.js";import{liveExecutionForNode as K}from"../canvas/executions.js";import{conversationStore as ee,isConversationNotFound as Je}from"../conversation-store/index.js";import{PARKED_RESIDENT_SQL as Ye}from"../canvas/canvas.js";import{WAKE_MAIL_SQL as Ge}from"../canvas/deliveries.js";import{readNodeRecap as Xe}from"../canvas/node-recap.js";import{enqueueNodeMail as ze}from"../feed/messages.js";import{recordInitialInput as Qe}from"./initial-input.js";import{newestReportBody as Ve}from"../feed/reports.js";import{ensureAppProfile as te,loadExactProfileManifest as ne}from"../profiles/manifest.js";import{stopNodeSandboxes as se}from"../spaces/stop.js";import{BrokerUnreachableError as Ze}from"../runtime/broker-request.js";import{interruptLive as Ke}from"../runtime/interactive-deliver.js";import{isBrokerLive as ae}from"../runtime/model-swap.js";import{newNodeId as et}from"../runtime/nodes.js";import{reviveNode as j}from"../runtime/revive.js";import{spawnChildPrepared as tt}from"../runtime/spawn.js";import{isPortableModelToken as nt}from"../runtime/launch.js";import{parseDurationMs as st}from"../wake.js";import{expandModelCandidates as at,parseModelSpec as it}from"../model-routes.js";import{payerOfGrant as J}from"../grants/mirror.js";import{isolatedBrokerLauncherAvailable as rt}from"../runtime/host.js";import{blaxelEnvironmentOf as ot}from"../runtime/blaxel-environment.js";import{resolveRunKind as dt,resolveRunModel as ct}from"../runtime/launch-target.js";import{cycleAwareMessages as ut}from"../runtime/session-cycles.js";import{originFor as ie}from"../runtime/stamp/protocol.js";import{readOutputRequest as mt,readOutputResult as re}from"../runtime/output-result.js";import{admitLegacyStructuredOutput as oe}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as lt}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as ft}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as pt}from"../../daemon/runs/observer.js";import{closeNode as de}from"../runtime/close.js";import{parseScope as _t}from"@north-light/identity";import{appendRunEvent as ce,lockRunRoot as wt,subscribeRunEvents as gt}from"./events.js";import{runActivity as Et}from"./activity.js";import{cancelOpenQuestions as ue,openNoticeIds as yt,openQuestionIds as me}from"./questions.js";import{appSpace as Y}from"../layout.js";import{ensureAppSpace as ht}from"../spaces/space.js";import{assertUploadsUsable as le,resolveStorageUrls as Rt}from"../storage/attachments.js";import{storageClient as St,storageConfig as Nt}from"../storage/client.js";import{deleteUploadRow as vt,insertUploadUses as fe,releaseRunUploads as bt,runUsesPath as Ot}from"../storage/tables.js";import{abortProviderCalls as pe}from"../providers/inflight.js";import{filterAsync as _e,mapAsync as x}from"../async-array.js";const we=c((e,t,s,n)=>Rt(t,e,s,n?{taken:n}:{}),"defaultResolver"),Dt=3e3;class R extends Error{static{c(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,s,n,d,f,r,i=t===503){super(n),this.status=t,this.code=s,this.param=d,this.details=f,this.scope=r,this.retryable=i}}const N=c((e,t)=>new R(400,"invalid_request",e,t),"invalid"),G=c(()=>new R(404,"not_found","run not found"),"missing"),X=c(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),I=c(async()=>await B(),"db");async function q(e,t,s=!1){const n=await O(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!s&&n.deleting_at)throw G();return n}c(q,"ownedRun");const ge=["waiting_on_user","idle","settled"];async function C(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=await(await I()).prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
2
2
  (n.last_settled_at IS NULL OR EXISTS (
3
3
  SELECT 1 FROM run_events e WHERE e.run_id = ? AND e.node_id = n.node_id AND e.type = 'node.turn.started'
4
4
  AND e.sequence_number > COALESCE((SELECT MAX(c.sequence_number) FROM run_events c
5
5
  WHERE c.run_id = e.run_id AND c.node_id = e.node_id AND c.type = 'node.turn.completed'), 0)
6
- )) LIMIT 1`).get(e.node_id,e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||s||await mt(e)?"running":(await me(e.node_id)).length?"waiting_on_user":await(await A()).prepare(`SELECT 1 FROM deliveries d JOIN nodes n ON n.node_id = d.destination_id
6
+ )) LIMIT 1`).get(e.node_id,e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||s||await lt(e)?"running":(await me(e.node_id)).length?"waiting_on_user":await(await I()).prepare(`SELECT 1 FROM deliveries d JOIN nodes n ON n.node_id = d.destination_id
7
7
  WHERE n.run_id = ? AND ${Ge("d","'armed', 'pending', 'handed_off'")}
8
- AND (n.status IN ('active', 'idle') OR ${Ye("n")}) LIMIT 1`).get(e.node_id)?"running":"idle"}c(C,"runStatus");async function Wn(e){const t=await O(e);return t!==null&&await C(t)==="running"}c(Wn,"runIsRunning");async function W(e){await Z(e.node_id),e=await O(e.node_id)??e;const t=await C(e),s=t==="settled"?[]:await me(e.node_id),n=await Qe(e.node_id)||void 0,d=t==="settled"?await lt(e):null,f=d?.kind==="result"?await re(e.node_id):void 0,r=Xe(e.node_id);return{run_id:e.node_id,name:e.name,status:t,...d?{outcome:d}:{},...f===void 0?{}:{result:f},...n!==void 0?{last_report:n}:{},...r?{recap:r}:{},pending_question_ids:s,open_notice_ids:t==="settled"?[]:await Et(e.node_id),...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(X())),payer:await J(e.grant_id),scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at,activity:await gt(e.node_id,t)}}c(W,"runObject");const z=864e5,Ee=255;function Fn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>Ee)throw N(`Idempotency-Key must be 1-${Ee} characters`);return e}}c(Fn,"idempotencyKeyOf");function Dt(e){if(Le()){if(!e)throw new R(403,"permission_error","a cloud role serves this call only for a token that names a person");return e}}c(Dt,"cloudPersonScope");function k(e,t){const s=Dt(e);return s===void 0?t:`${s}:${t}`}c(k,"personKey");async function H(e,t,s,n){n&&await n.prepare("SELECT pg_advisory_xact_lock(hashtext(?))").get(`idempotency:${e}:${t}`),n??=await B();const d=await n.prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!d||Date.now()-Date.parse(d.created_at)>=z)){if(d.body_hash!==s)throw new R(409,"idempotency_conflict","key used with a different request");return{run_id:d.run_id,response:JSON.parse(d.response_json)}}}c(H,"findIdempotent");async function ye(e,t,s,n,d,f,r){await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,s,new Date(Date.now()-z).toISOString()),await e.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,s,n,d,JSON.stringify(f),r)}c(ye,"recordIdempotent");async function qn(e=Date.now()){return Number((await(await B()).prepare("DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-z).toISOString())).changes)}c(qn,"pruneExpiredIdempotencyKeys");async function he(e,t,s,n,d,f=!1){const r=n.text;let i=0;return{messageId:(await ze(t,{kind:"message",label:r.slice(0,120),senderNodeId:"human",senderName:s,bodyJson:d?{body:r,...f?{steer:!0}:{}}:{body:r,start_turn:!1},urgency:d?"normal":"deferred",wake:d?1:0,withinEnqueue:c(async(m,h)=>{n.uses.length&&(await le(s,n.uses,m),await fe(n.uses.map(({upload_id:g,path:E,blob_key:o})=>({upload_id:g,path:E,blob_key:o,run_id:t})),m)),i=(await ce(m,t,t,"node.message.accepted",{message_id:h,start_turn:d})).sequence_number},"withinEnqueue")})).messageId,sequence:i}}c(he,"acceptRunMessage");class Re extends Error{static{c(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const Mt=1440*60*1e3;function Se(e){const t=typeof e=="string"?nt(e):null;if(t===null||!Number.isSafeInteger(t))throw N(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw N("deadline must be greater than zero","deadline");if(t>Mt)throw N("deadline must be at most 24h","deadline");return t}c(Se,"parseRunDeadlineMs");async function Hn(e,t,s,n=we){if(t.isolated&&!it()&&await rt((t.profile===void 0?await te(e.grantee):ne(t.profile)).profileId)===null)throw new R(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&Se(t.deadline);const{causedBy:d,...f}=t,r=Q("sha256").update(JSON.stringify(f)).digest("hex");if(s){const a=await H(e.grantee,k(e.sub,s),r);if(a){const l=await q(a.run_id,e.grantee);return!l.pi_pid&&await C(l)==="running"&&(t.output_schema!==void 0&&!l.outcome_at&&await ut(l.node_id)===null&&await re(l.node_id)===void 0&&await oe(l.node_id,"terminal",t.output_schema),await j(l.node_id,{resume:!0,capacity:"freeze"})),a.response}}await yt(e.grantee);const i=t.profile===void 0?await te(e.grantee):ne(t.profile),u=i.manifest.grantee??"app:terminal";if(u!==e.grantee){const a=`crtr:memory:rw:${u}:profile:${i.profileId}`;if(!e.resolved.some(l=>P(l,a))||t.scopes!==null&&!t.scopes.some(l=>P(l,a)))throw new R(403,"scope_missing",`missing scope ${a}`,"profile",void 0,a)}if(t.model!==void 0){const a=t.model;if(tt(a)){if(a.includes("/")&&await J(e.grant)!=="app"){const l=a.lastIndexOf("/"),D=a.slice(0,l),v=a.slice(l+1);if(["ultra","strong","medium","light"].includes(v)&&(await st({kind:"logical",family:D,strength:v,spec:a},Y(e.grantee).files,i.profileId)).every(S=>S.family!==D))throw N(`model '${a}' names a model family that is not configured in this daemon`,"model")}}else if(at(a)===void 0)throw N(`model '${a}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const m=await Ke(),h=We(Y(e.grantee).nodes,m);if(t.isolated&&t.cwd!==void 0){const a=Ce(h,ke(t.cwd));if(!V(t.cwd)||a===".."||a.startsWith(`..${xe}`)||V(a))throw N("cwd must be inside the isolated root node folder","cwd")}const g=await n(m,e.grantee,t.prompt),E=g.text,o=t.message===void 0?void 0:await n(m,e.grantee,t.message,g.uses.map(a=>a.path)),p=await J(e.grant);let y;try{const a=dt(i,t.model);await et({kind:ot(i),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??h:Y(e.grantee).files,profile:i.profileId,prompt:E,nodeId:m,isolated:t.isolated??!1,...t.causedBy===void 0?{}:{causedBy:t.causedBy},...a===void 0?{}:{model:a},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+Se(t.deadline)).toISOString()},...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:m,event_cursor:1,usage_json:JSON.stringify(X())},withinCreate:c(async(l,D)=>{if(s){const S=await H(e.grantee,k(e.sub,s),r,l);if(S)throw new Re(S)}const v=g.uses;if(v.length&&(await le(e.grantee,v,l),await fe(v.map(({upload_id:S,path:I,blob_key:U})=>({upload_id:S,path:I,blob_key:U,run_id:m})),l)),y={run_id:m,node_id:m,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:p,status:"running",created_at:D.created,metadata:t.metadata,sequence_number:0},await ce(l,m,m,"run.started",{scopes:t.scopes,payer:p,usage:X()}),o){const S=await he(l,m,e.grantee,o,!1);y.message={run_id:m,message_id:S.messageId,sequence_number:S.sequence}}s&&await ye(l,e.grantee,k(e.sub,s),r,m,y,D.created)},"withinCreate")},t.output_schema===void 0?void 0:async l=>{await oe(l,"terminal",t.output_schema)})}catch(a){if(a instanceof Re)return a.winner.response;if(t.model!==void 0&&a instanceof Te&&a.code==="usage")throw N(a.message,"model");if(a instanceof Ie&&(a.code==="isolated_run"||a.code==="invalid_request")){const l=a.details&&typeof a.details=="object"&&"param"in a.details&&typeof a.details.param=="string"?a.details.param:void 0;throw new R(a.status,a.code,a.message,l)}throw a}if(!y)throw new Error("run creation did not commit");return y}c(Hn,"startRun");async function Un(e,t){let s;if(t.after)try{const i=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!i||typeof i!="object"||!("activity"in i)||typeof i.activity!="string"||!("id"in i)||typeof i.id!="string")throw new Error("invalid cursor");s={activity:i.activity,id:i.id}}catch{throw N("invalid list cursor","after")}const n=await(await A()).prepareUncached(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
8
+ AND (n.status IN ('active', 'idle') OR ${Ye("n")}) LIMIT 1`).get(e.node_id)?"running":"idle"}c(C,"runStatus");async function qn(e){const t=await O(e);return t!==null&&await C(t)==="running"}c(qn,"runIsRunning");async function W(e){await Z(e.node_id),e=await O(e.node_id)??e;const t=await C(e),s=t==="settled"?[]:await me(e.node_id),n=await Ve(e.node_id)||void 0,d=t==="settled"?await ft(e):null,f=d?.kind==="result"?await re(e.node_id):void 0,r=Xe(e.node_id);return{run_id:e.node_id,name:e.name,status:t,...d?{outcome:d}:{},...f===void 0?{}:{result:f},...n!==void 0?{last_report:n}:{},...r?{recap:r}:{},pending_question_ids:s,open_notice_ids:t==="settled"?[]:await yt(e.node_id),...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(X())),payer:await J(e.grant_id),scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at,activity:await Et(e.node_id,t)}}c(W,"runObject");const z=864e5,Ee=255;function Hn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>Ee)throw N(`Idempotency-Key must be 1-${Ee} characters`);return e}}c(Hn,"idempotencyKeyOf");function Mt(e){if(Le()){if(!e)throw new R(403,"permission_error","a cloud role serves this call only for a token that names a person");return e}}c(Mt,"cloudPersonScope");function k(e,t){const s=Mt(e);return s===void 0?t:`${s}:${t}`}c(k,"personKey");async function H(e,t,s,n){n&&await n.prepare("SELECT pg_advisory_xact_lock(hashtext(?))").get(`idempotency:${e}:${t}`),n??=await B();const d=await n.prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!d||Date.now()-Date.parse(d.created_at)>=z)){if(d.body_hash!==s)throw new R(409,"idempotency_conflict","key used with a different request");return{run_id:d.run_id,response:JSON.parse(d.response_json)}}}c(H,"findIdempotent");async function ye(e,t,s,n,d,f,r){await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,s,new Date(Date.now()-z).toISOString()),await e.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,s,n,d,JSON.stringify(f),r)}c(ye,"recordIdempotent");async function Un(e=Date.now()){return Number((await(await B()).prepare("DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-z).toISOString())).changes)}c(Un,"pruneExpiredIdempotencyKeys");async function he(e,t,s,n,d,f=!1){const r=n.text;let i=0;return{messageId:(await ze(t,{kind:"message",label:r.slice(0,120),senderNodeId:"human",senderName:s,bodyJson:d?{body:r,...f?{steer:!0}:{}}:{body:r,start_turn:!1},urgency:d?"normal":"deferred",wake:d?1:0,withinEnqueue:c(async(m,h)=>{n.uses.length&&(await le(s,n.uses,m),await fe(n.uses.map(({upload_id:g,path:E,blob_key:o})=>({upload_id:g,path:E,blob_key:o,run_id:t})),m)),i=(await ce(m,t,t,"node.message.accepted",{message_id:h,start_turn:d})).sequence_number},"withinEnqueue")})).messageId,sequence:i}}c(he,"acceptRunMessage");class Re extends Error{static{c(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const It=1440*60*1e3;function Se(e){const t=typeof e=="string"?st(e):null;if(t===null||!Number.isSafeInteger(t))throw N(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw N("deadline must be greater than zero","deadline");if(t>It)throw N("deadline must be at most 24h","deadline");return t}c(Se,"parseRunDeadlineMs");async function $n(e,t,s,n=we){if(t.isolated&&!rt()&&await ot((t.profile===void 0?await te(e.grantee):ne(t.profile)).profileId)===null)throw new R(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&Se(t.deadline);const{causedBy:d,...f}=t,r=Q("sha256").update(JSON.stringify(f)).digest("hex");if(s){const a=await H(e.grantee,k(e.sub,s),r);if(a){const l=await q(a.run_id,e.grantee);return!l.pi_pid&&await C(l)==="running"&&(t.output_schema!==void 0&&!l.outcome_at&&await mt(l.node_id)===null&&await re(l.node_id)===void 0&&await oe(l.node_id,"terminal",t.output_schema),await j(l.node_id,{resume:!0,capacity:"freeze"})),a.response}}await ht(e.grantee);const i=t.profile===void 0?await te(e.grantee):ne(t.profile),u=i.manifest.grantee??"app:terminal";if(u!==e.grantee){const a=`crtr:memory:rw:${u}:profile:${i.profileId}`;if(!e.resolved.some(l=>P(l,a))||t.scopes!==null&&!t.scopes.some(l=>P(l,a)))throw new R(403,"scope_missing",`missing scope ${a}`,"profile",void 0,a)}if(t.model!==void 0){const a=t.model;if(nt(a)){if(a.includes("/")&&await J(e.grant)!=="app"){const l=a.lastIndexOf("/"),D=a.slice(0,l),v=a.slice(l+1);if(["ultra","strong","medium","light"].includes(v)&&(await at({kind:"logical",family:D,strength:v,spec:a},Y(e.grantee).files,i.profileId)).every(S=>S.family!==D))throw N(`model '${a}' names a model family that is not configured in this daemon`,"model")}}else if(it(a)===void 0)throw N(`model '${a}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const m=await et(),h=We(Y(e.grantee).nodes,m);if(t.isolated&&t.cwd!==void 0){const a=Ce(h,ke(t.cwd));if(!V(t.cwd)||a===".."||a.startsWith(`..${xe}`)||V(a))throw N("cwd must be inside the isolated root node folder","cwd")}const g=await n(m,e.grantee,t.prompt),E=g.text,o=t.message===void 0?void 0:await n(m,e.grantee,t.message,g.uses.map(a=>a.path)),p=await J(e.grant);let y;try{const a=ct(i,t.model);await tt({kind:dt(i),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??h:Y(e.grantee).files,profile:i.profileId,prompt:E,nodeId:m,isolated:t.isolated??!1,...t.causedBy===void 0?{}:{causedBy:t.causedBy},...a===void 0?{}:{model:a},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+Se(t.deadline)).toISOString()},...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:m,event_cursor:1,usage_json:JSON.stringify(X())},withinCreate:c(async(l,D)=>{if(s){const S=await H(e.grantee,k(e.sub,s),r,l);if(S)throw new Re(S)}const v=g.uses;if(v.length&&(await le(e.grantee,v,l),await fe(v.map(({upload_id:S,path:A,blob_key:U})=>({upload_id:S,path:A,blob_key:U,run_id:m})),l)),y={run_id:m,node_id:m,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:p,status:"running",created_at:D.created,metadata:t.metadata,sequence_number:0},await ce(l,m,m,"run.started",{scopes:t.scopes,payer:p,usage:X()}),o){const S=await he(l,m,e.grantee,o,!1);y.message={run_id:m,message_id:S.messageId,sequence_number:S.sequence}}else await Qe(m,e.grantee,E);s&&await ye(l,e.grantee,k(e.sub,s),r,m,y,D.created)},"withinCreate")},t.output_schema===void 0?void 0:async l=>{await oe(l,"terminal",t.output_schema)})}catch(a){if(a instanceof Re)return a.winner.response;if(t.model!==void 0&&a instanceof Te&&a.code==="usage")throw N(a.message,"model");if(a instanceof Ae&&(a.code==="isolated_run"||a.code==="invalid_request")){const l=a.details&&typeof a.details=="object"&&"param"in a.details&&typeof a.details.param=="string"?a.details.param:void 0;throw new R(a.status,a.code,a.message,l)}throw a}if(!y)throw new Error("run creation did not commit");return y}c($n,"startRun");async function Pn(e,t){let s;if(t.after)try{const i=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!i||typeof i!="object"||!("activity"in i)||typeof i.activity!="string"||!("id"in i)||typeof i.id!="string")throw new Error("invalid cursor");s={activity:i.activity,id:i.id}}catch{throw N("invalid list cursor","after")}const n=await(await I()).prepareUncached(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
9
9
  WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}${t.sub===void 0?"":" AND sub = ?"}
10
- ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e],...t.sub===void 0?[]:[t.sub]),d=await _e(await x((await _e(n,async({node_id:i})=>!t.visible||await t.visible(i))).filter(({activity:i,node_id:u})=>!s||i<s.activity||i===s.activity&&u<s.id),async i=>({root:await O(i.node_id),activity:i.activity})),async({root:i})=>!t.status||await C(i)===t.status),f=d.slice(0,t.limit),r=f.at(-1);return{runs:await x(f,async({root:i})=>await W(i)),next:d.length>t.limit&&r?Buffer.from(JSON.stringify({activity:r.activity,id:r.root.node_id})).toString("base64url"):null}}c(Un,"listRuns");async function $n(e,t,s){const n=await q(e,t),d=c(async()=>await W(await q(e,t)),"read");return!s||ge.includes(await C(n))?await d():new Promise((f,r)=>{let i=c(()=>{},"unsubscribe");const u=c(()=>{clearTimeout(o),clearInterval(E),i()},"settle"),m=c(async()=>{u();try{f(await d())}catch(p){r(p)}},"finish"),h=c(async()=>{ge.includes(String((await d()).status))&&await m()},"check"),g=c(()=>{h().catch(p=>{u(),r(p)})},"run"),E=setInterval(g,250),o=setTimeout(()=>{m()},s*1e3);wt(e,g).then(p=>{i=p},p=>{u(),r(p)})})}c($n,"waitRun");const At=5;async function Pn(e,t,s=we,n=!0,d,f=!0){const r=e.status==="canceled"||e.outcome_reason==="closed",i=e.grantee??"app:terminal",u=Q("sha256").update(JSON.stringify(["run.message",e.node_id,t,n,...n&&!f?["steer:false"]:[]])).digest("hex"),m=c(async g=>{const E=await O(e.node_id),o=await(await A()).prepare("SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(g.message_id));return E&&!r&&n&&!E.pi_pid&&o&&await j(e.node_id,{resume:!0,capacity:"freeze"}),g},"replay");if(d){const g=await H(i,k(e.sub,d),u);if(g)return m(g.response)}if(r)throw new R(409,"run_settled","canceled run cannot receive a message");const h=n&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;for(let g=1;;g++){const E=await s(e.node_id,i,t),o=await F(async p=>{if(d){const l=await H(i,k(e.sub,d),u,p);if(l)return{replayed:l.response}}if(E.uses.length){await _t(p,e.node_id);for(const l of E.uses)if(await bt(e.node_id,l.path,p))return"path_taken"}await h?.(e.node_id);const y=await he(p,e.node_id,i,E,n,n&&f),a={run_id:e.node_id,message_id:y.messageId,sequence_number:y.sequence};return d&&await ye(p,i,k(e.sub,d),u,e.node_id,a,new Date().toISOString()),{result:a}});if(o==="path_taken"){if(g>=At)throw new R(503,"service_unavailable","attachments of concurrent messages kept taking each other's file names; retry");continue}return"replayed"in o?m(o.replayed):(n&&!e.pi_pid&&await j(e.node_id,{resume:!0,capacity:"freeze"}),o.result)}}c(Pn,"messageRun");async function It(e){const t=c(()=>new R(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let s=0;s<2;s++){const n=await O(e);if(!n)throw G();if(!ae(n)){if(n.streaming)throw t();return}const d=(await K(e))?.executionId;try{await Ze(e)==="turn"&&pe({nodes:[e]});return}catch(f){if(!(f instanceof Ve))throw f;const r=await O(e);if(!r)throw G();if(!r.streaming)return;if(s===0&&ae(r)&&(await K(e))?.executionId!==d)continue;throw t()}}throw t()}c(It,"interruptNode");async function Bn(e,t="stop"){const s=t==="stop"?(await(await A()).prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id)).map(({node_id:n})=>n):[e.node_id];return await Promise.all(s.map(n=>It(n))),await W(await O(e.node_id)??e)}c(Bn,"interruptRun");async function jn(e,t={}){const s=(await(await A()).prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(r=>r.node_id);pe({run:e.node_id});const n=[];if(await C(e)!=="settled")n.push(...(await de(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"})).closed);else for(const r of s){if(r===e.node_id)continue;const i=await O(r);i&&i.status!=="done"&&i.status!=="canceled"&&i.status!=="dead"&&n.push(...(await de(r,{preserveEmpty:!0,stopReason:"run_canceled"})).closed)}if(await ue({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(r=>se(r,"run_canceled")))).some(r=>!r.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const f=await O(e.node_id);return await W(f??e)}c(jn,"cancelRun");const Ne=200;async function Jn(e,t){if(typeof t!="string"||!t.trim())throw N("name is required","name");const s=t.trim();if(s.length>Ne)throw N(`name exceeds ${Ne} characters`,"name");const n=await Pe(e.node_id,{name:s});return n.window&&je(n.window,Be(n)),await W(n)}c(Jn,"renameRun");async function Yn(e,t={config:St,client:Rt}){await ue({run_id:e.node_id},"the run was deleted");const s=await F(async u=>(await u.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),(await u.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(m=>m.node_id)));if((await Promise.all(s.map(u=>se(u,"run_deleted",{deleting:!0})))).some(u=>!u.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=await x(s,async u=>{const m=await Ue(u);if(m.app===null)throw new Error(`run node missing during deletion: ${u}`);return m}),f=await(await A()).prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:u}of f)try{await ee().delete(u)}catch(m){if(!Je(m))throw m}const r=await F(async u=>{for(const E of s){const o=await He(u,E);o!==null&&o.deleted_at===null&&await qe(u,o)}const m=await vt([e.node_id],u);await u.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),await u.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const h=s.map(()=>"?").join(","),g=await u.prepareUncached(`SELECT message_id FROM messages WHERE sender_node_id IN (${h}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${h})`).all(...s,...s);await u.prepareUncached(`DELETE FROM deliveries WHERE destination_id IN (${h})`).run(...s);for(const{message_id:E}of g)await u.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(E,E);return m});for(const u of d)await $e(u);const{notifyRunDeleted:i}=await import("./events.js");return i(e.node_id),{uploads_pending:await Tt(r,t)}}c(Yn,"deleteRun");async function Tt(e,t){if(!e.length||!t.config())return e.length;let s;try{s=t.client()}catch{return e.length}const n=new Set,d=e.map(r=>s.deleteUpload(r).then(async()=>{await Nt(r),n.add(r)},()=>{}));let f;return await Promise.race([Promise.all(d),new Promise(r=>{f=setTimeout(r,t.budgetMs??Ot),f.unref?.()})]),clearTimeout(f),e.length-n.size}c(Tt,"deleteReleasedUploads");async function Gn(e,t,s){await q(e,t),await Z(e);const n=await F(async o=>{const p=await o.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e),y=new Map;for(const S of p)y.set(S.node_id,(await o.prepare("SELECT session_id FROM sessions WHERE node_id = ? GROUP BY session_id ORDER BY min(created_at)").all(S.node_id)).map(I=>I.session_id));const l=(await o.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e)).event_cursor-1,D=await o.prepare(`SELECT node_id, sequence_number FROM run_events
10
+ ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e],...t.sub===void 0?[]:[t.sub]),d=await _e(await x((await _e(n,async({node_id:i})=>!t.visible||await t.visible(i))).filter(({activity:i,node_id:u})=>!s||i<s.activity||i===s.activity&&u<s.id),async i=>({root:await O(i.node_id),activity:i.activity})),async({root:i})=>!t.status||await C(i)===t.status),f=d.slice(0,t.limit),r=f.at(-1);return{runs:await x(f,async({root:i})=>await W(i)),next:d.length>t.limit&&r?Buffer.from(JSON.stringify({activity:r.activity,id:r.root.node_id})).toString("base64url"):null}}c(Pn,"listRuns");async function Bn(e,t,s){const n=await q(e,t),d=c(async()=>await W(await q(e,t)),"read");return!s||ge.includes(await C(n))?await d():new Promise((f,r)=>{let i=c(()=>{},"unsubscribe");const u=c(()=>{clearTimeout(o),clearInterval(E),i()},"settle"),m=c(async()=>{u();try{f(await d())}catch(p){r(p)}},"finish"),h=c(async()=>{ge.includes(String((await d()).status))&&await m()},"check"),g=c(()=>{h().catch(p=>{u(),r(p)})},"run"),E=setInterval(g,250),o=setTimeout(()=>{m()},s*1e3);gt(e,g).then(p=>{i=p},p=>{u(),r(p)})})}c(Bn,"waitRun");const At=5;async function jn(e,t,s=we,n=!0,d,f=!0){const r=e.status==="canceled"||e.outcome_reason==="closed",i=e.grantee??"app:terminal",u=Q("sha256").update(JSON.stringify(["run.message",e.node_id,t,n,...n&&!f?["steer:false"]:[]])).digest("hex"),m=c(async g=>{const E=await O(e.node_id),o=await(await I()).prepare("SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(g.message_id));return E&&!r&&n&&!E.pi_pid&&o&&await j(e.node_id,{resume:!0,capacity:"freeze"}),g},"replay");if(d){const g=await H(i,k(e.sub,d),u);if(g)return m(g.response)}if(r)throw new R(409,"run_settled","canceled run cannot receive a message");const h=n&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;for(let g=1;;g++){const E=await s(e.node_id,i,t),o=await F(async p=>{if(d){const l=await H(i,k(e.sub,d),u,p);if(l)return{replayed:l.response}}if(E.uses.length){await wt(p,e.node_id);for(const l of E.uses)if(await Ot(e.node_id,l.path,p))return"path_taken"}await h?.(e.node_id);const y=await he(p,e.node_id,i,E,n,n&&f),a={run_id:e.node_id,message_id:y.messageId,sequence_number:y.sequence};return d&&await ye(p,i,k(e.sub,d),u,e.node_id,a,new Date().toISOString()),{result:a}});if(o==="path_taken"){if(g>=At)throw new R(503,"service_unavailable","attachments of concurrent messages kept taking each other's file names; retry");continue}return"replayed"in o?m(o.replayed):(n&&!e.pi_pid&&await j(e.node_id,{resume:!0,capacity:"freeze"}),o.result)}}c(jn,"messageRun");async function Tt(e){const t=c(()=>new R(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let s=0;s<2;s++){const n=await O(e);if(!n)throw G();if(!ae(n)){if(n.streaming)throw t();return}const d=(await K(e))?.executionId;try{await Ke(e)==="turn"&&pe({nodes:[e]});return}catch(f){if(!(f instanceof Ze))throw f;const r=await O(e);if(!r)throw G();if(!r.streaming)return;if(s===0&&ae(r)&&(await K(e))?.executionId!==d)continue;throw t()}}throw t()}c(Tt,"interruptNode");async function Jn(e,t="stop"){const s=t==="stop"?(await(await I()).prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id)).map(({node_id:n})=>n):[e.node_id];return await Promise.all(s.map(n=>Tt(n))),await W(await O(e.node_id)??e)}c(Jn,"interruptRun");async function Yn(e,t={}){const s=(await(await I()).prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(r=>r.node_id);pe({run:e.node_id});const n=[];if(await C(e)!=="settled")n.push(...(await de(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"})).closed);else for(const r of s){if(r===e.node_id)continue;const i=await O(r);i&&i.status!=="done"&&i.status!=="canceled"&&i.status!=="dead"&&n.push(...(await de(r,{preserveEmpty:!0,stopReason:"run_canceled"})).closed)}if(await ue({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(r=>se(r,"run_canceled")))).some(r=>!r.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const f=await O(e.node_id);return await W(f??e)}c(Yn,"cancelRun");const Ne=200;async function Gn(e,t){if(typeof t!="string"||!t.trim())throw N("name is required","name");const s=t.trim();if(s.length>Ne)throw N(`name exceeds ${Ne} characters`,"name");const n=await Pe(e.node_id,{name:s});return n.window&&je(n.window,Be(n)),await W(n)}c(Gn,"renameRun");async function Xn(e,t={config:Nt,client:St}){await ue({run_id:e.node_id},"the run was deleted");const s=await F(async u=>(await u.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),(await u.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(m=>m.node_id)));if((await Promise.all(s.map(u=>se(u,"run_deleted",{deleting:!0})))).some(u=>!u.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=await x(s,async u=>{const m=await Ue(u);if(m.app===null)throw new Error(`run node missing during deletion: ${u}`);return m}),f=await(await I()).prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:u}of f)try{await ee().delete(u)}catch(m){if(!Je(m))throw m}const r=await F(async u=>{for(const E of s){const o=await He(u,E);o!==null&&o.deleted_at===null&&await qe(u,o)}const m=await bt([e.node_id],u);await u.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),await u.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const h=s.map(()=>"?").join(","),g=await u.prepareUncached(`SELECT message_id FROM messages WHERE sender_node_id IN (${h}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${h})`).all(...s,...s);await u.prepareUncached(`DELETE FROM deliveries WHERE destination_id IN (${h})`).run(...s);for(const{message_id:E}of g)await u.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(E,E);return m});for(const u of d)await $e(u);const{notifyRunDeleted:i}=await import("./events.js");return i(e.node_id),{uploads_pending:await Lt(r,t)}}c(Xn,"deleteRun");async function Lt(e,t){if(!e.length||!t.config())return e.length;let s;try{s=t.client()}catch{return e.length}const n=new Set,d=e.map(r=>s.deleteUpload(r).then(async()=>{await vt(r),n.add(r)},()=>{}));let f;return await Promise.race([Promise.all(d),new Promise(r=>{f=setTimeout(r,t.budgetMs??Dt),f.unref?.()})]),clearTimeout(f),e.length-n.size}c(Lt,"deleteReleasedUploads");async function zn(e,t,s){await q(e,t),await Z(e);const n=await F(async o=>{const p=await o.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e),y=new Map;for(const S of p)y.set(S.node_id,(await o.prepare("SELECT session_id FROM sessions WHERE node_id = ? GROUP BY session_id ORDER BY min(created_at)").all(S.node_id)).map(A=>A.session_id));const l=(await o.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e)).event_cursor-1,D=await o.prepare(`SELECT node_id, sequence_number FROM run_events
11
11
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
12
12
  ORDER BY sequence_number`).all(e,l),v=await o.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
13
13
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
14
- ORDER BY sequence_number`).all(e,l);return{nodes:p,sessionIds:y,latestSequence:l,completed:D,deltas:v}}),{nodes:d,sessionIds:f,latestSequence:r,completed:i,deltas:u}=n,m=await x(d,async o=>({node_id:o.node_id,parent_node_id:o.parent,conversations:await x(f.get(o.node_id)??[],async p=>{const{header:y,entries:a}=await ee().read(p);if(s==="entries")return{conversation_id:p,header:y,entries:a};const l=Fe.inMemory(y.cwd,void 0,[y,...a]),D=ct(l)??[],v=new Map(a.map((w,b)=>[w.id,b])),S=a.filter(w=>w.type==="custom"&&w.customType==="crtr-system-prompt").map(w=>({id:w.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in w?w.data:void 0,timestamp:w.timestamp}})),I=a.filter(w=>w.type==="custom_message"&&w.customType==="app_message").map(w=>({id:w.id,message:{role:"custom",customType:"app_message",content:"content"in w?w.content:"",timestamp:w.timestamp}})),U=o.node_id===e?a.find(w=>{if(w.type!=="message"||w.message.role!=="user")return!1;const b=ie(a,w.message.timestamp);return b?.type==="runtime"&&b.kind==="kickoff"})?.id:void 0,ve=[...D.filter(({id:w})=>!I.some(b=>b.id===w)),...S,...I].sort((w,b)=>(v.get(w.id)??Number.MAX_SAFE_INTEGER)-(v.get(b.id)??Number.MAX_SAFE_INTEGER)).map(({id:w,message:b})=>{const _=b,T=_.usage,$=_.role==="user"?ie(a,Number(_.timestamp)):null,be=$?.type==="human"||w===U,L=_.role==="toolResult"?"tool_result":_.role==="bashExecution"?"bash_execution":_.role==="compactionSummary"?"compaction_summary":_.role==="branchSummary"?"branch_summary":_.role==="custom"&&_.customType==="crtr-system-prompt"?"system":_.role==="user"?be?"user":"custom":_.role,Oe=L==="custom"?_.role==="custom"?_.customType:$?.type==="runtime"?$.kind:"unknown":void 0,De=L==="system"&&_.customType==="crtr-system-prompt"?[{type:"text",text:_.data?.text??""}]:typeof _.content=="string"?[{type:"text",text:_.content}]:Array.isArray(_.content)?_.content.map(M=>M.type==="toolCall"?{type:"tool_call",tool_call_id:M.id,name:M.name,arguments:M.arguments}:M.type==="image"?{type:"image",mime_type:M.mimeType}:M.type==="thinking"?{type:"thinking",text:M.thinking}:M):[];return{entry_id:w,role:L,...L==="custom"?{custom_type:Oe}:{},time:typeof _.timestamp=="string"?_.timestamp:new Date(Number(_.timestamp??Date.now())).toISOString(),content:De,...L==="assistant"?{model:_.model,provider:_.provider,stop_reason:_.stopReason,..._.errorMessage?{error_message:_.errorMessage}:{},...T?{usage:{input_tokens:T.input??0,output_tokens:T.output??0,cache_read_tokens:T.cacheRead??0,cache_write_tokens:T.cacheWrite??0,cost_usd:T.cost?.total??0}}:{}}:{},...L==="tool_result"?{tool_call_id:_.toolCallId,tool_name:_.toolName,is_error:_.isError}:{}}})??[];return{conversation_id:p,messages:ve}})})),h=new Map(await Promise.all(m.map(async o=>[o.node_id,await ft(o.node_id)])));for(const o of i){const p=h.get(o.node_id);p!=null&&o.sequence_number>=p&&h.set(o.node_id,null)}const g=new Map;for(const o of u){const p=h.get(o.node_id);if(p==null||o.sequence_number<p)continue;const y=JSON.parse(o.body_json),a=g.get(o.node_id)??{thinking:"",text:""};o.type==="node.thinking.delta"?a.thinking+=y.delta:a.text+=y.delta,g.set(o.node_id,a)}const E=m.map(o=>({...o,in_progress_message:h.get(o.node_id)==null?null:g.get(o.node_id)??{thinking:"",text:""}}));return{run_id:e,latest_sequence:r,nodes:E}}c(Gn,"traceRun");function Xn(e,t,s){if(t===void 0){if(!e.some(n=>P(n,"crtr:llm")))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw N("scopes must be a list of scope strings","scopes");for(const n of t){try{pt(n)}catch{throw N(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))throw N(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))&&!Ae(e,n))throw new R(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}c(Xn,"requestedScopes");export{z as IDEMPOTENCY_WINDOW_MS,Mt as RUN_DEADLINE_MAX_MS,Ot as RUN_DELETE_STORAGE_BUDGET_MS,Ne as RUN_NAME_MAX,R as RunError,jn as cancelRun,Dt as cloudPersonScope,Yn as deleteRun,Fn as idempotencyKeyOf,Bn as interruptRun,Un as listRuns,Pn as messageRun,q as ownedRun,Se as parseRunDeadlineMs,qn as pruneExpiredIdempotencyKeys,Jn as renameRun,Xn as requestedScopes,Wn as runIsRunning,W as runObject,Hn as startRun,Gn as traceRun,$n as waitRun};
14
+ ORDER BY sequence_number`).all(e,l);return{nodes:p,sessionIds:y,latestSequence:l,completed:D,deltas:v}}),{nodes:d,sessionIds:f,latestSequence:r,completed:i,deltas:u}=n,m=await x(d,async o=>({node_id:o.node_id,parent_node_id:o.parent,conversations:await x(f.get(o.node_id)??[],async p=>{const{header:y,entries:a}=await ee().read(p);if(s==="entries")return{conversation_id:p,header:y,entries:a};const l=Fe.inMemory(y.cwd,void 0,[y,...a]),D=ut(l)??[],v=new Map(a.map((w,b)=>[w.id,b])),S=a.filter(w=>w.type==="custom"&&w.customType==="crtr-system-prompt").map(w=>({id:w.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in w?w.data:void 0,timestamp:w.timestamp}})),A=a.filter(w=>w.type==="custom_message"&&w.customType==="app_message").map(w=>({id:w.id,message:{role:"custom",customType:"app_message",content:"content"in w?w.content:"",timestamp:w.timestamp}})),U=o.node_id===e?a.find(w=>{if(w.type!=="message"||w.message.role!=="user")return!1;const b=ie(a,w.message.timestamp);return b?.type==="runtime"&&b.kind==="kickoff"})?.id:void 0,ve=[...D.filter(({id:w})=>!A.some(b=>b.id===w)),...S,...A].sort((w,b)=>(v.get(w.id)??Number.MAX_SAFE_INTEGER)-(v.get(b.id)??Number.MAX_SAFE_INTEGER)).map(({id:w,message:b})=>{const _=b,T=_.usage,$=_.role==="user"?ie(a,Number(_.timestamp)):null,be=$?.type==="human"||w===U,L=_.role==="toolResult"?"tool_result":_.role==="bashExecution"?"bash_execution":_.role==="compactionSummary"?"compaction_summary":_.role==="branchSummary"?"branch_summary":_.role==="custom"&&_.customType==="crtr-system-prompt"?"system":_.role==="user"?be?"user":"custom":_.role,Oe=L==="custom"?_.role==="custom"?_.customType:$?.type==="runtime"?$.kind:"unknown":void 0,De=L==="system"&&_.customType==="crtr-system-prompt"?[{type:"text",text:_.data?.text??""}]:typeof _.content=="string"?[{type:"text",text:_.content}]:Array.isArray(_.content)?_.content.map(M=>M.type==="toolCall"?{type:"tool_call",tool_call_id:M.id,name:M.name,arguments:M.arguments}:M.type==="image"?{type:"image",mime_type:M.mimeType}:M.type==="thinking"?{type:"thinking",text:M.thinking}:M):[];return{entry_id:w,role:L,...L==="custom"?{custom_type:Oe}:{},time:typeof _.timestamp=="string"?_.timestamp:new Date(Number(_.timestamp??Date.now())).toISOString(),content:De,...L==="assistant"?{model:_.model,provider:_.provider,stop_reason:_.stopReason,..._.errorMessage?{error_message:_.errorMessage}:{},...T?{usage:{input_tokens:T.input??0,output_tokens:T.output??0,cache_read_tokens:T.cacheRead??0,cache_write_tokens:T.cacheWrite??0,cost_usd:T.cost?.total??0}}:{}}:{},...L==="tool_result"?{tool_call_id:_.toolCallId,tool_name:_.toolName,is_error:_.isError}:{}}})??[];return{conversation_id:p,messages:ve}})})),h=new Map(await Promise.all(m.map(async o=>[o.node_id,await pt(o.node_id)])));for(const o of i){const p=h.get(o.node_id);p!=null&&o.sequence_number>=p&&h.set(o.node_id,null)}const g=new Map;for(const o of u){const p=h.get(o.node_id);if(p==null||o.sequence_number<p)continue;const y=JSON.parse(o.body_json),a=g.get(o.node_id)??{thinking:"",text:""};o.type==="node.thinking.delta"?a.thinking+=y.delta:a.text+=y.delta,g.set(o.node_id,a)}const E=m.map(o=>({...o,in_progress_message:h.get(o.node_id)==null?null:g.get(o.node_id)??{thinking:"",text:""}}));return{run_id:e,latest_sequence:r,nodes:E}}c(zn,"traceRun");function Qn(e,t,s){if(t===void 0){if(!e.some(n=>P(n,"crtr:llm")))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw N("scopes must be a list of scope strings","scopes");for(const n of t){try{_t(n)}catch{throw N(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))throw N(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))&&!Ie(e,n))throw new R(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}c(Qn,"requestedScopes");export{z as IDEMPOTENCY_WINDOW_MS,It as RUN_DEADLINE_MAX_MS,Dt as RUN_DELETE_STORAGE_BUDGET_MS,Ne as RUN_NAME_MAX,R as RunError,Yn as cancelRun,Mt as cloudPersonScope,Xn as deleteRun,Hn as idempotencyKeyOf,Jn as interruptRun,Pn as listRuns,jn as messageRun,q as ownedRun,Se as parseRunDeadlineMs,Un as pruneExpiredIdempotencyKeys,Gn as renameRun,Qn as requestedScopes,qn as runIsRunning,W as runObject,$n as startRun,zn as traceRun,Bn as waitRun};
@@ -2,7 +2,7 @@ import { type AssistantMessageEventStream, type Context, type Model, type Models
2
2
  import type { ModelRuntime } from '@earendil-works/pi-coding-agent';
3
3
  /** Pi uses availability and auth for its model controls; only the daemon can
4
4
  * decide whether a route has credentials. Keep the broker's metadata selectable. */
5
- export declare function configureBrokerModelRuntime(runtime: ModelRuntime, intent?: string): void;
5
+ export declare function configureBrokerModelRuntime(runtime: ModelRuntime, intent?: string, causedBy?: string): void;
6
6
  export declare const LLM_BROKER_RETRY_WINDOW_S = 300;
7
7
  export declare const LLM_REFUSAL_DIAGNOSTIC = "crtr:llm-refusal";
8
8
  /** The retry deadline (epoch ms) a final daemon refusal carried on its
@@ -23,5 +23,5 @@ export declare function requestBody(model: Model<any>, context: Context, options
23
23
  /** The real response under a deferred-head framing (`daemon/api/deferred-head.ts`): the magic line, keep-alive
24
24
  * blank lines, one JSON head line, then the body unchanged. Any other response is returned as it is. */
25
25
  export declare function unwrapDeferredHead(response: Response): Promise<Response>;
26
- /** One pi stream, backed exclusively by the authenticated daemon llm route. `intent` replaces the node's own `CRTR_MODEL_INTENT` for one stream: a background one-shot of an app-paid node asks for `app/light`, not the node's rung. */
27
- export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions, intent?: string): AssistantMessageEventStream;
26
+ /** One pi stream, backed exclusively by the authenticated daemon llm route. `intent` replaces the node's own `CRTR_MODEL_INTENT` for one stream: a background one-shot of an app-paid node asks for `app/light`, not the node's rung. `causedBy` is the cause a one-shot helper captured when it was dispatched; the main stream reads the live turn's at call time. */
27
+ export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions, intent?: string, causedBy?: string): AssistantMessageEventStream;
@@ -1,3 +1,3 @@
1
- var J=Object.defineProperty;var d=(e,n)=>J(e,"name",{value:n,configurable:!0});import{setTimeout as Y}from"node:timers/promises";import{createAssistantMessageEventStream as z,getCurrentSystemPrompt as G,getCurrentTools as X}from"@earendil-works/pi-ai";import{socketFetch as K}from"../../../api/node-transport.js";import{DEFER_HEAD_REQUEST_HEADER as Q,DEFERRED_HEAD_CONTENT_TYPE as V,DEFERRED_HEAD_MAGIC as Z}from"../../../daemon/api/deferred-head.js";import{apiSocketPath as ee}from"../../canvas/paths.js";import{northlightUnreachable as te}from"../../directory/reach.js";import{currentNodeToken as ne}from"./node-token.js";import{brokerApiUrl as A}from"./daemon-ops.js";import{currentCausedBy as re}from"./turn-cause.js";import{envModelExact as U,envModelIntent as oe}from"../../../shared/env.js";import{MODEL_CONTEXT_BODY_MAX_BYTES as S}from"../../llm/body-limits.js";import{modelRequestFromConfig as se}from"../../model-routes.js";import{parseProviderRateLimit as ie,providerFailureDiagnostic as T}from"../../provider-failure.js";import{UPSTREAM_MODEL_UNAVAILABLE as D}from"../../fault-classifier.js";function De(e,n){e.checkAuth=async t=>e.getProvider(t)?{type:"api_key"}:void 0,e.getAvailable=async t=>e.getModels(t),e.getAvailableSnapshot=()=>e.getModels(),e.streamSimple=(t,u,o)=>pe(t,u,o,n)}d(De,"configureBrokerModelRuntime");const ae=300,q="crtr:llm-refusal";class k extends Error{static{d(this,"LlmRefusalError")}retryAt;rateLimit;code;status;constructor(n,t,u,o,r){super(n),this.retryAt=t,this.rateLimit=u,this.code=o,this.status=r}}class R extends Error{static{d(this,"UpstreamModelUnavailableError")}}function B(e,n){const t=e===void 0?"the request body":`the request body (${e} bytes)`;return new Error(`request_too_large: ${t} exceeds the ${n}-byte model request limit; compact the conversation to shrink the context`)}d(B,"contextTooLargeError");function L(e){const n=e.details?.rate_limit;if(!n||typeof n!="object")return;const t=ie(n);if(t===void 0)return;const{provider:u,model:o}=n;return typeof u=="string"&&u!==""&&typeof o=="string"&&o!==""?{...t,model:`${u}/${o}`}:t}d(L,"refusalRateLimit");function Le(e){for(const n of e.diagnostics??[]){if(n.type!==q)continue;const t=n.details?.retryAt;if(typeof t=="number"&&Number.isFinite(t)&&t>0)return t}}d(Le,"refusalRetryAt");class F extends Error{static{d(this,"ContentFilteredError")}}function P(e){return typeof e=="string"?e:e.map(n=>n.type==="text"?{type:"text",text:n.text}:{type:"image_url",image_url:{url:`data:${n.mimeType};base64,${n.data}`}})}d(P,"wireContent");function ce(e){const n=d(o=>o.role==="assistant"&&(o.stopReason==="error"||o.stopReason==="aborted"),"incomplete"),t=e.some(n)?e.filter(o=>!n(o)):e;let u=t.length;for(;u>0&&t[u-1]?.role==="assistant";)u--;return u===t.length?t:t.slice(0,u)}d(ce,"wireHistory");function le(e,n,t,u){const o=[],r=G(n.messages),i=X(n.messages);r?o.push({role:"system",content:r}):n.systemPrompt&&o.push({role:"system",content:n.systemPrompt});for(const f of ce(n.messages))f.role==="user"?o.push({role:"user",content:P(f.content)}):f.role==="toolResult"?o.push({role:"tool",content:P(f.content),tool_call_id:f.toolCallId}):f.role==="assistant"&&o.push({role:"assistant",content:f.content.filter(c=>c.type==="text").map(c=>c.text).join("")||null,tool_calls:f.content.filter(c=>c.type==="toolCall").map(c=>({id:c.id,type:"function",function:{name:c.name,arguments:JSON.stringify(c.arguments)}}))});const _=`${e.provider}/${e.id}`,y=u??oe();return{model:se(_,y,U())?.kind==="logical"?y:_,model_policy:U()?"exact":"substitute",stream:!0,messages:o,...i.length?{tools:i.map(f=>({type:"function",function:{name:f.name,description:f.description,parameters:f.parameters}}))}:{},...t.reasoning?{reasoning_effort:t.reasoning}:{},...t.temperature!==void 0?{temperature:t.temperature}:{},...t.maxTokens!==void 0?{max_tokens:t.maxTokens}:{}}}d(le,"requestBody");function O(e,n){if(typeof n!="string")return!1;const t=n.indexOf("/");return t<1||t===n.length-1?!1:(e.provider=n.slice(0,t),e.model=n.slice(t+1),!0)}d(O,"applyServedModel");function H(e){if(e.details?.served_model!==void 0)return e.details.served_model;const n=e.details?.rate_limit;return typeof n?.provider=="string"&&typeof n.model=="string"?`${n.provider}/${n.model}`:void 0}d(H,"refusalRoute");function j(e){if(!e||typeof e!="object"||!("error"in e))throw new Error("llm returned an invalid response");const n=e.error;if(!n||typeof n.message!="string")throw new Error("llm returned an invalid refusal");return n}d(j,"parseRefusal");function W(){const e=A();return e===void 0?"http://localhost/v1/llm":new URL("/v1/llm",e).toString()}d(W,"llmUrl");function de(){return A()===void 0?K(ee()):globalThis.fetch}d(de,"llmFetch");async function ue(e){if(!e.headers.get("content-type")?.startsWith(V))return e;if(!e.body)throw new Error("deferred head response has no body");const n=e.body.getReader();let t=new Uint8Array(0),u=!1;for(;;){const o=t.indexOf(10);if(o<0){const{value:c,done:p}=await n.read();if(p)throw new Error("deferred head response ended before its head");const w=new Uint8Array(t.length+c.length);w.set(t),w.set(c,t.length),t=w;continue}const r=new TextDecoder().decode(t.subarray(0,o)).trim();if(t=t.subarray(o+1),!u){if(`${r}
2
- `!==Z)throw new Error("deferred head response has no magic line");u=!0;continue}if(r==="")continue;const i=JSON.parse(r),_=new Headers;for(const[c,p]of Object.entries(i.headers))for(const w of Array.isArray(p)?p:[p])_.append(c,w);const y=t,f=new ReadableStream({start(c){y.length>0&&c.enqueue(y)},async pull(c){const{value:p,done:w}=await n.read();w?c.close():c.enqueue(p)},cancel(c){return n.cancel(c)}});return new Response(i.status===204?null:f,{status:i.status,headers:_})}}d(ue,"unwrapDeferredHead");function fe(){const e=re();return e===void 0?{}:{"crtr-caused-by":e}}d(fe,"causedByHeader");function pe(e,n,t={},u){const o=z(),r={role:"assistant",content:[],api:e.api,provider:e.provider,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};return(async()=>{const i=ne();if(!i)throw new Error("llm requires a node token");const _=JSON.stringify(le(e,n,t,u)),y=Buffer.byteLength(_);if(y>S)throw B(y,S);let f=0;for(;;){t.signal?.throwIfAborted();const c=await de()(W(),{method:"POST",headers:{authorization:`Bearer ${i}`,"content-type":"application/json",[Q]:"1",...fe()},body:_,signal:t.signal}).catch(l=>{const s=W();throw A()===void 0||t.signal?.aborted?l:new R(te(l,s).message)}),p=await ue(c);if(!p.ok){const l=j(await p.json());if(p.status===413||l.code==="payload_too_large")throw B(y,S);if(O(r,H(l)),l.retryable!==!0)throw new k(l.message,void 0,L(l),l.code,p.status);const s=l.retry_after_s;if(typeof s!="number"||!Number.isFinite(s)||s<=0)throw l.code===D?new R(l.message):new Error(l.message);const h=ae-f;if(s>h){const m=Date.now()+s*1e3;throw new k(`${l.message} (retry after ${s}s, at ${new Date(m).toISOString()})`,m,L(l))}await Y(s*1e3,void 0,{signal:t.signal}),f+=s;continue}if(!p.body)throw new Error("llm returned no stream");o.push({type:"start",partial:r});const w=p.body.getReader(),I=new TextDecoder;let x="",b="stop",M,$=!1,C=!1;const N=d(l=>{const s=JSON.parse(l);if(s.error){const a=j(s);throw O(r,H(a)),a.retryable!==!0?new k(a.message,void 0,L(a),a.code):a.code===D?new R(a.message):new Error(a.message)}if(s.served_model){if(C=!0,s.served_model.indexOf("/")<1)throw new Error("llm returned an invalid served_model");O(r,s.served_model)}const h=s.choices?.[0],m=h?.delta;if(m?.reasoning_content){const a=r.content.findIndex(v=>v.type==="thinking"),g=a<0?{type:"thinking",thinking:""}:r.content[a],E=a<0?r.content.push(g)-1:a;if(a<0&&o.push({type:"thinking_start",contentIndex:E,partial:r}),g.type!=="thinking")throw new Error("invalid thinking block");g.thinking+=m.reasoning_content,o.push({type:"thinking_delta",contentIndex:E,delta:m.reasoning_content,partial:r})}if(m?.content){const a=r.content.findIndex(v=>v.type==="text"),g=a<0?{type:"text",text:""}:r.content[a],E=a<0?r.content.push(g)-1:a;if(a<0&&o.push({type:"text_start",contentIndex:E,partial:r}),g.type!=="text")throw new Error("invalid text block");g.text+=m.content,o.push({type:"text_delta",contentIndex:E,delta:m.content,partial:r})}for(const a of m?.tool_calls??[]){const g={type:"toolCall",id:a.id,name:a.function.name,arguments:JSON.parse(a.function.arguments)},E=r.content.push(g)-1;o.push({type:"toolcall_start",contentIndex:E,partial:r}),o.push({type:"toolcall_end",contentIndex:E,toolCall:g,partial:r})}h?.finish_reason&&(b=h.finish_reason),h?.message?.refusal&&(M=h.message.refusal),s.usage&&($=!0,r.usage={input:s.usage.prompt_tokens,output:s.usage.completion_tokens,cacheRead:s.usage.cache_read_tokens,cacheWrite:s.usage.cache_write_tokens,totalTokens:s.usage.total_tokens,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:typeof s.usage.usd_equivalent=="number"&&Number.isFinite(s.usage.usd_equivalent)?s.usage.usd_equivalent:0}})},"apply");for(;;){const{value:l,done:s}=await w.read();if(s)break;x+=I.decode(l,{stream:!0});let h;for(;(h=x.indexOf(`
3
- `))>=0;){const m=x.slice(0,h).trim();x=x.slice(h+1),m&&N(m)}}if(x+=I.decode(),x.trim()&&N(x.trim()),!$||!C)throw new Error("llm stream ended without usage or served_model");for(const[l,s]of r.content.entries())s.type==="text"&&o.push({type:"text_end",contentIndex:l,content:s.text,partial:r}),s.type==="thinking"&&o.push({type:"thinking_end",contentIndex:l,content:s.thinking,partial:r});if(b==="content_filter")throw new F(M??"Content filtered");if(!["stop","tool_calls","length"].includes(b))throw new Error(`llm returned unknown finish reason: ${b}`);r.stopReason=b==="tool_calls"?"toolUse":b==="length"?"length":"stop",o.push({type:"done",reason:r.stopReason,message:r}),o.end();return}})().catch(i=>{r.stopReason=t.signal?.aborted?"aborted":"error",r.errorMessage=i instanceof Error?i.message:String(i),i instanceof k&&(r.diagnostics=[{type:q,timestamp:Date.now(),...i.retryAt!==void 0?{details:{retryAt:i.retryAt}}:{}},...i.rateLimit!==void 0?[T({status:429,ratelimit:i.rateLimit})]:[],...i.rateLimit===void 0&&i.code==="cap_exhausted"?[T({status:i.status??402,code:i.code})]:[]]),i instanceof R&&(r.diagnostics=[T({status:503,code:D})]),i instanceof F&&r.stopReason==="error"&&(r.rawStopReason="content_filter"),o.push({type:"error",reason:r.stopReason,error:r}),o.end()}),o}d(pe,"streamBrokerModel");export{ae as LLM_BROKER_RETRY_WINDOW_S,q as LLM_REFUSAL_DIAGNOSTIC,De as configureBrokerModelRuntime,Le as refusalRetryAt,le as requestBody,pe as streamBrokerModel,ue as unwrapDeferredHead,ce as wireHistory};
1
+ var Y=Object.defineProperty;var f=(e,t)=>Y(e,"name",{value:t,configurable:!0});import{setTimeout as z}from"node:timers/promises";import{createAssistantMessageEventStream as G,getCurrentSystemPrompt as X,getCurrentTools as K}from"@earendil-works/pi-ai";import{socketFetch as Q}from"../../../api/node-transport.js";import{DEFER_HEAD_REQUEST_HEADER as V,DEFERRED_HEAD_CONTENT_TYPE as Z,DEFERRED_HEAD_MAGIC as ee}from"../../../daemon/api/deferred-head.js";import{apiSocketPath as te}from"../../canvas/paths.js";import{northlightUnreachable as ne}from"../../directory/reach.js";import{currentNodeToken as re}from"./node-token.js";import{brokerApiUrl as A}from"./daemon-ops.js";import{currentCausedBy as oe}from"./turn-cause.js";import{envModelExact as U,envModelIntent as se}from"../../../shared/env.js";import{MODEL_CONTEXT_BODY_MAX_BYTES as S}from"../../llm/body-limits.js";import{modelRequestFromConfig as ie}from"../../model-routes.js";import{parseProviderRateLimit as ae,providerFailureDiagnostic as T}from"../../provider-failure.js";import{UPSTREAM_MODEL_UNAVAILABLE as D}from"../../fault-classifier.js";function Le(e,t,n){e.checkAuth=async a=>e.getProvider(a)?{type:"api_key"}:void 0,e.getAvailable=async a=>e.getModels(a),e.getAvailableSnapshot=()=>e.getModels(),e.streamSimple=(a,s,i)=>me(a,s,i,t,n)}f(Le,"configureBrokerModelRuntime");const ce=300,q="crtr:llm-refusal";class k extends Error{static{f(this,"LlmRefusalError")}retryAt;rateLimit;code;status;constructor(t,n,a,s,i){super(t),this.retryAt=n,this.rateLimit=a,this.code=s,this.status=i}}class R extends Error{static{f(this,"UpstreamModelUnavailableError")}}function B(e,t){const n=e===void 0?"the request body":`the request body (${e} bytes)`;return new Error(`request_too_large: ${n} exceeds the ${t}-byte model request limit; compact the conversation to shrink the context`)}f(B,"contextTooLargeError");function L(e){const t=e.details?.rate_limit;if(!t||typeof t!="object")return;const n=ae(t);if(n===void 0)return;const{provider:a,model:s}=t;return typeof a=="string"&&a!==""&&typeof s=="string"&&s!==""?{...n,model:`${a}/${s}`}:n}f(L,"refusalRateLimit");function Oe(e){for(const t of e.diagnostics??[]){if(t.type!==q)continue;const n=t.details?.retryAt;if(typeof n=="number"&&Number.isFinite(n)&&n>0)return n}}f(Oe,"refusalRetryAt");class F extends Error{static{f(this,"ContentFilteredError")}}function P(e){return typeof e=="string"?e:e.map(t=>t.type==="text"?{type:"text",text:t.text}:{type:"image_url",image_url:{url:`data:${t.mimeType};base64,${t.data}`}})}f(P,"wireContent");function le(e){const t=f(s=>s.role==="assistant"&&(s.stopReason==="error"||s.stopReason==="aborted"),"incomplete"),n=e.some(t)?e.filter(s=>!t(s)):e;let a=n.length;for(;a>0&&n[a-1]?.role==="assistant";)a--;return a===n.length?n:n.slice(0,a)}f(le,"wireHistory");function de(e,t,n,a){const s=[],i=X(t.messages),r=K(t.messages);i?s.push({role:"system",content:i}):t.systemPrompt&&s.push({role:"system",content:t.systemPrompt});for(const p of le(t.messages))p.role==="user"?s.push({role:"user",content:P(p.content)}):p.role==="toolResult"?s.push({role:"tool",content:P(p.content),tool_call_id:p.toolCallId}):p.role==="assistant"&&s.push({role:"assistant",content:p.content.filter(c=>c.type==="text").map(c=>c.text).join("")||null,tool_calls:p.content.filter(c=>c.type==="toolCall").map(c=>({id:c.id,type:"function",function:{name:c.name,arguments:JSON.stringify(c.arguments)}}))});const d=`${e.provider}/${e.id}`,_=a??se();return{model:ie(d,_,U())?.kind==="logical"?_:d,model_policy:U()?"exact":"substitute",stream:!0,messages:s,...r.length?{tools:r.map(p=>({type:"function",function:{name:p.name,description:p.description,parameters:p.parameters}}))}:{},...n.reasoning?{reasoning_effort:n.reasoning}:{},...n.temperature!==void 0?{temperature:n.temperature}:{},...n.maxTokens!==void 0?{max_tokens:n.maxTokens}:{}}}f(de,"requestBody");function O(e,t){if(typeof t!="string")return!1;const n=t.indexOf("/");return n<1||n===t.length-1?!1:(e.provider=t.slice(0,n),e.model=t.slice(n+1),!0)}f(O,"applyServedModel");function H(e){if(e.details?.served_model!==void 0)return e.details.served_model;const t=e.details?.rate_limit;return typeof t?.provider=="string"&&typeof t.model=="string"?`${t.provider}/${t.model}`:void 0}f(H,"refusalRoute");function j(e){if(!e||typeof e!="object"||!("error"in e))throw new Error("llm returned an invalid response");const t=e.error;if(!t||typeof t.message!="string")throw new Error("llm returned an invalid refusal");return t}f(j,"parseRefusal");function W(){const e=A();return e===void 0?"http://localhost/v1/llm":new URL("/v1/llm",e).toString()}f(W,"llmUrl");function ue(){return A()===void 0?Q(te()):globalThis.fetch}f(ue,"llmFetch");async function fe(e){if(!e.headers.get("content-type")?.startsWith(Z))return e;if(!e.body)throw new Error("deferred head response has no body");const t=e.body.getReader();let n=new Uint8Array(0),a=!1;for(;;){const s=n.indexOf(10);if(s<0){const{value:c,done:w}=await t.read();if(w)throw new Error("deferred head response ended before its head");const m=new Uint8Array(n.length+c.length);m.set(n),m.set(c,n.length),n=m;continue}const i=new TextDecoder().decode(n.subarray(0,s)).trim();if(n=n.subarray(s+1),!a){if(`${i}
2
+ `!==ee)throw new Error("deferred head response has no magic line");a=!0;continue}if(i==="")continue;const r=JSON.parse(i),d=new Headers;for(const[c,w]of Object.entries(r.headers))for(const m of Array.isArray(w)?w:[w])d.append(c,m);const _=n,p=new ReadableStream({start(c){_.length>0&&c.enqueue(_)},async pull(c){const{value:w,done:m}=await t.read();m?c.close():c.enqueue(w)},cancel(c){return t.cancel(c)}});return new Response(r.status===204?null:p,{status:r.status,headers:d})}}f(fe,"unwrapDeferredHead");function pe(e){const t=e??oe();return t===void 0?{}:{"crtr-caused-by":t}}f(pe,"causedByHeader");function me(e,t,n={},a,s){const i=G(),r={role:"assistant",content:[],api:e.api,provider:e.provider,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};return(async()=>{const d=re();if(!d)throw new Error("llm requires a node token");const _=JSON.stringify(de(e,t,n,a)),p=Buffer.byteLength(_);if(p>S)throw B(p,S);let c=0;for(;;){n.signal?.throwIfAborted();const w=await ue()(W(),{method:"POST",headers:{authorization:`Bearer ${d}`,"content-type":"application/json",[V]:"1",...pe(s)},body:_,signal:n.signal}).catch(u=>{const o=W();throw A()===void 0||n.signal?.aborted?u:new R(ne(u,o).message)}),m=await fe(w);if(!m.ok){const u=j(await m.json());if(m.status===413||u.code==="payload_too_large")throw B(p,S);if(O(r,H(u)),u.retryable!==!0)throw new k(u.message,void 0,L(u),u.code,m.status);const o=u.retry_after_s;if(typeof o!="number"||!Number.isFinite(o)||o<=0)throw u.code===D?new R(u.message):new Error(u.message);const g=ce-c;if(o>g){const h=Date.now()+o*1e3;throw new k(`${u.message} (retry after ${o}s, at ${new Date(h).toISOString()})`,h,L(u))}await z(o*1e3,void 0,{signal:n.signal}),c+=o;continue}if(!m.body)throw new Error("llm returned no stream");i.push({type:"start",partial:r});const J=m.body.getReader(),I=new TextDecoder;let x="",b="stop",M,$=!1,C=!1;const N=f(u=>{const o=JSON.parse(u);if(o.error){const l=j(o);throw O(r,H(l)),l.retryable!==!0?new k(l.message,void 0,L(l),l.code):l.code===D?new R(l.message):new Error(l.message)}if(o.served_model){if(C=!0,o.served_model.indexOf("/")<1)throw new Error("llm returned an invalid served_model");O(r,o.served_model)}const g=o.choices?.[0],h=g?.delta;if(h?.reasoning_content){const l=r.content.findIndex(v=>v.type==="thinking"),y=l<0?{type:"thinking",thinking:""}:r.content[l],E=l<0?r.content.push(y)-1:l;if(l<0&&i.push({type:"thinking_start",contentIndex:E,partial:r}),y.type!=="thinking")throw new Error("invalid thinking block");y.thinking+=h.reasoning_content,i.push({type:"thinking_delta",contentIndex:E,delta:h.reasoning_content,partial:r})}if(h?.content){const l=r.content.findIndex(v=>v.type==="text"),y=l<0?{type:"text",text:""}:r.content[l],E=l<0?r.content.push(y)-1:l;if(l<0&&i.push({type:"text_start",contentIndex:E,partial:r}),y.type!=="text")throw new Error("invalid text block");y.text+=h.content,i.push({type:"text_delta",contentIndex:E,delta:h.content,partial:r})}for(const l of h?.tool_calls??[]){const y={type:"toolCall",id:l.id,name:l.function.name,arguments:JSON.parse(l.function.arguments)},E=r.content.push(y)-1;i.push({type:"toolcall_start",contentIndex:E,partial:r}),i.push({type:"toolcall_end",contentIndex:E,toolCall:y,partial:r})}g?.finish_reason&&(b=g.finish_reason),g?.message?.refusal&&(M=g.message.refusal),o.usage&&($=!0,r.usage={input:o.usage.prompt_tokens,output:o.usage.completion_tokens,cacheRead:o.usage.cache_read_tokens,cacheWrite:o.usage.cache_write_tokens,totalTokens:o.usage.total_tokens,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:typeof o.usage.usd_equivalent=="number"&&Number.isFinite(o.usage.usd_equivalent)?o.usage.usd_equivalent:0}})},"apply");for(;;){const{value:u,done:o}=await J.read();if(o)break;x+=I.decode(u,{stream:!0});let g;for(;(g=x.indexOf(`
3
+ `))>=0;){const h=x.slice(0,g).trim();x=x.slice(g+1),h&&N(h)}}if(x+=I.decode(),x.trim()&&N(x.trim()),!$||!C)throw new Error("llm stream ended without usage or served_model");for(const[u,o]of r.content.entries())o.type==="text"&&i.push({type:"text_end",contentIndex:u,content:o.text,partial:r}),o.type==="thinking"&&i.push({type:"thinking_end",contentIndex:u,content:o.thinking,partial:r});if(b==="content_filter")throw new F(M??"Content filtered");if(!["stop","tool_calls","length"].includes(b))throw new Error(`llm returned unknown finish reason: ${b}`);r.stopReason=b==="tool_calls"?"toolUse":b==="length"?"length":"stop",i.push({type:"done",reason:r.stopReason,message:r}),i.end();return}})().catch(d=>{r.stopReason=n.signal?.aborted?"aborted":"error",r.errorMessage=d instanceof Error?d.message:String(d),d instanceof k&&(r.diagnostics=[{type:q,timestamp:Date.now(),...d.retryAt!==void 0?{details:{retryAt:d.retryAt}}:{}},...d.rateLimit!==void 0?[T({status:429,ratelimit:d.rateLimit})]:[],...d.rateLimit===void 0&&d.code==="cap_exhausted"?[T({status:d.status??402,code:d.code})]:[]]),d instanceof R&&(r.diagnostics=[T({status:503,code:D})]),d instanceof F&&r.stopReason==="error"&&(r.rawStopReason="content_filter"),i.push({type:"error",reason:r.stopReason,error:r}),i.end()}),i}f(me,"streamBrokerModel");export{ce as LLM_BROKER_RETRY_WINDOW_S,q as LLM_REFUSAL_DIAGNOSTIC,Le as configureBrokerModelRuntime,Oe as refusalRetryAt,de as requestBody,me as streamBrokerModel,fe as unwrapDeferredHead,le as wireHistory};
@@ -1,5 +1,3 @@
1
1
  import type { MailEntryDTO } from '../../../api/dto/mail.js';
2
- /** A message whose body overflowed the digest carries the full text in its row (`data.body_full`) and names a path as
3
- * its `ref`. The broker writes the text at that path in its own filesystem so the agent reads it as it always has,
4
- * and drops the copy from the entry it renders. */
5
- export declare function materializeSpilledBody(entry: MailEntryDTO): MailEntryDTO;
2
+ /** Materialize overflow text in the broker's writable node folder, not the daemon's runtime records. */
3
+ export declare function materializeSpilledBody(entry: MailEntryDTO, nodeId: string): MailEntryDTO;
@@ -1 +1 @@
1
- var t=Object.defineProperty;var f=(i,r)=>t(i,"name",{value:r,configurable:!0});import{mkdirSync as d,writeFileSync as l}from"node:fs";import{dirname as o}from"node:path";function c(i){const r=i.data?.body_full;if(typeof r!="string"||i.ref===void 0||!i.ref.startsWith("/"))return i;d(o(i.ref),{recursive:!0}),l(i.ref,r,"utf8");const{body_full:a,...e}=i.data;return{...i,data:e}}f(c,"materializeSpilledBody");export{c as materializeSpilledBody};
1
+ var a=Object.defineProperty;var t=(e,i)=>a(e,"name",{value:i,configurable:!0});import{mkdirSync as d,writeFileSync as l}from"node:fs";import{basename as s,dirname as m,join as n}from"node:path";import{nodeAgentDir as u}from"../../canvas/paths.js";function _(e,i){const o=e.data?.body_full;if(typeof o!="string"||e.ref===void 0||!e.ref.startsWith("/"))return e;const r=n(u(i),"messages",s(e.ref));d(m(r),{recursive:!0}),l(r,o,"utf8");const{body_full:c,...f}=e.data;return{...e,ref:r,data:f}}t(_,"materializeSpilledBody");export{_ as materializeSpilledBody};
@@ -4,4 +4,8 @@ type Branch = ReturnType<BrokerSession['sessionManager']['getBranch']>;
4
4
  export declare function turnCauseOf(branch: Branch): string | undefined;
5
5
  /** `message:<id>` of the turn running now, or undefined. */
6
6
  export declare function currentCausedBy(): string | undefined;
7
+ /** The cause a one-shot helper call dispatched now belongs to: the turn whose input entry is staged and whose prompt has not
8
+ * reached the session yet (a helper started by that prompt's own input event runs before its user entry exists), else the
9
+ * running or latest turn's. Read once at dispatch, so a helper that outlives its turn keeps that turn's cause. */
10
+ export declare function currentOrPendingCausedBy(): string | undefined;
7
11
  export {};
@@ -1 +1 @@
1
- var f=Object.defineProperty;var r=(s,e)=>f(s,"name",{value:e,configurable:!0});let u;function c(s){u=s}r(c,"setTurnCauseSource");function a(s){let e=[],t;for(const n of s)if(n.type==="custom"&&n.customType==="crtr-turn-input"){const i=n.data?.message_ids;Array.isArray(i)&&e.push(...i.filter(o=>typeof o=="string"))}else(n.type==="message"&&n.message.role==="user"||n.type==="custom_message")&&(e.length>0?(t=e[0],e=[]):t=void 0);return t===void 0?void 0:`message:${t}`}r(a,"turnCauseOf");function p(){return u===void 0?void 0:a(u().sessionManager.getBranch())}r(p,"currentCausedBy");export{p as currentCausedBy,c as setTurnCauseSource,a as turnCauseOf};
1
+ var a=Object.defineProperty;var r=(n,e)=>a(n,"name",{value:e,configurable:!0});let u;function g(n){u=n}r(g,"setTurnCauseSource");function d(n){let e=[],s;for(const t of n)if(t.type==="custom"&&t.customType==="crtr-turn-input"){const i=t.data?.message_ids;Array.isArray(i)&&e.push(...i.filter(o=>typeof o=="string"))}else(t.type==="message"&&t.message.role==="user"||t.type==="custom_message")&&(e.length>0?(s=e[0],e=[]):s=void 0);return{cause:s,pending:e}}r(d,"causeAndPending");function f(n){const{cause:e}=d(n);return e===void 0?void 0:`message:${e}`}r(f,"turnCauseOf");function p(){return u===void 0?void 0:f(u().sessionManager.getBranch())}r(p,"currentCausedBy");function y(){if(u===void 0)return;const{cause:n,pending:e}=d(u().sessionManager.getBranch()),s=e[0]??n;return s===void 0?void 0:`message:${s}`}r(y,"currentOrPendingCausedBy");export{p as currentCausedBy,y as currentOrPendingCausedBy,g as setTurnCauseSource,f as turnCauseOf};
@@ -20,6 +20,8 @@ export interface HeadlessRequest {
20
20
  seedMessages?: readonly AgentMessage[];
21
21
  /** Reuses a provider cache identity without binding or persisting a session. */
22
22
  sessionId?: string;
23
+ /** The turn cause the call belongs to (`message:<id>`), captured by the caller with the call's input; null names none. Omit to read the turn at dispatch. */
24
+ causedBy?: string | null;
23
25
  /** Omit `noTools` to load Pi's builtin tool suite. */
24
26
  toolPolicy?: 'builtin';
25
27
  }