@north-light/cli 0.3.481 → 0.3.482

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.
@@ -1,5 +1,5 @@
1
1
  /** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
2
- export declare const CONTRACT_LEVEL = "1.7";
2
+ export declare const CONTRACT_LEVEL = "1.8";
3
3
  /** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
4
4
  export declare const REQUIRED_CONTRACT_HEADER = "Crouter-Required-Contract";
5
5
  /** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
@@ -1 +1 @@
1
- var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});const f="1.7",i="Crouter-Required-Contract",p="Crouter-Contract";function l(r){const t=/^(\d+)\.(\d+)$/.exec(r.trim());return t===null?null:{major:Number(t[1]),minor:Number(t[2])}}e(l,"parseContractLevel");function a(r){return r==null?[]:r.split(",").map(t=>l(t)).filter(t=>t!==null)}e(a,"parseServedContracts");function s(r,t){const n=l(r);return n===null?!1:(typeof t=="string"||t===null||t===void 0?a(t):t).some(u=>u.major===n.major&&u.minor>=n.minor)}e(s,"contractSatisfies");function C(r,t,n={}){if(r===void 0)return null;if(l(r)===null)return{status:400,code:"invalid_request",param:i,message:`${i} must be a contract level like 1.0.`};if(s(r,t))return null;const o=r.trim();return{status:426,code:"runtime_version_unsupported",message:t===null||a(t).length===0?`The runtime did not name its contract level; the caller requires contract ${o} or later. Roll the runtime forward.`:`The runtime serves contract ${t}; the caller requires contract ${o} or later within the same major. Roll the runtime forward, or pin an SDK whose crouterContract the runtime serves.`,details:{sdk_version:(n.legacyMinimum??"").trim(),runtime_version:n.runtimeVersion??null,required_contract:o,runtime_contract:t}}}e(C,"contractRefusal");export{p as CONTRACT_HEADER,f as CONTRACT_LEVEL,i as REQUIRED_CONTRACT_HEADER,C as contractRefusal,s as contractSatisfies,l as parseContractLevel,a as parseServedContracts};
1
+ var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});const f="1.8",i="Crouter-Required-Contract",p="Crouter-Contract";function l(r){const t=/^(\d+)\.(\d+)$/.exec(r.trim());return t===null?null:{major:Number(t[1]),minor:Number(t[2])}}e(l,"parseContractLevel");function a(r){return r==null?[]:r.split(",").map(t=>l(t)).filter(t=>t!==null)}e(a,"parseServedContracts");function s(r,t){const n=l(r);return n===null?!1:(typeof t=="string"||t===null||t===void 0?a(t):t).some(u=>u.major===n.major&&u.minor>=n.minor)}e(s,"contractSatisfies");function C(r,t,n={}){if(r===void 0)return null;if(l(r)===null)return{status:400,code:"invalid_request",param:i,message:`${i} must be a contract level like 1.0.`};if(s(r,t))return null;const o=r.trim();return{status:426,code:"runtime_version_unsupported",message:t===null||a(t).length===0?`The runtime did not name its contract level; the caller requires contract ${o} or later. Roll the runtime forward.`:`The runtime serves contract ${t}; the caller requires contract ${o} or later within the same major. Roll the runtime forward, or pin an SDK whose crouterContract the runtime serves.`,details:{sdk_version:(n.legacyMinimum??"").trim(),runtime_version:n.runtimeVersion??null,required_contract:o,runtime_contract:t}}}e(C,"contractRefusal");export{p as CONTRACT_HEADER,f as CONTRACT_LEVEL,i as REQUIRED_CONTRACT_HEADER,C as contractRefusal,s as contractSatisfies,l as parseContractLevel,a as parseServedContracts};
@@ -9,6 +9,12 @@ when-and-why-to-read: When you need Release notes, this knowledge should be read
9
9
 
10
10
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
11
11
 
12
+ ## 0.3.482
13
+
14
+ ### `runs.start` accepts `deadline` (additive, no app change)
15
+
16
+ `RunStartParams.deadline` bounds a run's wall-clock time, measured from start: one or more `<int>[smhd]` parts (`10m`, `1h30m`), at most `24h`. When it passes, the run settles with `outcome.reason` `deadline_exceeded` and its agent is stopped. A malformed, zero or over-24h value is refused with 400 `invalid_request` and `param: 'deadline'`, and no run is created. `deadline` takes part in the idempotency body, so the same key with another deadline is a 409 `idempotency_conflict`. `model` (already accepted) and `deadline` work on `isolated` runs. `payer`, `model_policy` and `kind` are still refused.
17
+
12
18
  ## 0.3.481
13
19
 
14
20
  ### `npx @north-light/sdk login`, `logout`, `whoami`, `register` and `apps` (additive, no app change)
@@ -1 +1 @@
1
- var k=Object.defineProperty;var u=(n,e)=>k(n,"name",{value:e,configurable:!0});import{resolve as x}from"node:path";import{envNodeId as C}from"../../shared/env.js";import{cliClient as f}from"../../commands/api-client.js";import{apiErrorToCliError as j}from"../io.js";import{ApiError as L}from"../../api/index.js";import{defineBranch as h,defineLeaf as T}from"../command.js";import{resolveCommandRegistry as U}from"../command-manifests/registry.js";import{executeExternalLeaf as M}from"./transport/exec-invoke.js";import{invokeHttpLeaf as A}from"./transport/http-invoke.js";async function S(n){const e=await f().request("GET",`/v1/providers/${encodeURIComponent(n)}/tools`);return new Set(e.groups.flatMap(r=>r.leaves.map(a=>a.tool)))}u(S,"allowedProviderTools");function m(n,e,r){return n.children.some(a=>a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))}u(m,"hasAllowedLeaf");function N(n,e,r){return n.children.filter(a=>a.tier!=="hidden"&&(a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))).length}u(N,"visibleChildCount");function _(n,e,r){return async()=>{if(!C())return n.help;const a=await S(e.id);return{...n.help,listing:n.help.listing?.flatMap(t=>{const i=n.children.find(s=>s.name===t.name);if(i?.kind==="leaf")return a.has([...r,i.name].join(" "))?[t]:[];if(i?.kind!=="branch")return[];const o=[...r,i.name];if(!m(i,o,a))return[];const p=N(i,o,a);return[{...t,...t.subCount!==void 0?{subCount:p}:{}}]})}}}u(_,"providerHelp");const b="Runs on one of your devices. Add `--machine <machine_id>` to pick which; without it the call goes to your only device, and with several the answer is `machine_required` listing each one's machine_id. The `runtime:` prefix on the id is optional.";function g(n,e,r,a=!1){return{outputKind:"object",...a?{machineSelector:!0}:{},run:u(async(t,i)=>{const o={...t};for(const p of r.params){if(!("type"in p)||p.type!=="file")continue;const s=p.name.replace(/-([a-z])/g,(c,w)=>w.toUpperCase()),d=o[s];typeof d=="string"&&(o[s]=x(d))}try{return await f({timeoutMs:0}).request("POST","/v1/provider/call",{provider:n,tool:e,arguments:o,...i?.machine===void 0?{}:{machine:i.machine}},{timeout:0})}catch(p){throw p instanceof L?j(p,void 0,{providerCall:!0}):p}},"run")}}u(g,"providerLeafAdapter");function v(n,e){return/^[A-Za-z0-9_-]{1,64}$/.test(n)&&n!=="crtr"&&!e.has(n)}u(v,"validRootName");function O(n,e){const r=[],a=[];for(const t of n){const{provider:i,commands:o}=t;if(!Array.isArray(o)||t.status!=="available"&&!v(i,e))continue;if(t.status!=="available"){const s=t.error??"bundle installation pending",d=`Unavailable (${t.status}): ${s}`,c=h({name:i,rootEntry:{concept:t.display_name,desc:d,useWhen:d},help:{name:i,summary:d},children:[]});c.unavailable=d,a.push(c);continue}const p=u(s=>s.kind==="branch"?{...s,children:s.children.map(p)}:{...s,rest:{method:"GET",path:"/",params:{}}},"helpNode");for(const s of o)s.kind!=="branch"||!Array.isArray(s.children)||!v(s.name,e)||r.push({contributor:{name:i,scope:"user"},manifestName:s.name,node:p(s),adaptLeaf:u((d,c)=>g(i,c.slice(1).join(" "),d,t.transport==="machine"),"adaptLeaf")})}return[...I(U(r,e)),...a]}u(O,"composeSandboxProviderSubtrees");function y(n,e){return(r,a)=>{const t=n.transport,i=e(a);if(n.provider!==void 0)return g(n.provider.id,i.slice(1).join(" "),r,t.kind==="machine");if(t.kind==="exec"){const p=t.executable;if(p===void 0)throw new Error(`exec plugin "${n.plugin.name}" has an executable leaf without transport.executable`);return{outputKind:"object",run:u(async s=>M({plugin:n.plugin,executable:p,commandPath:i,output:r.output},s),"run")}}if(t.kind==="machine")throw new Error(`machine plugin "${n.plugin.name}" is not a capability provider`);const o=r;return{outputKind:o.rest.streaming===!0?"jsonl":"object",run:u((p,s)=>A({registration:{name:n.plugin.name,endpoint:t.endpoint,...t.authEnv!==void 0?{authEnv:t.authEnv}:{}},...n.manifest?.baseUrl!==void 0?{baseUrl:n.manifest.baseUrl}:{},...n.manifest?.timeouts!==void 0?{timeouts:n.manifest.timeouts}:{},params:o.params,rest:o.rest,output:o.output,commandPath:i},p,s),"run")}}}u(y,"adaptLeaf");function W(n){return{contributions:n.map(e=>({contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,manifestName:e.manifestName,adaptLeaf:y(e,r=>[e.manifestName,...r.slice(1)]),...e.provider!==void 0?{provider:e.provider}:{}})),coreMounts:[],issues:[]}}u(W,"adaptPluginContributions");function F(n){return n.map(e=>({parent:e.parent,plugin:e.plugin.name,contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,...e.provider!==void 0?{provider:e.provider}:{},adaptLeaf:y({...e,manifestName:e.node.name},r=>e.provider===void 0?[...r]:[e.provider.id,...r.slice(e.parent.length)])}))}u(F,"adaptPluginCoreMounts");function I(n){return n.contributions.map(e=>l(e,e.node,[e.node.name]))}u(I,"composeExternalSubtrees");function Z(n,e){return n.filter(r=>r.parent.join("\0")===e.join("\0")).map(r=>r.node.kind==="branch"?l(r,r.node,[...e,r.node.name],r.provider===void 0?1:e.length):E(r,r.node,[...e,r.node.name]))}u(Z,"composeCoreBranchMounts");function l(n,e,r,a=1){const t=e.rootEntry===void 0?void 0:{concept:e.rootEntry.concept,desc:e.rootEntry.description,useWhen:e.rootEntry.whenToUse},i=h({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...t!==void 0?{rootEntry:t}:{},help:{name:r.join(" "),summary:e.summary,...e.model!==void 0?{model:e.model}:{},...r.length===1&&n.extensionIssue!==void 0?{extensionIssue:n.extensionIssue}:{}},...e.passthrough!==void 0?{passthrough:e.passthrough}:{},children:e.children.map(o=>o.kind==="branch"?l(n,o,[...r,o.name],a):E(n,o,[...r,o.name]))});return n.provider!==void 0&&(i.effectiveHelp=_(i,n.provider,r.slice(a))),i}u(l,"buildBranch");function E(n,e,r){const a=n.adaptLeaf(e,r);return T({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...a.machineSelector===!0?{machineSelector:!0}:{},help:{name:r.join(" "),summary:e.summary,...a.machineSelector===!0?{guide:b}:{},params:e.params,output:e.output,outputKind:a.outputKind,effects:[...e.effects]},run:a.run})}u(E,"buildLeaf");export{W as adaptPluginContributions,F as adaptPluginCoreMounts,Z as composeCoreBranchMounts,I as composeExternalSubtrees,O as composeSandboxProviderSubtrees};
1
+ var k=Object.defineProperty;var u=(n,e)=>k(n,"name",{value:e,configurable:!0});import{resolve as x}from"node:path";import{envNodeId as C}from"../../shared/env.js";import{cliClient as l}from"../../commands/api-client.js";import{apiErrorToCliError as j}from"../io.js";import{ApiError as L}from"../../api/index.js";import{defineBranch as h,defineLeaf as T}from"../command.js";import{resolveCommandRegistry as U}from"../command-manifests/registry.js";import{executeExternalLeaf as M}from"./transport/exec-invoke.js";import{invokeHttpLeaf as A}from"./transport/http-invoke.js";import{readPathParam as S}from"./transport/http-plan.js";async function N(n){const e=await l().request("GET",`/v1/providers/${encodeURIComponent(n)}/tools`);return new Set(e.groups.flatMap(r=>r.leaves.map(a=>a.tool)))}u(N,"allowedProviderTools");function m(n,e,r){return n.children.some(a=>a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))}u(m,"hasAllowedLeaf");function P(n,e,r){return n.children.filter(a=>a.tier!=="hidden"&&(a.kind==="leaf"?r.has([...e,a.name].join(" ")):m(a,[...e,a.name],r))).length}u(P,"visibleChildCount");function _(n,e,r){return async()=>{if(!C())return n.help;const a=await N(e.id);return{...n.help,listing:n.help.listing?.flatMap(t=>{const i=n.children.find(s=>s.name===t.name);if(i?.kind==="leaf")return a.has([...r,i.name].join(" "))?[t]:[];if(i?.kind!=="branch")return[];const o=[...r,i.name];if(!m(i,o,a))return[];const p=P(i,o,a);return[{...t,...t.subCount!==void 0?{subCount:p}:{}}]})}}}u(_,"providerHelp");const $="Runs on one of your devices. Add `--machine <machine_id>` to pick which; without it the call goes to your only device, and with several the answer is `machine_required` listing each one's machine_id. The `runtime:` prefix on the id is optional.";function g(n,e,r,a=!1){return{outputKind:"object",...a?{machineSelector:!0}:{},run:u(async(t,i)=>{const o={...t};for(const p of r.params){if(!("type"in p))continue;const s=p.name.replace(/-([a-z])/g,(c,w)=>w.toUpperCase()),d=o[s];p.type==="file"&&typeof d=="string"?o[s]=x(d):p.type==="path"&&d!==void 0&&(o[s]=S(`provider command \`${n} ${e}\``,p,d))}try{return await l({timeoutMs:0}).request("POST","/v1/provider/call",{provider:n,tool:e,arguments:o,...i?.machine===void 0?{}:{machine:i.machine}},{timeout:0})}catch(p){throw p instanceof L?j(p,void 0,{providerCall:!0}):p}},"run")}}u(g,"providerLeafAdapter");function v(n,e){return/^[A-Za-z0-9_-]{1,64}$/.test(n)&&n!=="crtr"&&!e.has(n)}u(v,"validRootName");function F(n,e){const r=[],a=[];for(const t of n){const{provider:i,commands:o}=t;if(!Array.isArray(o)||t.status!=="available"&&!v(i,e))continue;if(t.status!=="available"){const s=t.error??"bundle installation pending",d=`Unavailable (${t.status}): ${s}`,c=h({name:i,rootEntry:{concept:t.display_name,desc:d,useWhen:d},help:{name:i,summary:d},children:[]});c.unavailable=d,a.push(c);continue}const p=u(s=>s.kind==="branch"?{...s,children:s.children.map(p)}:{...s,rest:{method:"GET",path:"/",params:{}}},"helpNode");for(const s of o)s.kind!=="branch"||!Array.isArray(s.children)||!v(s.name,e)||r.push({contributor:{name:i,scope:"user"},manifestName:s.name,node:p(s),adaptLeaf:u((d,c)=>g(i,c.slice(1).join(" "),d,t.transport==="machine"),"adaptLeaf")})}return[...b(U(r,e)),...a]}u(F,"composeSandboxProviderSubtrees");function y(n,e){return(r,a)=>{const t=n.transport,i=e(a);if(n.provider!==void 0)return g(n.provider.id,i.slice(1).join(" "),r,t.kind==="machine");if(t.kind==="exec"){const p=t.executable;if(p===void 0)throw new Error(`exec plugin "${n.plugin.name}" has an executable leaf without transport.executable`);return{outputKind:"object",run:u(async s=>M({plugin:n.plugin,executable:p,commandPath:i,output:r.output},s),"run")}}if(t.kind==="machine")throw new Error(`machine plugin "${n.plugin.name}" is not a capability provider`);const o=r;return{outputKind:o.rest.streaming===!0?"jsonl":"object",run:u((p,s)=>A({registration:{name:n.plugin.name,endpoint:t.endpoint,...t.authEnv!==void 0?{authEnv:t.authEnv}:{}},...n.manifest?.baseUrl!==void 0?{baseUrl:n.manifest.baseUrl}:{},...n.manifest?.timeouts!==void 0?{timeouts:n.manifest.timeouts}:{},params:o.params,rest:o.rest,output:o.output,commandPath:i},p,s),"run")}}}u(y,"adaptLeaf");function Z(n){return{contributions:n.map(e=>({contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,manifestName:e.manifestName,adaptLeaf:y(e,r=>[e.manifestName,...r.slice(1)]),...e.provider!==void 0?{provider:e.provider}:{}})),coreMounts:[],issues:[]}}u(Z,"adaptPluginContributions");function J(n){return n.map(e=>({parent:e.parent,plugin:e.plugin.name,contributor:{name:e.plugin.name,scope:e.plugin.scope,sourceMarketplace:e.plugin.sourceMarketplace},node:e.node,...e.provider!==void 0?{provider:e.provider}:{},adaptLeaf:y({...e,manifestName:e.node.name},r=>e.provider===void 0?[...r]:[e.provider.id,...r.slice(e.parent.length)])}))}u(J,"adaptPluginCoreMounts");function b(n){return n.contributions.map(e=>f(e,e.node,[e.node.name]))}u(b,"composeExternalSubtrees");function Q(n,e){return n.filter(r=>r.parent.join("\0")===e.join("\0")).map(r=>r.node.kind==="branch"?f(r,r.node,[...e,r.node.name],r.provider===void 0?1:e.length):E(r,r.node,[...e,r.node.name]))}u(Q,"composeCoreBranchMounts");function f(n,e,r,a=1){const t=e.rootEntry===void 0?void 0:{concept:e.rootEntry.concept,desc:e.rootEntry.description,useWhen:e.rootEntry.whenToUse},i=h({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...t!==void 0?{rootEntry:t}:{},help:{name:r.join(" "),summary:e.summary,...e.model!==void 0?{model:e.model}:{},...r.length===1&&n.extensionIssue!==void 0?{extensionIssue:n.extensionIssue}:{}},...e.passthrough!==void 0?{passthrough:e.passthrough}:{},children:e.children.map(o=>o.kind==="branch"?f(n,o,[...r,o.name],a):E(n,o,[...r,o.name]))});return n.provider!==void 0&&(i.effectiveHelp=_(i,n.provider,r.slice(a))),i}u(f,"buildBranch");function E(n,e,r){const a=n.adaptLeaf(e,r);return T({name:e.name,description:e.description,whenToUse:e.whenToUse,...e.tier!==void 0?{tier:e.tier}:{},...n.plugin!==void 0?{plugin:n.plugin}:{},...a.machineSelector===!0?{machineSelector:!0}:{},help:{name:r.join(" "),summary:e.summary,...a.machineSelector===!0?{guide:$}:{},params:e.params,output:e.output,outputKind:a.outputKind,effects:[...e.effects]},run:a.run})}u(E,"buildLeaf");export{Z as adaptPluginContributions,J as adaptPluginCoreMounts,Q as composeCoreBranchMounts,b as composeExternalSubtrees,F as composeSandboxProviderSubtrees};
@@ -40,6 +40,11 @@ export interface RequestPlan {
40
40
  body?: string;
41
41
  }
42
42
  export declare function buildRequestPlan(spec: HttpInvokerSpec, input: Record<string, unknown>, context: LeafRunContext | undefined, options: RequestPlanOptions): RequestPlan;
43
+ /** Read the local file a `type:"path"` param names (relative paths resolve
44
+ * against the caller's cwd) and return its content per the param's `encoding`.
45
+ * Shared by the HTTP-plugin plan and the provider-leaf adapter, so every
46
+ * transport ships file content and none ships the path string. */
47
+ export declare function readPathParam(commandLabel: string, param: InputParam, value: unknown): unknown;
43
48
  /** Map a unary 2xx body to the validated result object, or throw
44
49
  * cli_protocol_error (GENERAL) for bad JSON / a non-object / an output mismatch. */
45
50
  export declare function mapUnary2xx(spec: HttpInvokerSpec, body: string): Record<string, unknown>;
@@ -1 +1 @@
1
- var N=Object.defineProperty;var f=(e,t)=>N(e,"name",{value:t,configurable:!0});import{readFileSync as k,statSync as R}from"node:fs";import{resolve as j}from"node:path";import{validateDeclaredResult as C}from"../../../api/command-manifest/result.js";import{CrtrError as g}from"../../errors.js";import{envelopeClaimsStale as z,staleErrorDetails as U}from"../../manifest-stale.js";import{ExitCode as m}from"../../../types.js";import{isRecord as x}from"../../../shared/predicates.js";const q=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,P=new Set(["internal","unknown_path","command_collision","cli_protocol_error"]),T=new Set(["authorization","crtr-request-id","crtr-run-id","crtr-approval","crtr-upload-id","crtr-upload-link","accept","content-type"]);function X(e,t,n,r){const i=new Map;for(const o of e.params)i.set(o.name,o);const l=Object.entries(e.rest.params),u=e.baseUrl??new URL(e.registration.endpoint).origin;let p=e.rest.path;for(const[o,a]of l){if(a.in!=="path")continue;const s=t[w(o)];p=p.split(`{${o}}`).join(G(s))}const b=new URL(p,u);for(const[o,a]of l){if(a.in!=="query")continue;const s=w(o);$(i.get(o),s,t,n)&&b.searchParams.append(a.as??o,String(t[s]))}const y=L(e,l,i,t,n,r.fileMode),h=Object.keys(y).length>0?JSON.stringify(y):void 0,c={},d=f((o,a)=>{const s=Object.keys(c).find(S=>S.toLowerCase()===o.toLowerCase());s!==void 0&&delete c[s],c[o]=a},"setHeader");d("Accept","application/json"),d("Crtr-Request-Id",r.requestId),r.authorization!==null&&d("Authorization",r.authorization);for(const[o,a]of l){if(a.in!=="header")continue;const s=w(o);if(!$(i.get(o),s,t,n))continue;const S=a.as;if(r.fileMode==="pass-through"&&T.has(S.toLowerCase()))throw new g("invalid_type",`${v(e)}: header "${S}" is reserved for the runtime`,m.USAGE,{field:o,next:"Remove the runtime-owned header mapping from the manifest."});const _=String(t[s]);if(/[\r\n]/.test(_))throw new g("invalid_type",`${v(e)}: header "${S}" value must not contain a newline`,m.USAGE,{field:o,received:"(newline in header value)",next:"Remove newline characters from the value."});d(S,_)}h!==void 0&&d("Content-Type","application/json");for(const[o,a]of Object.entries(r.extraHeaders)){if(r.fileMode==="pass-through"&&/[\r\n]/.test(a))throw new g("invalid_type",`${v(e)}: header "${o}" value must not contain a newline`,m.USAGE);d(o,a)}if(r.fileMode==="pass-through"){if(d("Accept","application/json"),h!==void 0)d("Content-Type","application/json");else{const o=Object.keys(c).find(a=>a.toLowerCase()==="content-type");o!==void 0&&delete c[o]}if(d("Crtr-Request-Id",r.requestId),r.authorization!==null)d("Authorization",r.authorization);else{const o=Object.keys(c).find(a=>a.toLowerCase()==="authorization");o!==void 0&&delete c[o]}}return{url:b,method:e.rest.method,headers:c,...h!==void 0?{body:h}:{}}}f(X,"buildRequestPlan");function L(e,t,n,r,i,l){const u=new Map;for(const[y,h]of t){if(h.in!=="body")continue;const c=h.as??y,d=u.get(c);d!==void 0?d.push(y):u.set(c,[y])}const p={};for(const[y,h]of u){const c=h.map(s=>({name:s,param:n.get(s)})),d=c.find(s=>s.param.kind!=="stdin"),o=c.find(s=>s.param.kind==="stdin");let a;d!==void 0&&$(d.param,w(d.name),r,i)?a={param:d.param,value:r[w(d.name)]}:o!==void 0&&$(o.param,w(o.name),r,i)&&(a={param:o.param,value:r[w(o.name)]}),a!==void 0&&(p[y]=A(e,a.param,a.value,l))}const b={...e.rest.body};return e.rest.bodyRoot!==void 0?b[e.rest.bodyRoot]=p:Object.assign(b,p),b}f(L,"assembleBody");function A(e,t,n,r){if(r==="pass-through"||t.kind==="context-file")return n;if((t.kind==="positional"||t.kind==="flag")&&t.type==="path"){if(Array.isArray(n))return n.map(p=>A(e,t,p,r));const i=String(n),l=j(process.cwd(),i);let u;try{u=R(l)}catch{throw O(e,t.name,i,"no file exists at that path","an existing local file path")}if(!u.isFile())throw O(e,t.name,i,"the path is not a regular file","a regular local file (not a directory, socket, or device)");try{return t.encoding==="base64"?k(l).toString("base64"):k(l,"utf8")}catch{throw O(e,t.name,i,"the file could not be read","a readable local file path")}}return n}f(A,"materializeBodyValue");function O(e,t,n,r,i){return new g("invalid_type",`${v(e)}: cannot read file for "${t}" \u2014 ${r}: ${n}`,m.USAGE,{field:t,received:n,next:`Pass ${i}, relative to the current directory or absolute.`})}f(O,"fileError");function $(e,t,n,r){return r!==void 0?r.providedParams.has(t):Object.prototype.hasOwnProperty.call(n,t)&&n[t]!==void 0}f($,"isPresent");function G(e){const t=String(e);return t==="."||t===".."?t.replace(/\./g,"%2E"):encodeURIComponent(t)}f(G,"encodePathSegmentValue");function w(e){return e.replace(/-([a-z])/g,(t,n)=>n.toUpperCase())}f(w,"paramKey");function Y(e,t){let n;try{n=JSON.parse(t)}catch{throw E(e,"response body was not valid JSON","a JSON object matching the declared output")}if(!x(n))throw E(e,`response body was not a JSON object (got ${J(n)})`,"a JSON object matching the declared output");const r=C(e.output,n);if(r!==null){const l=e.output.find(u=>u.name===r.field)?.type??"unknown";throw r.receivedType!==void 0?E(e,`output field "${r.field}" has the wrong type`,`${r.field}: ${l}`):E(e,`response is missing required output field "${r.field}"`,`a "${r.field}" field of type ${l}`)}return n}f(Y,"mapUnary2xx");function Z(e,t,n){const r=D(t),i=I(n);if(i!==null){const l=q.test(i.code)&&!P.has(i.code);throw new g(l?i.code:"cli_protocol_error",i.message,r,{...i.received!==void 0?{received:i.received}:{},...i.field!==void 0?{field:i.field}:{},...i.manifestStale?U(e.registration.name):{},http_status:t,next:i.next??"Inspect the backend response, then retry if appropriate."})}throw new g("cli_http_error",`${v(e)}: request failed with HTTP ${t}`,r,{http_status:t,next:"Inspect the backend response, then retry if appropriate."})}f(Z,"throwNon2xx");function I(e){let t;try{t=JSON.parse(e)}catch{return null}if(!x(t)||!x(t.error))return null;const n=t.error;return typeof n.code!="string"||typeof n.message!="string"?null:{code:n.code,message:n.message,...typeof n.field=="string"?{field:n.field}:{},...n.received!==void 0?{received:n.received}:{},...typeof n.next=="string"?{next:n.next}:{},manifestStale:z(n),...n.question!==void 0?{question:n.question}:{}}}f(I,"parseHttpError");function D(e){return e===400||e===401||e===403||e===422?m.USAGE:e===404?m.NOT_FOUND:e===409?m.AMBIGUOUS:m.GENERAL}f(D,"deriveExit");function E(e,t,n){return new g("cli_protocol_error",`${v(e)}: ${t}. Expected ${n}.`,m.GENERAL,{received:t,next:`Run \`crtr pkg plugin update ${e.registration.name}\` or inspect the backend response.`})}f(E,"protocolError");function v(e){return`HTTP-transport plugin "${e.registration.name}" command \`${e.commandPath.join(" ")}\``}f(v,"label");function J(e){return e===null?"null":Array.isArray(e)?"array":typeof e}f(J,"typeName");export{X as buildRequestPlan,Y as mapUnary2xx,I as parseHttpError,Z as throwNon2xx};
1
+ var N=Object.defineProperty;var f=(e,t)=>N(e,"name",{value:t,configurable:!0});import{readFileSync as k,statSync as R}from"node:fs";import{resolve as j}from"node:path";import{validateDeclaredResult as C}from"../../../api/command-manifest/result.js";import{CrtrError as g}from"../../errors.js";import{envelopeClaimsStale as z,staleErrorDetails as U}from"../../manifest-stale.js";import{ExitCode as h}from"../../../types.js";import{isRecord as x}from"../../../shared/predicates.js";const P=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,q=new Set(["internal","unknown_path","command_collision","cli_protocol_error"]),T=new Set(["authorization","crtr-request-id","crtr-run-id","crtr-approval","crtr-upload-id","crtr-upload-link","accept","content-type"]);function Y(e,t,n,r){const i=new Map;for(const o of e.params)i.set(o.name,o);const c=Object.entries(e.rest.params),u=e.baseUrl??new URL(e.registration.endpoint).origin;let y=e.rest.path;for(const[o,a]of c){if(a.in!=="path")continue;const s=t[w(o)];y=y.split(`{${o}}`).join(M(s))}const b=new URL(y,u);for(const[o,a]of c){if(a.in!=="query")continue;const s=w(o);$(i.get(o),s,t,n)&&b.searchParams.append(a.as??o,String(t[s]))}const m=G(e,c,i,t,n,r.fileMode),p=Object.keys(m).length>0?JSON.stringify(m):void 0,l={},d=f((o,a)=>{const s=Object.keys(l).find(S=>S.toLowerCase()===o.toLowerCase());s!==void 0&&delete l[s],l[o]=a},"setHeader");d("Accept","application/json"),d("Crtr-Request-Id",r.requestId),r.authorization!==null&&d("Authorization",r.authorization);for(const[o,a]of c){if(a.in!=="header")continue;const s=w(o);if(!$(i.get(o),s,t,n))continue;const S=a.as;if(r.fileMode==="pass-through"&&T.has(S.toLowerCase()))throw new g("invalid_type",`${v(e)}: header "${S}" is reserved for the runtime`,h.USAGE,{field:o,next:"Remove the runtime-owned header mapping from the manifest."});const _=String(t[s]);if(/[\r\n]/.test(_))throw new g("invalid_type",`${v(e)}: header "${S}" value must not contain a newline`,h.USAGE,{field:o,received:"(newline in header value)",next:"Remove newline characters from the value."});d(S,_)}p!==void 0&&d("Content-Type","application/json");for(const[o,a]of Object.entries(r.extraHeaders)){if(r.fileMode==="pass-through"&&/[\r\n]/.test(a))throw new g("invalid_type",`${v(e)}: header "${o}" value must not contain a newline`,h.USAGE);d(o,a)}if(r.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",r.requestId),r.authorization!==null)d("Authorization",r.authorization);else{const o=Object.keys(l).find(a=>a.toLowerCase()==="authorization");o!==void 0&&delete l[o]}}return{url:b,method:e.rest.method,headers:l,...p!==void 0?{body:p}:{}}}f(Y,"buildRequestPlan");function G(e,t,n,r,i,c){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:n.get(s)})),d=l.find(s=>s.param.kind!=="stdin"),o=l.find(s=>s.param.kind==="stdin");let a;d!==void 0&&$(d.param,w(d.name),r,i)?a={param:d.param,value:r[w(d.name)]}:o!==void 0&&$(o.param,w(o.name),r,i)&&(a={param:o.param,value:r[w(o.name)]}),a!==void 0&&(y[m]=I(e,a.param,a.value,c))}const b={...e.rest.body};return e.rest.bodyRoot!==void 0?b[e.rest.bodyRoot]=y:Object.assign(b,y),b}f(G,"assembleBody");function I(e,t,n,r){return r==="pass-through"||t.kind==="context-file"?n:(t.kind==="positional"||t.kind==="flag")&&t.type==="path"?A(v(e),t,n):n}f(I,"materializeBodyValue");function A(e,t,n){if(Array.isArray(n))return n.map(u=>A(e,t,u));const r=String(n),i=j(process.cwd(),r);let c;try{c=R(i)}catch{throw O(e,t.name,r,"no file exists at that path","an existing local file path")}if(!c.isFile())throw O(e,t.name,r,"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"?k(i).toString("base64"):k(i,"utf8")}catch{throw O(e,t.name,r,"the file could not be read","a readable local file path")}}f(A,"readPathParam");function O(e,t,n,r,i){return new g("invalid_type",`${e}: cannot read file for "${t}" \u2014 ${r}: ${n}`,h.USAGE,{field:t,received:n,next:`Pass ${i}, relative to the current directory or absolute.`})}f(O,"fileError");function $(e,t,n,r){return r!==void 0?r.providedParams.has(t):Object.prototype.hasOwnProperty.call(n,t)&&n[t]!==void 0}f($,"isPresent");function M(e){const t=String(e);return t==="."||t===".."?t.replace(/\./g,"%2E"):encodeURIComponent(t)}f(M,"encodePathSegmentValue");function w(e){return e.replace(/-([a-z])/g,(t,n)=>n.toUpperCase())}f(w,"paramKey");function Z(e,t){let n;try{n=JSON.parse(t)}catch{throw E(e,"response body was not valid JSON","a JSON object matching the declared output")}if(!x(n))throw E(e,`response body was not a JSON object (got ${H(n)})`,"a JSON object matching the declared output");const r=C(e.output,n);if(r!==null){const c=e.output.find(u=>u.name===r.field)?.type??"unknown";throw r.receivedType!==void 0?E(e,`output field "${r.field}" has the wrong type`,`${r.field}: ${c}`):E(e,`response is missing required output field "${r.field}"`,`a "${r.field}" field of type ${c}`)}return n}f(Z,"mapUnary2xx");function ee(e,t,n){const r=J(t),i=D(n);if(i!==null){const c=P.test(i.code)&&!q.has(i.code);throw new g(c?i.code:"cli_protocol_error",i.message,r,{...i.received!==void 0?{received:i.received}:{},...i.field!==void 0?{field:i.field}:{},...i.manifestStale?U(e.registration.name):{},http_status:t,next:i.next??"Inspect the backend response, then retry if appropriate."})}throw new g("cli_http_error",`${v(e)}: request failed with HTTP ${t}`,r,{http_status:t,next:"Inspect the backend response, then retry if appropriate."})}f(ee,"throwNon2xx");function D(e){let t;try{t=JSON.parse(e)}catch{return null}if(!x(t)||!x(t.error))return null;const n=t.error;return typeof n.code!="string"||typeof n.message!="string"?null:{code:n.code,message:n.message,...typeof n.field=="string"?{field:n.field}:{},...n.received!==void 0?{received:n.received}:{},...typeof n.next=="string"?{next:n.next}:{},manifestStale:z(n),...n.question!==void 0?{question:n.question}:{}}}f(D,"parseHttpError");function J(e){return e===400||e===401||e===403||e===422?h.USAGE:e===404?h.NOT_FOUND:e===409?h.AMBIGUOUS:h.GENERAL}f(J,"deriveExit");function E(e,t,n){return new g("cli_protocol_error",`${v(e)}: ${t}. Expected ${n}.`,h.GENERAL,{received:t,next:`Run \`crtr pkg plugin update ${e.registration.name}\` or inspect the backend response.`})}f(E,"protocolError");function v(e){return`HTTP-transport plugin "${e.registration.name}" command \`${e.commandPath.join(" ")}\``}f(v,"label");function H(e){return e===null?"null":Array.isArray(e)?"array":typeof e}f(H,"typeName");export{Y as buildRequestPlan,Z as mapUnary2xx,D as parseHttpError,A as readPathParam,ee as throwNon2xx};
@@ -34,6 +34,10 @@ export declare const IDEMPOTENCY_WINDOW_MS = 86400000;
34
34
  export declare function idempotencyKeyOf(header: unknown): string | undefined;
35
35
  /** Delete keys past their window; returns how many were removed. */
36
36
  export declare function pruneExpiredIdempotencyKeys(now?: number): number;
37
+ /** Longest `run.start` deadline an app may set: 24 hours. The grammar is `crtr node new --deadline`'s (parts of `<int>[smhd]`, summed). */
38
+ export declare const RUN_DEADLINE_MAX_MS: number;
39
+ /** The milliseconds of a `run.start` `deadline` duration; refuses a malformed, zero, or over-24h value as `invalid_request` on `deadline`. */
40
+ export declare function parseRunDeadlineMs(raw: string): number;
37
41
  export declare function startRun(principal: AppPrincipal, input: {
38
42
  prompt: string;
39
43
  scopes: string[] | null;
@@ -42,6 +46,7 @@ export declare function startRun(principal: AppPrincipal, input: {
42
46
  isolated?: boolean;
43
47
  cwd?: string;
44
48
  model?: string;
49
+ deadline?: string;
45
50
  output_schema?: Record<string, unknown>;
46
51
  message?: string;
47
52
  }, idempotencyKey?: string, resolveAttachments?: AttachmentResolver): Promise<Record<string, unknown>>;
@@ -1,12 +1,12 @@
1
- var Se=Object.defineProperty;var m=(e,t)=>Se(e,"name",{value:t,configurable:!0});import{prepared as w}from"../sqlite-statements.js";import{coveredByAny as Ne}from"../../shared/env.js";import{createHash as J}from"node:crypto";import{ApiError as ve}from"../../api/errors.js";import{CrtrError as Oe}from"../errors.js";import{isAbsolute as Y,relative as be,resolve as De,sep as Te,join as Ie}from"node:path";import{SessionManager as Me}from"@earendil-works/pi-coding-agent";import{covers as W}from"@north-light/identity";import{openDb as G,withCanvasWrite as L}from"../canvas/db.js";import{deleteNodeWithOwned as Ae}from"../graph/deletion.js";import{getById as Le}from"../graph/objects.js";import{repairRunConversations as X}from"../canvas/sessions.js";import{getNode as S,nodeFiles as Ce,removeNodeFiles as xe,updateNode as ke}from"../canvas/canvas.js";import{fullName as We}from"../canvas/labels.js";import{renameWindow as Fe}from"../runtime/placement.js";import{liveExecutionForNode as z}from"../canvas/executions.js";import{conversationStore as Q,isConversationNotFound as He}from"../conversation-store/index.js";import{enqueueNodeMail as qe}from"../feed/messages.js";import{newestReportBody as Ue}from"../feed/reports.js";import{ensureAppProfile as Pe,loadExactProfileManifest as Be}from"../profiles/manifest.js";import{stopNodeSandboxes as V}from"../spaces/stop.js";import{BrokerUnreachableError as $e}from"../runtime/broker-request.js";import{interruptLive as je}from"../runtime/interactive-deliver.js";import{isBrokerLive as Z}from"../runtime/model-swap.js";import{newNodeId as Je}from"../runtime/nodes.js";import{writeGoal as Ye}from"../runtime/kickoff.js";import{reviveNode as F}from"../runtime/revive.js";import{spawnChildPrepared as Ge}from"../runtime/spawn.js";import{isPortableModelToken as Xe}from"../runtime/launch.js";import{expandModelCandidates as ze,parseModelSpec as Qe}from"../model-routes.js";import{isolatedBrokerLauncherAvailable as Ve}from"../runtime/host.js";import{resolveRunKind as Ze}from"../runtime/launch-target.js";import{cycleAwareMessages as Ke}from"../runtime/session-cycles.js";import{originFor as K}from"../runtime/stamp/protocol.js";import{readOutputRequest as et,readOutputResult as ee}from"../runtime/structured-output.js";import{admitLegacyStructuredOutput as te}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as tt}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as nt}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as st}from"../../daemon/runs/observer.js";import{closeNode as ne}from"../runtime/close.js";import{parseScope as rt}from"@north-light/identity";import{appendRunEvent as se,subscribeRunEvents as ot}from"./events.js";import{runActivity as it}from"./activity.js";import{cancelOpenQuestions as re,openQuestionIds as oe}from"./questions.js";import{appSpace as H}from"../layout.js";import{ensureAppSpace as dt}from"../spaces/space.js";import{assertUploadsUsable as ie,resolveStorageUrls as at}from"../storage/attachments.js";import{storageClient as ct,storageConfig as ut}from"../storage/client.js";import{deleteUploadRow as mt,insertUploadUses as de,releaseRunUploads as lt}from"../storage/tables.js";import{abortProviderCalls as ae}from"../providers/inflight.js";const ce=m((e,t,r)=>at(t,e,r),"defaultResolver"),_t=3e3;function pn(e){return Number(w(e,"UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}m(pn,"rewriteLocalIdempotencyGrantee");class R extends Error{static{m(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,r,s,i,c,d,o=t===503){super(s),this.status=t,this.code=r,this.param=i,this.details=c,this.scope=d,this.retryable=o}}const N=m((e,t)=>new R(400,"invalid_request",e,t),"invalid"),q=m(()=>new R(404,"not_found","run not found"),"missing"),U=m(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),b=m(()=>G(),"db");function C(e,t,r=!1){const s=S(e);if(!s||s.parent!==null||s.run_id!==e||s.grantee!==t||!r&&s.deleting_at)throw q();return s}m(C,"ownedRun");const P=["waiting_on_user","idle","settled"];function I(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=w(b(),`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
1
+ var Ne=Object.defineProperty;var m=(e,t)=>Ne(e,"name",{value:t,configurable:!0});import{prepared as w}from"../sqlite-statements.js";import{coveredByAny as ve}from"../../shared/env.js";import{createHash as J}from"node:crypto";import{ApiError as be}from"../../api/errors.js";import{CrtrError as Oe}from"../errors.js";import{isAbsolute as Y,relative as De,resolve as Me,sep as Ie,join as Te}from"node:path";import{SessionManager as Ae}from"@earendil-works/pi-coding-agent";import{covers as W}from"@north-light/identity";import{openDb as G,withCanvasWrite as L}from"../canvas/db.js";import{deleteNodeWithOwned as Le}from"../graph/deletion.js";import{getById as Ce}from"../graph/objects.js";import{repairRunConversations as X}from"../canvas/sessions.js";import{getNode as N,nodeFiles as xe,removeNodeFiles as ke,updateNode as We}from"../canvas/canvas.js";import{fullName as Fe}from"../canvas/labels.js";import{renameWindow as He}from"../runtime/placement.js";import{liveExecutionForNode as z}from"../canvas/executions.js";import{conversationStore as Q,isConversationNotFound as qe}from"../conversation-store/index.js";import{enqueueNodeMail as Ue}from"../feed/messages.js";import{newestReportBody as Pe}from"../feed/reports.js";import{ensureAppProfile as Be,loadExactProfileManifest as $e}from"../profiles/manifest.js";import{stopNodeSandboxes as V}from"../spaces/stop.js";import{BrokerUnreachableError as je}from"../runtime/broker-request.js";import{interruptLive as Je}from"../runtime/interactive-deliver.js";import{isBrokerLive as Z}from"../runtime/model-swap.js";import{newNodeId as Ye}from"../runtime/nodes.js";import{writeGoal as Ge}from"../runtime/kickoff.js";import{reviveNode as F}from"../runtime/revive.js";import{spawnChildPrepared as Xe}from"../runtime/spawn.js";import{isPortableModelToken as ze}from"../runtime/launch.js";import{parseDurationMs as Qe}from"../wake.js";import{expandModelCandidates as Ve,parseModelSpec as Ze}from"../model-routes.js";import{isolatedBrokerLauncherAvailable as Ke}from"../runtime/host.js";import{resolveRunKind as et}from"../runtime/launch-target.js";import{cycleAwareMessages as tt}from"../runtime/session-cycles.js";import{originFor as K}from"../runtime/stamp/protocol.js";import{readOutputRequest as nt,readOutputResult as ee}from"../runtime/structured-output.js";import{admitLegacyStructuredOutput as te}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as st}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as rt}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as ot}from"../../daemon/runs/observer.js";import{closeNode as ne}from"../runtime/close.js";import{parseScope as it}from"@north-light/identity";import{appendRunEvent as se,subscribeRunEvents as dt}from"./events.js";import{runActivity as at}from"./activity.js";import{cancelOpenQuestions as re,openQuestionIds as oe}from"./questions.js";import{appSpace as H}from"../layout.js";import{ensureAppSpace as ct}from"../spaces/space.js";import{assertUploadsUsable as ie,resolveStorageUrls as ut}from"../storage/attachments.js";import{storageClient as mt,storageConfig as lt}from"../storage/client.js";import{deleteUploadRow as ft,insertUploadUses as de,releaseRunUploads as _t}from"../storage/tables.js";import{abortProviderCalls as ae}from"../providers/inflight.js";const ce=m((e,t,r)=>ut(t,e,r),"defaultResolver"),pt=3e3;function wn(e){return Number(w(e,"UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}m(wn,"rewriteLocalIdempotencyGrantee");class S extends Error{static{m(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,r,s,i,c,d,o=t===503){super(s),this.status=t,this.code=r,this.param=i,this.details=c,this.scope=d,this.retryable=o}}const R=m((e,t)=>new S(400,"invalid_request",e,t),"invalid"),q=m(()=>new S(404,"not_found","run not found"),"missing"),U=m(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),O=m(()=>G(),"db");function C(e,t,r=!1){const s=N(e);if(!s||s.parent!==null||s.run_id!==e||s.grantee!==t||!r&&s.deleting_at)throw q();return s}m(C,"ownedRun");const P=["waiting_on_user","idle","settled"];function I(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=w(O(),`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),r=w(b(),"SELECT 1 FROM deliveries WHERE destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||r||!e.last_settled_at||tt(e)?"running":oe(e.node_id).length?"waiting_on_user":"idle"}m(I,"runStatus");function fn(e){const t=S(e);return t!==null&&I(t)==="running"}m(fn,"runIsRunning");function A(e){X(e.node_id),e=S(e.node_id)??e;const t=I(e),r=t==="settled"?[]:oe(e.node_id),s=Ue(e.node_id)||void 0,i=t==="settled"?nt(e):null,c=i?.kind==="result"?ee(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...i?{outcome:i}:{},...c===void 0?{}:{result:c},...s!==void 0?{last_report:s}:{},pending_question_ids:r,...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(U())),payer:"user",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:it(e.node_id,t)}}m(A,"runObject");const B=864e5,ue=255;function gn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>ue)throw N(`Idempotency-Key must be 1-${ue} characters`);return e}}m(gn,"idempotencyKeyOf");function x(e,t,r,s=G()){const i=w(s,"SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!i||Date.now()-Date.parse(i.created_at)>=B)){if(i.body_hash!==r)throw new R(409,"idempotency_conflict","key used with a different request");return{run_id:i.run_id,response:JSON.parse(i.response_json)}}}m(x,"findIdempotent");function me(e,t,r,s,i,c,d){w(e,"DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,r,new Date(Date.now()-B).toISOString()),w(e,"INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,r,s,i,JSON.stringify(c),d)}m(me,"recordIdempotent");function En(e=Date.now()){return L(t=>Number(w(t,"DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-B).toISOString()).changes))}m(En,"pruneExpiredIdempotencyKeys");function le(e,t,r,s,i){const c=s.text;let d=0;return{messageId:qe(t,{kind:"message",label:c.slice(0,120),senderNodeId:"human",senderName:r,bodyJson:i?{body:c}:{body:c,start_turn:!1},urgency:i?"normal":"deferred",wake:i?1:0,withinEnqueue:m((a,p)=>{s.uses.length&&(ie(r,s.uses,a),de(s.uses.map(({upload_id:y,path:E})=>({upload_id:y,path:E,run_id:t})),a)),d=se(a,t,t,"node.message.accepted",{message_id:p,start_turn:i}).sequence_number},"withinEnqueue")}).messageId,sequence:d}}m(le,"acceptRunMessage");class _e extends Error{static{m(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}async function wn(e,t,r,s=ce){if(t.isolated&&!Ve())throw new R(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");const i=J("sha256").update(JSON.stringify(t)).digest("hex");if(r){const n=x(e.grantee,r,i);if(n){const u=C(n.run_id,e.grantee);return!u.pi_pid&&I(u)==="running"&&(t.output_schema!==void 0&&!u.outcome_at&&et(u.node_id).state==="absent"&&ee(u.node_id,u.grantee)===void 0&&te(u.node_id,"terminal",t.output_schema),await F(u.node_id,{resume:!0,capacity:"freeze"})),n.response}}await dt(e.grantee);const c=t.profile===void 0?Pe(e.grantee):Be(t.profile),d=c.manifest.grantee??"app:terminal";if(d!==e.grantee){const n=`crtr:memory:rw:${d}:profile:${c.profileId}`;if(!e.resolved.some(u=>W(u,n))||t.scopes!==null&&!t.scopes.some(u=>W(u,n)))throw new R(403,"scope_missing",`missing scope ${n}`,"profile",void 0,n)}if(t.model!==void 0){const n=t.model;if(Xe(n)){if(n.includes("/")){const u=n.lastIndexOf("/"),h=n.slice(0,u),g=n.slice(u+1);if(["ultra","strong","medium","light"].includes(g)&&ze({kind:"logical",family:h,strength:g,spec:n},H(e.grantee).files,c.profileId).every(M=>M.family!==h))throw N(`model '${n}' names a model family that is not configured in this daemon`,"model")}}else if(Qe(n)===void 0)throw N(`model '${n}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const o=Je(),a=Ie(H(e.grantee).nodes,o);if(t.isolated&&t.cwd!==void 0){const n=be(a,De(t.cwd));if(!Y(t.cwd)||n===".."||n.startsWith(`..${Te}`)||Y(n))throw N("cwd must be inside the isolated root node folder","cwd")}const p=await s(o,e.grantee,t.prompt),y=p.text;let E;try{E=t.message===void 0?void 0:await s(o,e.grantee,t.message)}catch(n){throw p.cleanup(),n}let f;try{await Ge({kind:Ze(c),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??a:H(e.grantee).files,profile:c.profileId,prompt:y,nodeId:o,isolated:t.isolated??!1,...t.model===void 0?{}:{model:t.model},...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:o,event_cursor:1,usage_json:JSON.stringify(U())},withinCreate:m((n,u)=>{if(r){const g=x(e.grantee,r,i,n);if(g)throw new _e(g)}const h=p.uses;if(h.length&&(ie(e.grantee,h,n),de(h.map(({upload_id:g,path:M})=>({upload_id:g,path:M,run_id:o})),n)),Ye(o,y),f={run_id:o,node_id:o,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:u.created,metadata:t.metadata,sequence_number:0},se(n,o,o,"run.started",{scopes:t.scopes,payer:"user",usage:U()}),E){const g=le(n,o,e.grantee,E,!1);f.message={run_id:o,message_id:g.messageId,sequence_number:g.sequence}}r&&me(n,e.grantee,r,i,o,f,u.created)},"withinCreate")},t.output_schema===void 0?void 0:n=>{te(n,"terminal",t.output_schema)})}catch(n){if(S(o)||(p.cleanup(),E?.cleanup()),n instanceof _e)return n.winner.response;if(t.model!==void 0&&n instanceof Oe&&n.code==="usage")throw N(n.message,"model");if(n instanceof ve&&(n.code==="isolated_run"||n.code==="invalid_request")){const u=n.details&&typeof n.details=="object"&&"param"in n.details&&typeof n.details.param=="string"?n.details.param:void 0;throw new R(n.status,n.code,n.message,u)}throw n}if(!f)throw new Error("run creation did not commit");return f}m(wn,"startRun");function hn(e,t){let r;if(t.after)try{const o=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!o||typeof o!="object"||!("activity"in o)||typeof o.activity!="string"||!("id"in o)||typeof o.id!="string")throw new Error("invalid cursor");r={activity:o.activity,id:o.id}}catch{throw N("invalid list cursor","after")}const i=b().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
6
+ )) LIMIT 1`).get(e.node_id,e.node_id),r=w(O(),"SELECT 1 FROM deliveries WHERE destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||r||!e.last_settled_at||st(e)?"running":oe(e.node_id).length?"waiting_on_user":"idle"}m(I,"runStatus");function hn(e){const t=N(e);return t!==null&&I(t)==="running"}m(hn,"runIsRunning");function A(e){X(e.node_id),e=N(e.node_id)??e;const t=I(e),r=t==="settled"?[]:oe(e.node_id),s=Pe(e.node_id)||void 0,i=t==="settled"?rt(e):null,c=i?.kind==="result"?ee(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...i?{outcome:i}:{},...c===void 0?{}:{result:c},...s!==void 0?{last_report:s}:{},pending_question_ids:r,...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(U())),payer:"user",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:at(e.node_id,t)}}m(A,"runObject");const B=864e5,ue=255;function yn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>ue)throw R(`Idempotency-Key must be 1-${ue} characters`);return e}}m(yn,"idempotencyKeyOf");function x(e,t,r,s=G()){const i=w(s,"SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!i||Date.now()-Date.parse(i.created_at)>=B)){if(i.body_hash!==r)throw new S(409,"idempotency_conflict","key used with a different request");return{run_id:i.run_id,response:JSON.parse(i.response_json)}}}m(x,"findIdempotent");function me(e,t,r,s,i,c,d){w(e,"DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,r,new Date(Date.now()-B).toISOString()),w(e,"INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,r,s,i,JSON.stringify(c),d)}m(me,"recordIdempotent");function Rn(e=Date.now()){return L(t=>Number(w(t,"DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-B).toISOString()).changes))}m(Rn,"pruneExpiredIdempotencyKeys");function le(e,t,r,s,i){const c=s.text;let d=0;return{messageId:Ue(t,{kind:"message",label:c.slice(0,120),senderNodeId:"human",senderName:r,bodyJson:i?{body:c}:{body:c,start_turn:!1},urgency:i?"normal":"deferred",wake:i?1:0,withinEnqueue:m((a,_)=>{s.uses.length&&(ie(r,s.uses,a),de(s.uses.map(({upload_id:y,path:E})=>({upload_id:y,path:E,run_id:t})),a)),d=se(a,t,t,"node.message.accepted",{message_id:_,start_turn:i}).sequence_number},"withinEnqueue")}).messageId,sequence:d}}m(le,"acceptRunMessage");class fe extends Error{static{m(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const gt=1440*60*1e3;function _e(e){const t=typeof e=="string"?Qe(e):null;if(t===null||!Number.isSafeInteger(t))throw R(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw R("deadline must be greater than zero","deadline");if(t>gt)throw R("deadline must be at most 24h","deadline");return t}m(_e,"parseRunDeadlineMs");async function Sn(e,t,r,s=ce){if(t.isolated&&!Ke())throw new S(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&_e(t.deadline);const i=J("sha256").update(JSON.stringify(t)).digest("hex");if(r){const n=x(e.grantee,r,i);if(n){const u=C(n.run_id,e.grantee);return!u.pi_pid&&I(u)==="running"&&(t.output_schema!==void 0&&!u.outcome_at&&nt(u.node_id).state==="absent"&&ee(u.node_id,u.grantee)===void 0&&te(u.node_id,"terminal",t.output_schema),await F(u.node_id,{resume:!0,capacity:"freeze"})),n.response}}await ct(e.grantee);const c=t.profile===void 0?Be(e.grantee):$e(t.profile),d=c.manifest.grantee??"app:terminal";if(d!==e.grantee){const n=`crtr:memory:rw:${d}:profile:${c.profileId}`;if(!e.resolved.some(u=>W(u,n))||t.scopes!==null&&!t.scopes.some(u=>W(u,n)))throw new S(403,"scope_missing",`missing scope ${n}`,"profile",void 0,n)}if(t.model!==void 0){const n=t.model;if(ze(n)){if(n.includes("/")){const u=n.lastIndexOf("/"),h=n.slice(0,u),g=n.slice(u+1);if(["ultra","strong","medium","light"].includes(g)&&Ve({kind:"logical",family:h,strength:g,spec:n},H(e.grantee).files,c.profileId).every(T=>T.family!==h))throw R(`model '${n}' names a model family that is not configured in this daemon`,"model")}}else if(Ze(n)===void 0)throw R(`model '${n}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const o=Ye(),a=Te(H(e.grantee).nodes,o);if(t.isolated&&t.cwd!==void 0){const n=De(a,Me(t.cwd));if(!Y(t.cwd)||n===".."||n.startsWith(`..${Ie}`)||Y(n))throw R("cwd must be inside the isolated root node folder","cwd")}const _=await s(o,e.grantee,t.prompt),y=_.text;let E;try{E=t.message===void 0?void 0:await s(o,e.grantee,t.message)}catch(n){throw _.cleanup(),n}let p;try{await Xe({kind:et(c),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??a:H(e.grantee).files,profile:c.profileId,prompt:y,nodeId:o,isolated:t.isolated??!1,...t.model===void 0?{}:{model:t.model},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+_e(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:o,event_cursor:1,usage_json:JSON.stringify(U())},withinCreate:m((n,u)=>{if(r){const g=x(e.grantee,r,i,n);if(g)throw new fe(g)}const h=_.uses;if(h.length&&(ie(e.grantee,h,n),de(h.map(({upload_id:g,path:T})=>({upload_id:g,path:T,run_id:o})),n)),Ge(o,y),p={run_id:o,node_id:o,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:u.created,metadata:t.metadata,sequence_number:0},se(n,o,o,"run.started",{scopes:t.scopes,payer:"user",usage:U()}),E){const g=le(n,o,e.grantee,E,!1);p.message={run_id:o,message_id:g.messageId,sequence_number:g.sequence}}r&&me(n,e.grantee,r,i,o,p,u.created)},"withinCreate")},t.output_schema===void 0?void 0:n=>{te(n,"terminal",t.output_schema)})}catch(n){if(N(o)||(_.cleanup(),E?.cleanup()),n instanceof fe)return n.winner.response;if(t.model!==void 0&&n instanceof Oe&&n.code==="usage")throw R(n.message,"model");if(n instanceof be&&(n.code==="isolated_run"||n.code==="invalid_request")){const u=n.details&&typeof n.details=="object"&&"param"in n.details&&typeof n.details.param=="string"?n.details.param:void 0;throw new S(n.status,n.code,n.message,u)}throw n}if(!p)throw new Error("run creation did not commit");return p}m(Sn,"startRun");function Nn(e,t){let r;if(t.after)try{const o=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!o||typeof o!="object"||!("activity"in o)||typeof o.activity!="string"||!("id"in o)||typeof o.id!="string")throw new Error("invalid cursor");r={activity:o.activity,id:o.id}}catch{throw R("invalid list cursor","after")}const i=O().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
7
7
  WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}
8
- ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({node_id:o})=>!t.visible||t.visible(o)).filter(({activity:o,node_id:a})=>!r||o<r.activity||o===r.activity&&a<r.id).map(o=>({root:S(o.node_id),activity:o.activity})).filter(({root:o})=>!t.status||I(o)===t.status),c=i.slice(0,t.limit),d=c.at(-1);return{runs:c.map(({root:o})=>A(o)),next:i.length>t.limit&&d?Buffer.from(JSON.stringify({activity:d.activity,id:d.root.node_id})).toString("base64url"):null}}m(hn,"listRuns");async function yn(e,t,r){const s=C(e,t),i=m(()=>A(C(e,t)),"read");return!r||P.includes(I(s))?i():new Promise((c,d)=>{const o=m(()=>{clearTimeout(y),clearInterval(p),a();try{c(i())}catch(E){d(E)}},"finish"),a=ot(e,()=>{try{P.includes(String(i().status))&&o()}catch(E){clearTimeout(y),clearInterval(p),a(),d(E)}}),p=setInterval(()=>{P.includes(String(i().status))&&o()},250),y=setTimeout(o,r*1e3)})}m(yn,"waitRun");async function Rn(e,t,r=ce,s=!0,i){const c=e.status==="canceled"||e.outcome_reason==="closed",d=e.grantee??"app:terminal",o=J("sha256").update(JSON.stringify(["run.message",e.node_id,t,s])).digest("hex"),a=m(async f=>{const n=S(e.node_id),u=w(b(),"SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(f.message_id));return n&&!c&&s&&!n.pi_pid&&u&&await F(e.node_id,{resume:!0,capacity:"freeze"}),f},"replay");if(i){const f=x(d,i,o);if(f)return a(f.response)}if(c)throw new R(409,"run_settled","canceled run cannot receive a message");const p=await r(e.node_id,d,t),y=s&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;let E;try{E=L(f=>{if(i){const h=x(d,i,o,f);if(h)return{replayed:h.response}}y?.(e.node_id);const n=le(f,e.node_id,d,p,s),u={run_id:e.node_id,message_id:n.messageId,sequence_number:n.sequence};return i&&me(f,d,i,o,e.node_id,u,new Date().toISOString()),{result:u}})}catch(f){throw p.cleanup(),f}return"replayed"in E?(p.cleanup(),a(E.replayed)):(s&&!e.pi_pid&&await F(e.node_id,{resume:!0,capacity:"freeze"}),E.result)}m(Rn,"messageRun");async function pt(e){const t=m(()=>new R(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let r=0;r<2;r++){const s=S(e);if(!s)throw q();if(!Z(s)){if(s.streaming)throw t();return}const i=z(e)?.executionId;try{await je(e)==="turn"&&ae({nodes:[e]});return}catch(c){if(!(c instanceof $e))throw c;const d=S(e);if(!d)throw q();if(!d.streaming)return;if(r===0&&Z(d)&&z(e)?.executionId!==i)continue;throw t()}}throw t()}m(pt,"interruptNode");async function Sn(e,t="stop"){const r=t==="stop"?w(b(),"SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:s})=>s):[e.node_id];return await Promise.all(r.map(s=>pt(s))),A(S(e.node_id)??e)}m(Sn,"interruptRun");async function Nn(e,t={}){const r=w(b(),"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(d=>d.node_id);ae({run:e.node_id});const s=[];if(I(e)!=="settled")s.push(...ne(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const d of r){if(d===e.node_id)continue;const o=S(d);o&&o.status!=="done"&&o.status!=="canceled"&&o.status!=="dead"&&s.push(...ne(d,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await re({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...s])].map(d=>V(d,"run_canceled")))).some(d=>!d.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const c=S(e.node_id);return A(c??e)}m(Nn,"cancelRun");const pe=200;function vn(e,t){if(typeof t!="string"||!t.trim())throw N("name is required","name");const r=t.trim();if(r.length>pe)throw N(`name exceeds ${pe} characters`,"name");const s=ke(e.node_id,{name:r});return s.window&&Fe(s.window,We(s)),A(s)}m(vn,"renameRun");async function On(e,t={config:ut,client:ct}){await re({run_id:e.node_id},"the run was deleted");const r=L(a=>(w(a,"UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),w(a,"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(p=>p.node_id)));if((await Promise.all(r.map(a=>V(a,"run_deleted",{deleting:!0})))).some(a=>!a.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const i=r.map(a=>{const p=Ce(a);if(p.app===null)throw new Error(`run node missing during deletion: ${a}`);return p}),c=w(b(),"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:a}of c)try{Q().delete(a)}catch(p){if(!He(p))throw p}const d=L(a=>{for(const f of r){const n=Le(a,f);n!==null&&n.deleted_at===null&&Ae(a,n)}const p=lt([e.node_id],a);w(a,"DELETE FROM run_events WHERE run_id = ?").run(e.node_id),w(a,"DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const y=r.map(()=>"?").join(","),E=a.prepare(`SELECT message_id FROM messages WHERE sender_node_id IN (${y}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${y})`).all(...r,...r);a.prepare(`DELETE FROM deliveries WHERE destination_id IN (${y})`).run(...r);for(const{message_id:f}of E)w(a,"DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(f,f);return p});for(const a of i)xe(a);const{notifyRunDeleted:o}=await import("./events.js");return o(e.node_id),{uploads_pending:await ft(d,t)}}m(On,"deleteRun");async function ft(e,t){if(!e.length||!t.config())return e.length;let r;try{r=t.client()}catch{return e.length}const s=new Set,i=e.map(d=>r.deleteUpload(d).then(()=>{mt(d),s.add(d)},()=>{}));let c;return await Promise.race([Promise.all(i),new Promise(d=>{c=setTimeout(d,t.budgetMs??_t),c.unref?.()})]),clearTimeout(c),e.length-s.size}m(ft,"deleteReleasedUploads");function bn(e,t,r){C(e,t),X(e);const s=b();s.exec("BEGIN");try{const c=w(s,"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).map(n=>({node_id:n.node_id,parent_node_id:n.parent,conversations:w(s,"SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(n.node_id).map(({session_id:u})=>{const{header:h,entries:g}=Q().read(u);if(r==="entries")return{conversation_id:u,header:h,entries:g};const M=Me.inMemory(h.cwd,void 0,[h,...g]),fe=Ke(M)??[],$=new Map(g.map((_,v)=>[_.id,v])),ge=g.filter(_=>_.type==="custom"&&_.customType==="crtr-system-prompt").map(_=>({id:_.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in _?_.data:void 0,timestamp:_.timestamp}})),j=g.filter(_=>_.type==="custom_message"&&_.customType==="app_message").map(_=>({id:_.id,message:{role:"custom",customType:"app_message",content:"content"in _?_.content:"",timestamp:_.timestamp}})),Ee=n.node_id===e?g.find(_=>{if(_.type!=="message"||_.message.role!=="user")return!1;const v=K(g,_.message.timestamp);return v?.type==="runtime"&&v.kind==="kickoff"})?.id:void 0,we=[...fe.filter(({id:_})=>!j.some(v=>v.id===_)),...ge,...j].sort((_,v)=>($.get(_.id)??Number.MAX_SAFE_INTEGER)-($.get(v.id)??Number.MAX_SAFE_INTEGER)).map(({id:_,message:v})=>{const l=v,D=l.usage,k=l.role==="user"?K(g,Number(l.timestamp)):null,he=k?.type==="human"||_===Ee,T=l.role==="toolResult"?"tool_result":l.role==="bashExecution"?"bash_execution":l.role==="compactionSummary"?"compaction_summary":l.role==="branchSummary"?"branch_summary":l.role==="custom"&&l.customType==="crtr-system-prompt"?"system":l.role==="user"?he?"user":"custom":l.role,ye=T==="custom"?l.role==="custom"?l.customType:k?.type==="runtime"?k.kind:"unknown":void 0,Re=T==="system"&&l.customType==="crtr-system-prompt"?[{type:"text",text:l.data?.text??""}]:typeof l.content=="string"?[{type:"text",text:l.content}]:Array.isArray(l.content)?l.content.map(O=>O.type==="toolCall"?{type:"tool_call",tool_call_id:O.id,name:O.name,arguments:O.arguments}:O.type==="image"?{type:"image",mime_type:O.mimeType}:O.type==="thinking"?{type:"thinking",text:O.thinking}:O):[];return{entry_id:_,role:T,...T==="custom"?{custom_type:ye}:{},time:typeof l.timestamp=="string"?l.timestamp:new Date(Number(l.timestamp??Date.now())).toISOString(),content:Re,...T==="assistant"?{model:l.model,provider:l.provider,stop_reason:l.stopReason,...l.errorMessage?{error_message:l.errorMessage}:{},...D?{usage:{input_tokens:D.input??0,output_tokens:D.output??0,cache_read_tokens:D.cacheRead??0,cache_write_tokens:D.cacheWrite??0,cost_usd:D.cost?.total??0}}:{}}:{},...T==="tool_result"?{tool_call_id:l.toolCallId,tool_name:l.toolName,is_error:l.isError}:{}}})??[];return{conversation_id:u,messages:we}})})),o=w(s,"SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,a=new Map(c.map(n=>[n.node_id,st(n.node_id)])),p=w(s,`SELECT node_id, sequence_number FROM run_events
8
+ ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({node_id:o})=>!t.visible||t.visible(o)).filter(({activity:o,node_id:a})=>!r||o<r.activity||o===r.activity&&a<r.id).map(o=>({root:N(o.node_id),activity:o.activity})).filter(({root:o})=>!t.status||I(o)===t.status),c=i.slice(0,t.limit),d=c.at(-1);return{runs:c.map(({root:o})=>A(o)),next:i.length>t.limit&&d?Buffer.from(JSON.stringify({activity:d.activity,id:d.root.node_id})).toString("base64url"):null}}m(Nn,"listRuns");async function vn(e,t,r){const s=C(e,t),i=m(()=>A(C(e,t)),"read");return!r||P.includes(I(s))?i():new Promise((c,d)=>{const o=m(()=>{clearTimeout(y),clearInterval(_),a();try{c(i())}catch(E){d(E)}},"finish"),a=dt(e,()=>{try{P.includes(String(i().status))&&o()}catch(E){clearTimeout(y),clearInterval(_),a(),d(E)}}),_=setInterval(()=>{P.includes(String(i().status))&&o()},250),y=setTimeout(o,r*1e3)})}m(vn,"waitRun");async function bn(e,t,r=ce,s=!0,i){const c=e.status==="canceled"||e.outcome_reason==="closed",d=e.grantee??"app:terminal",o=J("sha256").update(JSON.stringify(["run.message",e.node_id,t,s])).digest("hex"),a=m(async p=>{const n=N(e.node_id),u=w(O(),"SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(p.message_id));return n&&!c&&s&&!n.pi_pid&&u&&await F(e.node_id,{resume:!0,capacity:"freeze"}),p},"replay");if(i){const p=x(d,i,o);if(p)return a(p.response)}if(c)throw new S(409,"run_settled","canceled run cannot receive a message");const _=await r(e.node_id,d,t),y=s&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;let E;try{E=L(p=>{if(i){const h=x(d,i,o,p);if(h)return{replayed:h.response}}y?.(e.node_id);const n=le(p,e.node_id,d,_,s),u={run_id:e.node_id,message_id:n.messageId,sequence_number:n.sequence};return i&&me(p,d,i,o,e.node_id,u,new Date().toISOString()),{result:u}})}catch(p){throw _.cleanup(),p}return"replayed"in E?(_.cleanup(),a(E.replayed)):(s&&!e.pi_pid&&await F(e.node_id,{resume:!0,capacity:"freeze"}),E.result)}m(bn,"messageRun");async function Et(e){const t=m(()=>new S(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let r=0;r<2;r++){const s=N(e);if(!s)throw q();if(!Z(s)){if(s.streaming)throw t();return}const i=z(e)?.executionId;try{await Je(e)==="turn"&&ae({nodes:[e]});return}catch(c){if(!(c instanceof je))throw c;const d=N(e);if(!d)throw q();if(!d.streaming)return;if(r===0&&Z(d)&&z(e)?.executionId!==i)continue;throw t()}}throw t()}m(Et,"interruptNode");async function On(e,t="stop"){const r=t==="stop"?w(O(),"SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:s})=>s):[e.node_id];return await Promise.all(r.map(s=>Et(s))),A(N(e.node_id)??e)}m(On,"interruptRun");async function Dn(e,t={}){const r=w(O(),"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(d=>d.node_id);ae({run:e.node_id});const s=[];if(I(e)!=="settled")s.push(...ne(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const d of r){if(d===e.node_id)continue;const o=N(d);o&&o.status!=="done"&&o.status!=="canceled"&&o.status!=="dead"&&s.push(...ne(d,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await re({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...s])].map(d=>V(d,"run_canceled")))).some(d=>!d.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const c=N(e.node_id);return A(c??e)}m(Dn,"cancelRun");const pe=200;function Mn(e,t){if(typeof t!="string"||!t.trim())throw R("name is required","name");const r=t.trim();if(r.length>pe)throw R(`name exceeds ${pe} characters`,"name");const s=We(e.node_id,{name:r});return s.window&&He(s.window,Fe(s)),A(s)}m(Mn,"renameRun");async function In(e,t={config:lt,client:mt}){await re({run_id:e.node_id},"the run was deleted");const r=L(a=>(w(a,"UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),w(a,"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(_=>_.node_id)));if((await Promise.all(r.map(a=>V(a,"run_deleted",{deleting:!0})))).some(a=>!a.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const i=r.map(a=>{const _=xe(a);if(_.app===null)throw new Error(`run node missing during deletion: ${a}`);return _}),c=w(O(),"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:a}of c)try{Q().delete(a)}catch(_){if(!qe(_))throw _}const d=L(a=>{for(const p of r){const n=Ce(a,p);n!==null&&n.deleted_at===null&&Le(a,n)}const _=_t([e.node_id],a);w(a,"DELETE FROM run_events WHERE run_id = ?").run(e.node_id),w(a,"DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const y=r.map(()=>"?").join(","),E=a.prepare(`SELECT message_id FROM messages WHERE sender_node_id IN (${y}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${y})`).all(...r,...r);a.prepare(`DELETE FROM deliveries WHERE destination_id IN (${y})`).run(...r);for(const{message_id:p}of E)w(a,"DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(p,p);return _});for(const a of i)ke(a);const{notifyRunDeleted:o}=await import("./events.js");return o(e.node_id),{uploads_pending:await wt(d,t)}}m(In,"deleteRun");async function wt(e,t){if(!e.length||!t.config())return e.length;let r;try{r=t.client()}catch{return e.length}const s=new Set,i=e.map(d=>r.deleteUpload(d).then(()=>{ft(d),s.add(d)},()=>{}));let c;return await Promise.race([Promise.all(i),new Promise(d=>{c=setTimeout(d,t.budgetMs??pt),c.unref?.()})]),clearTimeout(c),e.length-s.size}m(wt,"deleteReleasedUploads");function Tn(e,t,r){C(e,t),X(e);const s=O();s.exec("BEGIN");try{const c=w(s,"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).map(n=>({node_id:n.node_id,parent_node_id:n.parent,conversations:w(s,"SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(n.node_id).map(({session_id:u})=>{const{header:h,entries:g}=Q().read(u);if(r==="entries")return{conversation_id:u,header:h,entries:g};const T=Ae.inMemory(h.cwd,void 0,[h,...g]),ge=tt(T)??[],$=new Map(g.map((f,v)=>[f.id,v])),Ee=g.filter(f=>f.type==="custom"&&f.customType==="crtr-system-prompt").map(f=>({id:f.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in f?f.data:void 0,timestamp:f.timestamp}})),j=g.filter(f=>f.type==="custom_message"&&f.customType==="app_message").map(f=>({id:f.id,message:{role:"custom",customType:"app_message",content:"content"in f?f.content:"",timestamp:f.timestamp}})),we=n.node_id===e?g.find(f=>{if(f.type!=="message"||f.message.role!=="user")return!1;const v=K(g,f.message.timestamp);return v?.type==="runtime"&&v.kind==="kickoff"})?.id:void 0,he=[...ge.filter(({id:f})=>!j.some(v=>v.id===f)),...Ee,...j].sort((f,v)=>($.get(f.id)??Number.MAX_SAFE_INTEGER)-($.get(v.id)??Number.MAX_SAFE_INTEGER)).map(({id:f,message:v})=>{const l=v,D=l.usage,k=l.role==="user"?K(g,Number(l.timestamp)):null,ye=k?.type==="human"||f===we,M=l.role==="toolResult"?"tool_result":l.role==="bashExecution"?"bash_execution":l.role==="compactionSummary"?"compaction_summary":l.role==="branchSummary"?"branch_summary":l.role==="custom"&&l.customType==="crtr-system-prompt"?"system":l.role==="user"?ye?"user":"custom":l.role,Re=M==="custom"?l.role==="custom"?l.customType:k?.type==="runtime"?k.kind:"unknown":void 0,Se=M==="system"&&l.customType==="crtr-system-prompt"?[{type:"text",text:l.data?.text??""}]:typeof l.content=="string"?[{type:"text",text:l.content}]:Array.isArray(l.content)?l.content.map(b=>b.type==="toolCall"?{type:"tool_call",tool_call_id:b.id,name:b.name,arguments:b.arguments}:b.type==="image"?{type:"image",mime_type:b.mimeType}:b.type==="thinking"?{type:"thinking",text:b.thinking}:b):[];return{entry_id:f,role:M,...M==="custom"?{custom_type:Re}:{},time:typeof l.timestamp=="string"?l.timestamp:new Date(Number(l.timestamp??Date.now())).toISOString(),content:Se,...M==="assistant"?{model:l.model,provider:l.provider,stop_reason:l.stopReason,...l.errorMessage?{error_message:l.errorMessage}:{},...D?{usage:{input_tokens:D.input??0,output_tokens:D.output??0,cache_read_tokens:D.cacheRead??0,cache_write_tokens:D.cacheWrite??0,cost_usd:D.cost?.total??0}}:{}}:{},...M==="tool_result"?{tool_call_id:l.toolCallId,tool_name:l.toolName,is_error:l.isError}:{}}})??[];return{conversation_id:u,messages:he}})})),o=w(s,"SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,a=new Map(c.map(n=>[n.node_id,ot(n.node_id)])),_=w(s,`SELECT node_id, sequence_number FROM run_events
9
9
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
10
- ORDER BY sequence_number`).all(e,o);for(const n of p){const u=a.get(n.node_id);u!=null&&n.sequence_number>=u&&a.set(n.node_id,null)}const y=w(s,`SELECT node_id, sequence_number, type, body_json FROM run_events
10
+ ORDER BY sequence_number`).all(e,o);for(const n of _){const u=a.get(n.node_id);u!=null&&n.sequence_number>=u&&a.set(n.node_id,null)}const y=w(s,`SELECT node_id, sequence_number, type, body_json FROM run_events
11
11
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
12
- ORDER BY sequence_number`).all(e,o),E=new Map;for(const n of y){const u=a.get(n.node_id);if(u==null||n.sequence_number<u)continue;const h=JSON.parse(n.body_json),g=E.get(n.node_id)??{thinking:"",text:""};n.type==="node.thinking.delta"?g.thinking+=h.delta:g.text+=h.delta,E.set(n.node_id,g)}const f=c.map(n=>({...n,in_progress_message:a.get(n.node_id)==null?null:E.get(n.node_id)??{thinking:"",text:""}}));return s.exec("COMMIT"),{run_id:e,latest_sequence:o,nodes:f}}catch(i){throw s.exec("ROLLBACK"),i}}m(bn,"traceRun");function Dn(e,t,r){if(t===void 0){if(!e.some(s=>W(s,"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(s=>typeof s!="string"))throw N("scopes must be a list of scope strings","scopes");for(const s of t){try{rt(s)}catch{throw N(`invalid scope ${s}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(s)&&s.split(":")[4]===r.slice(4))throw N(`own-app files cannot narrow a run: ${s}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(s)&&s.split(":")[4]===r.slice(4))&&!Ne(e,s))throw new R(403,"scope_missing",`missing scope ${s}`,void 0,void 0,s)}if(!t.includes("crtr:llm"))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}m(Dn,"requestedScopes");export{B as IDEMPOTENCY_WINDOW_MS,_t as RUN_DELETE_STORAGE_BUDGET_MS,pe as RUN_NAME_MAX,R as RunError,Nn as cancelRun,On as deleteRun,gn as idempotencyKeyOf,Sn as interruptRun,hn as listRuns,Rn as messageRun,C as ownedRun,En as pruneExpiredIdempotencyKeys,vn as renameRun,Dn as requestedScopes,pn as rewriteLocalIdempotencyGrantee,fn as runIsRunning,A as runObject,wn as startRun,bn as traceRun,yn as waitRun};
12
+ ORDER BY sequence_number`).all(e,o),E=new Map;for(const n of y){const u=a.get(n.node_id);if(u==null||n.sequence_number<u)continue;const h=JSON.parse(n.body_json),g=E.get(n.node_id)??{thinking:"",text:""};n.type==="node.thinking.delta"?g.thinking+=h.delta:g.text+=h.delta,E.set(n.node_id,g)}const p=c.map(n=>({...n,in_progress_message:a.get(n.node_id)==null?null:E.get(n.node_id)??{thinking:"",text:""}}));return s.exec("COMMIT"),{run_id:e,latest_sequence:o,nodes:p}}catch(i){throw s.exec("ROLLBACK"),i}}m(Tn,"traceRun");function An(e,t,r){if(t===void 0){if(!e.some(s=>W(s,"crtr:llm")))throw new S(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(s=>typeof s!="string"))throw R("scopes must be a list of scope strings","scopes");for(const s of t){try{it(s)}catch{throw R(`invalid scope ${s}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(s)&&s.split(":")[4]===r.slice(4))throw R(`own-app files cannot narrow a run: ${s}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(s)&&s.split(":")[4]===r.slice(4))&&!ve(e,s))throw new S(403,"scope_missing",`missing scope ${s}`,void 0,void 0,s)}if(!t.includes("crtr:llm"))throw new S(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}m(An,"requestedScopes");export{B as IDEMPOTENCY_WINDOW_MS,gt as RUN_DEADLINE_MAX_MS,pt as RUN_DELETE_STORAGE_BUDGET_MS,pe as RUN_NAME_MAX,S as RunError,Dn as cancelRun,In as deleteRun,yn as idempotencyKeyOf,On as interruptRun,Nn as listRuns,bn as messageRun,C as ownedRun,_e as parseRunDeadlineMs,Rn as pruneExpiredIdempotencyKeys,Mn as renameRun,An as requestedScopes,wn as rewriteLocalIdempotencyGrantee,hn as runIsRunning,A as runObject,Sn as startRun,Tn as traceRun,vn as waitRun};
@@ -1 +1 @@
1
- var R=Object.defineProperty;var m=(a,t)=>R(a,"name",{value:t,configurable:!0});import{callerGrant as h}from"../principal.js";import{grantVersion as g}from"../../../core/grants/mirror.js";import{waitGrantChange as S}from"../../../core/grants/watch.js";import{RunError as n,idempotencyKeyOf as b,cancelRun as $,deleteRun as N,interruptRun as O,listRuns as A,messageRun as j,renameRun as x,requestedScopes as B,startRun as J,traceRun as z,waitRun as C}from"../../../core/runs/operations.js";import{canReadRun as v,requireRun as f,runCallerApp as E}from"../router.js";import{waitSeconds as y}from"../long-poll-wait.js";import{outputSchemaProblem as K}from"../../../core/runtime/structured-output.js";function l(a){if(!a||typeof a!="object"||Array.isArray(a))throw new n(400,"invalid_request","a JSON object is required");return a}m(l,"object");function q(a,t,i,u,d){if(a===null)return d;if(!/^(0|[1-9]\d*)$/.test(a)||!Number.isSafeInteger(Number(a))||Number(a)<i||Number(a)>u)throw new n(400,"invalid_request",`invalid ${t}`,t);return Number(a)}m(q,"integer");const T=256*1024;async function W(a,t,i,u,d,_){switch(a.name){case"grant.get":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=y("grant.get",u),s=u.get("since");if(s!==null&&!/^[A-Za-z0-9_-]{1,64}$/.test(s))throw new n(400,"invalid_request","invalid since","since");let o=h(t);return e&&s!==null&&g(o)===s&&(await S(t.grant,e),o=h(t)),{status:200,body:{sub:t.sub,grantee:t.grantee,client_id:t.client_id,grant:t.grant,rev:o.rev,resolved_scopes:o.resolved_scopes,spend_cap:o.spend_cap,exp:t.exp,payer:"user",dependencies:o.dependencies??{},version:g(o)}}}case"run.start":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=l(d),s=["mode","parent","fork_from","node_id","env","tools","system_prompt"];for(const r of s)if(e[r]!==void 0)throw new n(403,"owner_only",`${r} is owner-only`,r);const o=["payer","model_policy","deadline","kind"];for(const r of o)if(e[r]!==void 0)throw new n(400,"invalid_request",`${r} is not available`,r);for(const r of Object.keys(e))if(!["prompt","scopes","metadata","profile","isolated","cwd","worktree","output_schema","message","model"].includes(r))throw new n(400,"invalid_request",`unknown field ${r}`,r);if(e.model!==void 0&&(typeof e.model!="string"||!e.model.trim()))throw new n(400,"invalid_request","model must be a non-empty string","model");if(e.profile!==void 0&&(typeof e.profile!="string"||!e.profile))throw new n(400,"invalid_request","profile must be a profile id","profile");if(e.isolated!==void 0&&typeof e.isolated!="boolean")throw new n(400,"invalid_request","isolated must be a boolean","isolated");if(e.cwd!==void 0&&(e.isolated!==!0||typeof e.cwd!="string"||!e.cwd))throw new n(400,"invalid_request","cwd is available only for an isolated run and must be an absolute path inside its root folder","cwd");if(e.worktree!==void 0&&e.isolated!==!0)throw new n(400,"invalid_request","worktree is not available","worktree");if(e.isolated===!0&&e.worktree!==void 0)throw new n(400,"invalid_request","worktree is unavailable for an isolated run","worktree");if(typeof e.prompt!="string"||!e.prompt.trim())throw new n(400,"invalid_request","prompt is required","prompt");if(e.message!==void 0&&(typeof e.message!="string"||!e.message.trim()))throw new n(400,"invalid_request","message must be a non-empty string","message");const w=e.metadata===void 0?{}:l(e.metadata);if(Buffer.byteLength(JSON.stringify(w))>4096)throw new n(400,"invalid_request","metadata exceeds 4 KB","metadata");let c;if(e.output_schema!==void 0){const r=e.output_schema;if(!r||typeof r!="object"||Array.isArray(r))throw new n(400,"invalid_request","output_schema must be a JSON Schema object","output_schema");if(Buffer.byteLength(JSON.stringify(r))>T)throw new n(400,"invalid_request","output_schema exceeds 256 KB","output_schema");const p=await K(r);if(p!==null)throw new n(400,"invalid_request",`output_schema is not usable: ${p}`,"output_schema");c=r}const k=B(t.resolved,e.scopes,t.grantee);return{status:201,body:await J(t,{prompt:e.prompt,scopes:k,metadata:w,profile:e.profile,isolated:e.isolated,cwd:e.cwd,...e.model===void 0?{}:{model:e.model},...c===void 0?{}:{output_schema:c},...e.message===void 0?{}:{message:e.message}},b(_))}}case"run.list":{const e=u.get("status")??void 0;if(e&&!["running","waiting_on_user","idle","settled"].includes(e))throw new n(400,"invalid_request","invalid status","status");const s=u.get("app");if(s!==null&&!/^(?:app:)?[a-z0-9][a-z0-9-]*$/.test(s))throw new n(400,"invalid_request","invalid app","app");const o=s===null?E(t):s.startsWith("app:")?s:`app:${s}`;if(o!==null&&!v(t,o))throw new n(404,"not_found","run not found");return{status:200,body:A(o,{status:e,after:u.get("after")??void 0,limit:q(u.get("limit"),"limit",1,100,50),..."class"in t&&(t.class==="broker"||t.class==="cron")&&o!==null?{visible:m(w=>v(t,o,w),"visible")}:{}})}}case"run.get":{const e=y("run.get",u),s=f(t,i),o=await C(i,s.grantee,e);return f(t,i),{status:200,body:o}}case"run.message":{const e=l(d);if(typeof e.message!="string"||!e.message.trim())throw new n(400,"invalid_request","message is required","message");if(e.start_turn!==void 0&&typeof e.start_turn!="boolean")throw new n(400,"invalid_request","start_turn must be a boolean","start_turn");return{status:202,body:await j(f(t,i,!0),e.message,void 0,e.start_turn,b(_))}}case"run.interrupt":{const e=l(d===void 0?{}:d);if(e.children!==void 0&&e.children!=="stop"&&e.children!=="continue")throw new n(400,"invalid_request","invalid children","children");return{status:200,body:await O(f(t,i,!0),e.children)}}case"run.cancel":{const e=l(d===void 0?{}:d);if(e.keep_schedules!==void 0&&typeof e.keep_schedules!="boolean")throw new n(400,"invalid_request","invalid keep_schedules","keep_schedules");return{status:200,body:await $(f(t,i,!0),{keepSchedules:e.keep_schedules})}}case"run.rename":{const e=l(d);for(const s of Object.keys(e))if(s!=="name")throw new n(400,"invalid_request",`unknown field ${s}`,s);return{status:200,body:x(f(t,i,!0),e.name)}}case"run.delete":{const{uploads_pending:e}=await N(f(t,i,!0,!0));return{status:200,body:{run_id:i,uploads_pending:e}}}case"trace.get":{const e=u.get("format")??void 0;if(e&&e!=="entries")throw new n(400,"invalid_request","unknown trace format","format");const s=f(t,i);return{status:200,body:z(i,s.grantee,e)}}default:throw new n(404,"not_found","unknown operation")}}m(W,"handleRunOperation");export{W as handleRunOperation,q as integer};
1
+ var R=Object.defineProperty;var m=(a,t)=>R(a,"name",{value:t,configurable:!0});import{callerGrant as h}from"../principal.js";import{grantVersion as g}from"../../../core/grants/mirror.js";import{waitGrantChange as S}from"../../../core/grants/watch.js";import{RunError as n,idempotencyKeyOf as b,cancelRun as $,deleteRun as N,interruptRun as O,listRuns as A,messageRun as j,renameRun as x,requestedScopes as B,startRun as J,traceRun as z,waitRun as C}from"../../../core/runs/operations.js";import{canReadRun as v,requireRun as l,runCallerApp as E}from"../router.js";import{waitSeconds as y}from"../long-poll-wait.js";import{outputSchemaProblem as K}from"../../../core/runtime/structured-output.js";function f(a){if(!a||typeof a!="object"||Array.isArray(a))throw new n(400,"invalid_request","a JSON object is required");return a}m(f,"object");function q(a,t,i,d,u){if(a===null)return u;if(!/^(0|[1-9]\d*)$/.test(a)||!Number.isSafeInteger(Number(a))||Number(a)<i||Number(a)>d)throw new n(400,"invalid_request",`invalid ${t}`,t);return Number(a)}m(q,"integer");const T=256*1024;async function W(a,t,i,d,u,_){switch(a.name){case"grant.get":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=y("grant.get",d),s=d.get("since");if(s!==null&&!/^[A-Za-z0-9_-]{1,64}$/.test(s))throw new n(400,"invalid_request","invalid since","since");let o=h(t);return e&&s!==null&&g(o)===s&&(await S(t.grant,e),o=h(t)),{status:200,body:{sub:t.sub,grantee:t.grantee,client_id:t.client_id,grant:t.grant,rev:o.rev,resolved_scopes:o.resolved_scopes,spend_cap:o.spend_cap,exp:t.exp,payer:"user",dependencies:o.dependencies??{},version:g(o)}}}case"run.start":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=f(u),s=["mode","parent","fork_from","node_id","env","tools","system_prompt"];for(const r of s)if(e[r]!==void 0)throw new n(403,"owner_only",`${r} is owner-only`,r);const o=["payer","model_policy","kind"];for(const r of o)if(e[r]!==void 0)throw new n(400,"invalid_request",`${r} is not available`,r);for(const r of Object.keys(e))if(!["prompt","scopes","metadata","profile","isolated","cwd","worktree","output_schema","message","model","deadline"].includes(r))throw new n(400,"invalid_request",`unknown field ${r}`,r);if(e.model!==void 0&&(typeof e.model!="string"||!e.model.trim()))throw new n(400,"invalid_request","model must be a non-empty string","model");if(e.deadline!==void 0&&(typeof e.deadline!="string"||!e.deadline.trim()))throw new n(400,"invalid_request","deadline must be a duration string such as 10m","deadline");if(e.profile!==void 0&&(typeof e.profile!="string"||!e.profile))throw new n(400,"invalid_request","profile must be a profile id","profile");if(e.isolated!==void 0&&typeof e.isolated!="boolean")throw new n(400,"invalid_request","isolated must be a boolean","isolated");if(e.cwd!==void 0&&(e.isolated!==!0||typeof e.cwd!="string"||!e.cwd))throw new n(400,"invalid_request","cwd is available only for an isolated run and must be an absolute path inside its root folder","cwd");if(e.worktree!==void 0&&e.isolated!==!0)throw new n(400,"invalid_request","worktree is not available","worktree");if(e.isolated===!0&&e.worktree!==void 0)throw new n(400,"invalid_request","worktree is unavailable for an isolated run","worktree");if(typeof e.prompt!="string"||!e.prompt.trim())throw new n(400,"invalid_request","prompt is required","prompt");if(e.message!==void 0&&(typeof e.message!="string"||!e.message.trim()))throw new n(400,"invalid_request","message must be a non-empty string","message");const w=e.metadata===void 0?{}:f(e.metadata);if(Buffer.byteLength(JSON.stringify(w))>4096)throw new n(400,"invalid_request","metadata exceeds 4 KB","metadata");let c;if(e.output_schema!==void 0){const r=e.output_schema;if(!r||typeof r!="object"||Array.isArray(r))throw new n(400,"invalid_request","output_schema must be a JSON Schema object","output_schema");if(Buffer.byteLength(JSON.stringify(r))>T)throw new n(400,"invalid_request","output_schema exceeds 256 KB","output_schema");const p=await K(r);if(p!==null)throw new n(400,"invalid_request",`output_schema is not usable: ${p}`,"output_schema");c=r}const k=B(t.resolved,e.scopes,t.grantee);return{status:201,body:await J(t,{prompt:e.prompt,scopes:k,metadata:w,profile:e.profile,isolated:e.isolated,cwd:e.cwd,...e.model===void 0?{}:{model:e.model},...e.deadline===void 0?{}:{deadline:e.deadline},...c===void 0?{}:{output_schema:c},...e.message===void 0?{}:{message:e.message}},b(_))}}case"run.list":{const e=d.get("status")??void 0;if(e&&!["running","waiting_on_user","idle","settled"].includes(e))throw new n(400,"invalid_request","invalid status","status");const s=d.get("app");if(s!==null&&!/^(?:app:)?[a-z0-9][a-z0-9-]*$/.test(s))throw new n(400,"invalid_request","invalid app","app");const o=s===null?E(t):s.startsWith("app:")?s:`app:${s}`;if(o!==null&&!v(t,o))throw new n(404,"not_found","run not found");return{status:200,body:A(o,{status:e,after:d.get("after")??void 0,limit:q(d.get("limit"),"limit",1,100,50),..."class"in t&&(t.class==="broker"||t.class==="cron")&&o!==null?{visible:m(w=>v(t,o,w),"visible")}:{}})}}case"run.get":{const e=y("run.get",d),s=l(t,i),o=await C(i,s.grantee,e);return l(t,i),{status:200,body:o}}case"run.message":{const e=f(u);if(typeof e.message!="string"||!e.message.trim())throw new n(400,"invalid_request","message is required","message");if(e.start_turn!==void 0&&typeof e.start_turn!="boolean")throw new n(400,"invalid_request","start_turn must be a boolean","start_turn");return{status:202,body:await j(l(t,i,!0),e.message,void 0,e.start_turn,b(_))}}case"run.interrupt":{const e=f(u===void 0?{}:u);if(e.children!==void 0&&e.children!=="stop"&&e.children!=="continue")throw new n(400,"invalid_request","invalid children","children");return{status:200,body:await O(l(t,i,!0),e.children)}}case"run.cancel":{const e=f(u===void 0?{}:u);if(e.keep_schedules!==void 0&&typeof e.keep_schedules!="boolean")throw new n(400,"invalid_request","invalid keep_schedules","keep_schedules");return{status:200,body:await $(l(t,i,!0),{keepSchedules:e.keep_schedules})}}case"run.rename":{const e=f(u);for(const s of Object.keys(e))if(s!=="name")throw new n(400,"invalid_request",`unknown field ${s}`,s);return{status:200,body:x(l(t,i,!0),e.name)}}case"run.delete":{const{uploads_pending:e}=await N(l(t,i,!0,!0));return{status:200,body:{run_id:i,uploads_pending:e}}}case"trace.get":{const e=d.get("format")??void 0;if(e&&e!=="entries")throw new n(400,"invalid_request","unknown trace format","format");const s=l(t,i);return{status:200,body:z(i,s.grantee,e)}}default:throw new n(404,"not_found","unknown operation")}}m(W,"handleRunOperation");export{W as handleRunOperation,q as integer};
@@ -7,6 +7,12 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
+ ## 0.3.482
11
+
12
+ ### `runs.start` accepts `deadline` (additive, no app change)
13
+
14
+ `RunStartParams.deadline` bounds a run's wall-clock time, measured from start: one or more `<int>[smhd]` parts (`10m`, `1h30m`), at most `24h`. When it passes, the run settles with `outcome.reason` `deadline_exceeded` and its agent is stopped. A malformed, zero or over-24h value is refused with 400 `invalid_request` and `param: 'deadline'`, and no run is created. `deadline` takes part in the idempotency body, so the same key with another deadline is a 409 `idempotency_conflict`. `model` (already accepted) and `deadline` work on `isolated` runs. `payer`, `model_policy` and `kind` are still refused.
15
+
10
16
  ## 0.3.481
11
17
 
12
18
  ### `npx @north-light/sdk login`, `logout`, `whoami`, `register` and `apps` (additive, no app change)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.481",
3
+ "version": "0.3.482",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "license": "UNLICENSED",
139
139
  "dependencies": {
140
- "@north-light/identity": "0.3.481",
140
+ "@north-light/identity": "0.3.482",
141
141
  "@earendil-works/pi-agent-core": "1.1.0",
142
142
  "@earendil-works/pi-ai": "1.1.0",
143
143
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.481",
3
+ "version": "0.3.482",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.481",
3
+ "version": "0.3.482",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.481",
9
+ "version": "0.3.482",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "1.1.0",
19
19
  "@earendil-works/pi-coding-agent": "1.1.0",
20
20
  "@earendil-works/pi-tui": "1.1.0",
21
- "@north-light/identity": "0.3.481",
21
+ "@north-light/identity": "0.3.482",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12116,17 +12116,17 @@
12116
12116
  },
12117
12117
  "packages/crouter-api": {
12118
12118
  "name": "@north-light/api",
12119
- "version": "0.3.481",
12119
+ "version": "0.3.482",
12120
12120
  "license": "UNLICENSED"
12121
12121
  },
12122
12122
  "packages/crouter-env-docker": {
12123
12123
  "name": "@north-light/env-docker",
12124
- "version": "0.3.481",
12124
+ "version": "0.3.482",
12125
12125
  "license": "UNLICENSED"
12126
12126
  },
12127
12127
  "packages/crouter-identity": {
12128
12128
  "name": "@north-light/identity",
12129
- "version": "0.3.481",
12129
+ "version": "0.3.482",
12130
12130
  "license": "UNLICENSED",
12131
12131
  "dependencies": {
12132
12132
  "jose": "^6.2.1"
@@ -12134,20 +12134,20 @@
12134
12134
  },
12135
12135
  "packages/crouter-plugin": {
12136
12136
  "name": "@north-light/plugin",
12137
- "version": "0.3.481",
12137
+ "version": "0.3.482",
12138
12138
  "license": "UNLICENSED",
12139
12139
  "dependencies": {
12140
- "@north-light/api": "0.3.481",
12141
- "@north-light/identity": "0.3.481"
12140
+ "@north-light/api": "0.3.482",
12141
+ "@north-light/identity": "0.3.482"
12142
12142
  }
12143
12143
  },
12144
12144
  "packages/crouter-sdk": {
12145
12145
  "name": "@north-light/sdk",
12146
- "version": "0.3.481",
12146
+ "version": "0.3.482",
12147
12147
  "license": "UNLICENSED",
12148
12148
  "dependencies": {
12149
- "@north-light/api": "0.3.481",
12150
- "@north-light/identity": "0.3.481",
12149
+ "@north-light/api": "0.3.482",
12150
+ "@north-light/identity": "0.3.482",
12151
12151
  "jose": "^6.2.1"
12152
12152
  },
12153
12153
  "bin": {