@north-light/cli 0.3.505 → 0.3.506

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,3 +1,3 @@
1
- var ye=Object.defineProperty;var u=(e,t)=>ye(e,"name",{value:t,configurable:!0});import{randomUUID as ge}from"node:crypto";import{streamSimple as be}from"@earendil-works/pi-ai/compat";import{expandModelCandidates as re,parseModelSpec as se,probeRouteAvailability as ve}from"../model-routes.js";import{readMergedLaunchConfig as ie}from"../config.js";import{openModelRegistry as we}from"../runtime/model-registry.js";import{coolingUntilFor as ae,isManagedProvider as H,markSubscriptionRateLimited as xe,markSubscriptionSuccess as ke,readSubscriptionPool as je,retryAfterMsFromHeaders as K,retryAfterMsFromError as qe,refreshSubscriptionCredential as Ae,subscriptionNeedsSuccessWrite as Me}from"../subscription-state.js";import{classifyRateLimit as $e,describeRateLimitScope as de,rateLimitHeaders as Re}from"../rate-limit-scope.js";import{RunError as s}from"../runs/operations.js";import{recognizeProviderError as le}from"../provider-error-recognition.js";import{isSafetyRefusal as Ie}from"./refusal.js";import{assertUnderCap as Se,recordModelUsage as ce}from"../usage/ledger.js";import{outboundToken as Ce}from"../providers/mint.js";import{discardFile as Le}from"../providers/token-cache.js";import{ProviderError as Oe}from"../providers/errors.js";import{appCandidates as Fe}from"./app-rungs.js";function Ne(e){return typeof e=="string"||e===null||Array.isArray(e)&&e.every(t=>t&&typeof t=="object"&&(t.type==="text"&&typeof t.text=="string"||t.type==="image_url"&&typeof t.image_url?.url=="string"&&/^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(t.image_url.url)))}u(Ne,"validContent");function ue(e){return Array.isArray(e)?e.map(t=>{if(t.type==="text")return t;const[,n,r]=/^data:(image\/(?:png|jpeg|gif|webp));base64,(.*)$/.exec(t.image_url.url);return{type:"image",mimeType:n,data:r}}):e??""}u(ue,"imageContent");function rt(e){if(!e||typeof e!="object"||Array.isArray(e))throw new s(400,"invalid_request","body must be an object");const t=e;if(!Array.isArray(t.messages)||!t.messages.every(n=>n&&typeof n=="object"&&["system","user","assistant","tool"].includes(n.role)&&Ne(n.content)))throw new s(400,"invalid_request","messages must be chat messages","messages");if(t.messages.some(n=>["system","assistant"].includes(n.role)&&typeof n.content!="string"&&n.content!==null))throw new s(400,"invalid_request","system and assistant content must be text","messages");if(t.model!==void 0&&typeof t.model!="string")throw new s(400,"invalid_request","model must be a string","model");if(t.model_policy!==void 0&&!["exact","substitute"].includes(t.model_policy))throw new s(400,"invalid_request","invalid model_policy","model_policy");if(t.payer!==void 0&&!["user","app"].includes(t.payer))throw new s(400,"invalid_request","invalid payer","payer");if(t.reasoning_effort!==void 0&&!["minimal","low","medium","high","xhigh","max"].includes(t.reasoning_effort))throw new s(400,"invalid_request","invalid reasoning_effort","reasoning_effort");if(t.stream!==void 0&&typeof t.stream!="boolean")throw new s(400,"invalid_request","stream must be boolean","stream");if(t.tools!==void 0&&(!Array.isArray(t.tools)||!t.tools.every(n=>n?.type==="function"&&typeof n.function?.name=="string"&&n.function.name.length>0&&(n.function.description===void 0||typeof n.function.description=="string")&&(n.function.parameters===void 0||n.function.parameters!==null&&typeof n.function.parameters=="object"&&!Array.isArray(n.function.parameters)&&n.function.parameters.type==="object"))))throw new s(400,"invalid_request","invalid tools","tools");if(t.tool_choice!==void 0&&t.tool_choice!=="auto"&&t.tool_choice!=="none"&&t.tool_choice!=="required"&&(typeof t.tool_choice!="object"||t.tool_choice===null||t.tool_choice.type!=="function"||typeof t.tool_choice.function?.name!="string"))throw new s(400,"invalid_request","invalid tool_choice","tool_choice");if(t.messages.some(n=>n.role==="assistant"&&n.tool_calls!==void 0&&(!Array.isArray(n.tool_calls)||!n.tool_calls.every(r=>r&&typeof r.id=="string"&&typeof r.function?.name=="string"&&typeof r.function.arguments=="string"&&De(r.function.arguments)))))throw new s(400,"invalid_request","invalid assistant tool_calls","messages");if(t.stop!==void 0&&!(typeof t.stop=="string"||Array.isArray(t.stop)&&t.stop.every(n=>typeof n=="string")))throw new s(400,"invalid_request","invalid stop","stop");if(t.seed!==void 0&&!Number.isSafeInteger(t.seed))throw new s(400,"invalid_request","invalid seed","seed");for(const[n,r]of[["temperature",t.temperature],["top_p",t.top_p],["max_tokens",t.max_tokens]])if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)||n==="temperature"&&(r<0||r>2)||n==="top_p"&&(r<0||r>1)||n==="max_tokens"&&(!Number.isSafeInteger(r)||r<1)))throw new s(400,"invalid_request",`invalid ${n}`,n);if(t.response_format!==void 0){const n=t.response_format;if(!n||typeof n!="object"||Array.isArray(n)||!["text","json_object","json_schema"].includes(n.type)||n.type==="json_schema"&&(typeof n.json_schema?.name!="string"||!n.json_schema.name||!n.json_schema.schema||typeof n.json_schema.schema!="object"||Array.isArray(n.json_schema.schema)))throw new s(400,"invalid_request","invalid response_format","response_format")}if(t.metadata!==void 0&&Buffer.byteLength(JSON.stringify(t.metadata)??"")>4096)throw new s(400,"invalid_request","metadata exceeds 4 KB","metadata");return t}u(rt,"parseLlmRequest");function De(e){try{const t=JSON.parse(e);return t!==null&&typeof t=="object"&&!Array.isArray(t)}catch{return!1}}u(De,"isJsonObject");function Pe(e){const t=Date.now(),n=e.messages.map(i=>i.role==="system"?{role:"system",content:i.content??"",timestamp:t}:i.role==="tool"?{role:"toolResult",toolCallId:i.tool_call_id??"",toolName:"",content:typeof i.content=="string"||i.content===null?[{type:"text",text:i.content??""}]:ue(i.content),isError:!1,timestamp:t}:i.role==="assistant"?{role:"assistant",content:[...i.content?[{type:"text",text:i.content}]:[],...(i.tool_calls??[]).map(g=>({type:"toolCall",id:g.id,name:g.function.name,arguments:JSON.parse(g.function.arguments)}))],api:"openai-completions",provider:"openai",model:e.model??"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:t}:{role:"user",content:ue(i.content),timestamp:t}),r=n.findIndex(i=>i.role!=="system"),w=n.slice(0,r<0?n.length:r).map(i=>i.content),y=w.join(`
1
+ var ge=Object.defineProperty;var u=(e,t)=>ge(e,"name",{value:t,configurable:!0});import{randomUUID as be}from"node:crypto";import{streamSimple as ve}from"@earendil-works/pi-ai/compat";import{expandModelCandidates as re,parseModelSpec as se,probeRouteAvailability as we}from"../model-routes.js";import{readMergedLaunchConfig as ie}from"../config.js";import{openModelRegistry as xe}from"../runtime/model-registry.js";import{MAX_RATE_LIMIT_COOLDOWN_MS as ae,coolingUntilFor as de,isManagedProvider as H,markSubscriptionRateLimited as ke,markSubscriptionSuccess as je,readSubscriptionPool as Me,retryAfterMsFromHeaders as K,retryAfterMsFromError as qe,refreshSubscriptionCredential as Ae,subscriptionNeedsSuccessWrite as $e}from"../subscription-state.js";import{classifyRateLimit as Ie,describeRateLimitScope as le,rateLimitHeaders as Re}from"../rate-limit-scope.js";import{RunError as s}from"../runs/operations.js";import{recognizeProviderError as ce}from"../provider-error-recognition.js";import{isSafetyRefusal as Se}from"./refusal.js";import{assertUnderCap as Ce,recordModelUsage as ue}from"../usage/ledger.js";import{outboundToken as Le}from"../providers/mint.js";import{discardFile as Oe}from"../providers/token-cache.js";import{ProviderError as Fe}from"../providers/errors.js";import{appCandidates as Ne}from"./app-rungs.js";function De(e){return typeof e=="string"||e===null||Array.isArray(e)&&e.every(t=>t&&typeof t=="object"&&(t.type==="text"&&typeof t.text=="string"||t.type==="image_url"&&typeof t.image_url?.url=="string"&&/^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(t.image_url.url)))}u(De,"validContent");function fe(e){return Array.isArray(e)?e.map(t=>{if(t.type==="text")return t;const[,n,r]=/^data:(image\/(?:png|jpeg|gif|webp));base64,(.*)$/.exec(t.image_url.url);return{type:"image",mimeType:n,data:r}}):e??""}u(fe,"imageContent");function st(e){if(!e||typeof e!="object"||Array.isArray(e))throw new s(400,"invalid_request","body must be an object");const t=e;if(!Array.isArray(t.messages)||!t.messages.every(n=>n&&typeof n=="object"&&["system","user","assistant","tool"].includes(n.role)&&De(n.content)))throw new s(400,"invalid_request","messages must be chat messages","messages");if(t.messages.some(n=>["system","assistant"].includes(n.role)&&typeof n.content!="string"&&n.content!==null))throw new s(400,"invalid_request","system and assistant content must be text","messages");if(t.model!==void 0&&typeof t.model!="string")throw new s(400,"invalid_request","model must be a string","model");if(t.model_policy!==void 0&&!["exact","substitute"].includes(t.model_policy))throw new s(400,"invalid_request","invalid model_policy","model_policy");if(t.payer!==void 0&&!["user","app"].includes(t.payer))throw new s(400,"invalid_request","invalid payer","payer");if(t.reasoning_effort!==void 0&&!["minimal","low","medium","high","xhigh","max"].includes(t.reasoning_effort))throw new s(400,"invalid_request","invalid reasoning_effort","reasoning_effort");if(t.stream!==void 0&&typeof t.stream!="boolean")throw new s(400,"invalid_request","stream must be boolean","stream");if(t.tools!==void 0&&(!Array.isArray(t.tools)||!t.tools.every(n=>n?.type==="function"&&typeof n.function?.name=="string"&&n.function.name.length>0&&(n.function.description===void 0||typeof n.function.description=="string")&&(n.function.parameters===void 0||n.function.parameters!==null&&typeof n.function.parameters=="object"&&!Array.isArray(n.function.parameters)&&n.function.parameters.type==="object"))))throw new s(400,"invalid_request","invalid tools","tools");if(t.tool_choice!==void 0&&t.tool_choice!=="auto"&&t.tool_choice!=="none"&&t.tool_choice!=="required"&&(typeof t.tool_choice!="object"||t.tool_choice===null||t.tool_choice.type!=="function"||typeof t.tool_choice.function?.name!="string"))throw new s(400,"invalid_request","invalid tool_choice","tool_choice");if(t.messages.some(n=>n.role==="assistant"&&n.tool_calls!==void 0&&(!Array.isArray(n.tool_calls)||!n.tool_calls.every(r=>r&&typeof r.id=="string"&&typeof r.function?.name=="string"&&typeof r.function.arguments=="string"&&Ee(r.function.arguments)))))throw new s(400,"invalid_request","invalid assistant tool_calls","messages");if(t.stop!==void 0&&!(typeof t.stop=="string"||Array.isArray(t.stop)&&t.stop.every(n=>typeof n=="string")))throw new s(400,"invalid_request","invalid stop","stop");if(t.seed!==void 0&&!Number.isSafeInteger(t.seed))throw new s(400,"invalid_request","invalid seed","seed");for(const[n,r]of[["temperature",t.temperature],["top_p",t.top_p],["max_tokens",t.max_tokens]])if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)||n==="temperature"&&(r<0||r>2)||n==="top_p"&&(r<0||r>1)||n==="max_tokens"&&(!Number.isSafeInteger(r)||r<1)))throw new s(400,"invalid_request",`invalid ${n}`,n);if(t.response_format!==void 0){const n=t.response_format;if(!n||typeof n!="object"||Array.isArray(n)||!["text","json_object","json_schema"].includes(n.type)||n.type==="json_schema"&&(typeof n.json_schema?.name!="string"||!n.json_schema.name||!n.json_schema.schema||typeof n.json_schema.schema!="object"||Array.isArray(n.json_schema.schema)))throw new s(400,"invalid_request","invalid response_format","response_format")}if(t.metadata!==void 0&&Buffer.byteLength(JSON.stringify(t.metadata)??"")>4096)throw new s(400,"invalid_request","metadata exceeds 4 KB","metadata");return t}u(st,"parseLlmRequest");function Ee(e){try{const t=JSON.parse(e);return t!==null&&typeof t=="object"&&!Array.isArray(t)}catch{return!1}}u(Ee,"isJsonObject");function Pe(e){const t=Date.now(),n=e.messages.map(i=>i.role==="system"?{role:"system",content:i.content??"",timestamp:t}:i.role==="tool"?{role:"toolResult",toolCallId:i.tool_call_id??"",toolName:"",content:typeof i.content=="string"||i.content===null?[{type:"text",text:i.content??""}]:fe(i.content),isError:!1,timestamp:t}:i.role==="assistant"?{role:"assistant",content:[...i.content?[{type:"text",text:i.content}]:[],...(i.tool_calls??[]).map(g=>({type:"toolCall",id:g.id,name:g.function.name,arguments:JSON.parse(g.function.arguments)}))],api:"openai-completions",provider:"openai",model:e.model??"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:t}:{role:"user",content:fe(i.content),timestamp:t}),r=n.findIndex(i=>i.role!=="system"),w=n.slice(0,r<0?n.length:r).map(i=>i.content),y=w.join(`
2
2
 
3
- `),l=e.tools?.map(({function:i})=>({name:i.name,description:i.description??"",parameters:i.parameters??{type:"object",properties:{}}}));return{...y?{systemPrompt:y}:{},messages:n.slice(w.length),...l?{tools:l}:{}}}u(Pe,"contextOf");function fe(e,t,n,r){if(!e){const y=ie(n,r),l=Object.values({...y.modelRoutes??{},...y.legacyModelRoutes??{}}),i=l.length?[y.modelLadders.defaultProvider,...y.modelRouting?.familyOrder??[],...l.map(g=>g.family)].find(g=>l.some(F=>F.family===g)):y.modelLadders.defaultProvider??"anthropic";return{kind:"logical",family:i,strength:"strong",spec:`${i}/strong`}}const w=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);return w?{kind:"logical",family:w[1],strength:w[2],spec:e}:{kind:t==="exact"?"exact":"concrete",spec:e}}u(fe,"requestFor");function Ee(e,t){const{input:n,output:r,cacheRead:w,cacheWrite:y}=e.cost;return n===0&&r===0&&w===0&&y===0?null:Number.isFinite(t)&&t>=0?t:null}u(Ee,"usdEquivalent");function Te(e,t){return e.compat?.allowedFallbackModels?.find(r=>r.provider===e.provider&&r.model===t)}u(Te,"allowedFallback");function st(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}u(st,"llmCallerOf");function Ue(e){return e instanceof Oe?e.code==="server_error"?new s(503,"upstream_model_unavailable",e.message):new s(404,"model_unavailable",e.message):e}u(Ue,"mintFailure");async function it(e,t,n,r,w,y){const l=y?.payer==="app"?y:void 0;if(e.payer==="app"&&!l)throw new s(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&l)throw new s(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(l&&!l.inference_endpoint)throw new s(404,"model_unavailable",`${l.grantee} is app-paid but its grant carries no inference endpoint`);const i=l?.inference_endpoint??void 0;l||Se(w);const g=await we(),F=u(c=>c.routeId!=="concrete"&&c.routeId!=="exact","configured"),Y=u(c=>{const p=g.find(c.providerId,c.modelId);return p!==void 0&&(!e.reasoning_effort||p.reasoning)&&(e.seed===void 0&&e.response_format===void 0||p.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(p.api))},"matchesFeatures"),me=u(()=>{const c=fe(e.model,e.model_policy,r?.cwd,r?.profileId),p=re(c.kind==="exact"?{kind:"concrete",spec:c.spec}:c,r?.cwd,r?.profileId).filter(F);let a;if(c.kind==="logical")a=e.model_policy==="exact"?p.filter(m=>m.family===c.family&&m.strength===c.strength).slice(0,1):p;else{const m=se(c.spec),M=p.filter(j=>j.providerId===m?.providerId&&j.modelId===m.modelId&&(e.model_policy!=="exact"||j.thinkingLevel===m.thinkingLevel)&&Y(j));if(e.model_policy==="exact")a=M.slice(0,1);else if(M.length)a=M;else{const j=ie(r?.cwd,r?.profileId),x=[...Object.values(j.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[j.modelLadders.anthropic,j.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===c.spec)?.[0],f=fe(void 0,"substitute",r?.cwd,r?.profileId);a=x&&f.kind==="logical"?re({...f,strength:x,spec:c.spec},r?.cwd,r?.profileId).filter(v=>F(v)&&v.strength===x):[]}}return a},"ownerCandidates");let R;if(i?R=Fe(i,e.model,e.model_policy==="exact").flatMap((c,p)=>{const a=se(c.model);return a?[{routeId:"app",credentialSource:"app",family:"app",strength:c.strength,...a,rank:p}]:[]}):R=me(),R=R.filter(Y),R.length===0)throw e.model_policy==="exact"?new s(400,"substitution_refused","no eligible model route is configured"):new s(404,"model_unavailable","no eligible model route is configured");const ee=`chatcmpl-${ge()}`;let I=1/0,b,z;for(const c of R){if(!l&&!ve(c,g).authenticated)continue;const p=g.find(c.providerId,c.modelId);if(!p)continue;const a=i?{...p,baseUrl:`${i.base_url}/${p.provider}`}:p,m=c.providerId,M=!l&&H(m)?je(m).filter(x=>!x.authFailure):[],j=M.filter(x=>ae(x,a.id)<=Date.now());if(M.length&&!j.length){const x=Math.min(...M.map(f=>ae(f,a.id)));x<I&&(I=x,z=`${a.provider}/${a.id}`);continue}const te=l?[void 0,void 0]:M.length?j:[void 0];for(const[x,f]of te.entries()){const v=Date.now();let oe=f?.access;if(f&&f.expires<=Date.now()&&H(m)){const o=g.getProvider(m)?.auth.oauth;if(!o)throw new s(503,"upstream_model_unavailable",`no OAuth refresh for ${m}`,void 0,{served_model:`${a.provider}/${a.id}`});oe=(await Ae(m,f.label,async(k,ne)=>{const W=await o.refresh({type:"oauth",refresh:k,access:"",expires:0,...ne?{clientId:ne}:{}},t??new AbortController().signal),X=W.clientId;return{refresh:W.refresh,access:W.access,expires:W.expires,...typeof X=="string"&&X?{clientId:X}:{}}})).access}const pe=Pe(e);let N;if(l&&i)try{N=await Ce({audience:i.base_url,sub:l.sub,grantee:l.grantee,initiating_app:l.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw Ue(o)}const S=f||l?void 0:await g.getApiKeyAndHeaders(a);if(S&&!S.ok)continue;const h=`${a.provider}/${a.id}`,C=e.model??h;let A=!1,O,q=3e4,$;const B=[],Z=[],D=[];let d,P;const E=u((o,_=null)=>({id:ee,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:h,served_model:h,requested_model:C,substituted:C!==h&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,delta:o,finish_reason:_}]}),"chunk"),T=u(o=>{B.push(o),n?.(o)},"emit"),he=be(a,pe,{apiKey:N?.access_token??oe??(S?.ok?S.apiKey:void 0),...S?.ok?{headers:S.headers}:{},signal:t,reasoning:e.reasoning_effort??c.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:u(o=>{if(!o||typeof o!="object")return;const _=e.tool_choice,k=_==="required"?a.api==="anthropic-messages"?{type:"any"}:"required":typeof _=="object"&&_!==null?a.api==="anthropic-messages"?{type:"tool",name:_.function.name}:_:void 0;return{...o,...k?{tool_choice:k}:{},...e.stop!==void 0?{[a.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:u(async(o,_)=>{const k=await fetch(o,_);return O=k.status,k.status===429&&(A=!0,$=k.headers,q=K(k.headers)??15e3),k},"fetch"),onResponse:u(o=>{o.status===429&&(A=!0,$=o.headers,q=K(o.headers)??15e3)},"onResponse")});try{for await(const o of he)o.type==="text_delta"&&(Z.push(o.delta),T(E({content:o.delta}))),o.type==="thinking_delta"&&(D.push(o.delta),T(E({reasoning_content:o.delta}))),o.type==="done"&&(d=o.message),o.type==="error"&&(d=o.error)}catch(o){const _=qe(o);$===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Re(o.headers)).length&&($=o.headers);const k=le({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(l)P=o;else{if(!A&&k.kind!=="rate-limit")throw B.length?new s(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:h}):o;A=!0,q=_??q}}if(l){if(O===401){if(N&&Le(N.key),x===0)continue;throw new s(404,"model_unavailable",`${i.base_url} refuses this runtime's tokens`,void 0,{served_model:h})}if(A&&K($)===void 0)throw new s(503,"upstream_model_unavailable",`${h} was rate-limited without a retry-after`,void 0,{served_model:h});if(!A&&(P!==void 0||O!==void 0&&O>=500))throw new s(503,"upstream_model_unavailable",P instanceof Error?P.message:d?.errorMessage??"inference endpoint failed",void 0,{served_model:h})}if(!A&&d?.stopReason==="error"&&le({message:d.errorMessage}).kind==="rate-limit"&&(A=!0,q=15e3),A){const o=$e($,a.id);if(K($)===void 0&&o.resetAt!==void 0&&(q=Math.max(q,o.resetAt-Date.now())),b={provider:m,model:a.id,...f?{account:f.label}:{},observation:o},console.error(`[llm] 429 from ${h}${f?` account "${f.label}"`:""}: scope=${de(o.scope)} retry_after_ms=${q} headers=${JSON.stringify(o.headers)}`),f&&H(m)&&await xe(m,f.label,q,v,Date.now(),o.scope),Date.now()+q<I&&(I=Date.now()+q,z=h),Z.length||D.length)throw new s(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:h});if(l)break;continue}const U=Ie(d);if(O===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(d?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(d?.errorMessage??""))throw new s(400,"invalid_request",d.errorMessage,"tool_choice",{served_model:h});if(!d||d.stopReason==="error"&&!U||d.stopReason==="aborted")throw new s(503,"upstream_model_unavailable",d?.errorMessage??"model request failed",void 0,{served_model:h});f&&H(m)&&Me(f,a.id)&&await ke(m,f.label,v,a.id);const G=d.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),Q=U?"content_filter":d.stopReason==="toolUse"?"tool_calls":d.stopReason==="length"?"length":"stop",V=d.responseModel?Te(a,d.responseModel):void 0,L=V?`${a.provider}/${V.model}`:h,J={prompt_tokens:d.usage.input,completion_tokens:d.usage.output,total_tokens:d.usage.totalTokens,cache_read_tokens:d.usage.cacheRead,cache_write_tokens:d.usage.cacheWrite,usd_equivalent:Ee(V??a,d.usage.cost.total),served_model:L};l?ce(l.grantee,"app",L,d.usage,J.usd_equivalent):w&&ce(w.grantee,"user",L,d.usage,J.usd_equivalent);const _e={id:ee,object:"chat.completion",created:Math.floor(v/1e3),model:L,served_model:L,requested_model:C,substituted:C!==L&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,message:{role:"assistant",content:Z.join("")||null,...D.length?{reasoning_content:D.join("")}:{},...G.length?{tool_calls:G}:{},...U?{refusal:d.errorMessage??"Content filtered"}:{}},finish_reason:Q}],usage:J,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,_]of G.entries())T(E({tool_calls:[{index:o,..._}]}));return T({...E({},Q),...U?{choices:[{index:0,delta:{},finish_reason:Q,message:{refusal:d.errorMessage??"Content filtered"}}]}:{},usage:J}),{completion:_e,chunks:B}}}throw I!==1/0?new s(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((I-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:z,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:de(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new s(400,"substitution_refused","the requested model is unavailable"):new s(404,"model_unavailable","no usable model route is available")}u(it,"runLlm");export{st as llmCallerOf,rt as parseLlmRequest,it as runLlm};
3
+ `),l=e.tools?.map(({function:i})=>({name:i.name,description:i.description??"",parameters:i.parameters??{type:"object",properties:{}}}));return{...y?{systemPrompt:y}:{},messages:n.slice(w.length),...l?{tools:l}:{}}}u(Pe,"contextOf");function me(e,t,n,r){if(!e){const y=ie(n,r),l=Object.values({...y.modelRoutes??{},...y.legacyModelRoutes??{}}),i=l.length?[y.modelLadders.defaultProvider,...y.modelRouting?.familyOrder??[],...l.map(g=>g.family)].find(g=>l.some(F=>F.family===g)):y.modelLadders.defaultProvider??"anthropic";return{kind:"logical",family:i,strength:"strong",spec:`${i}/strong`}}const w=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);return w?{kind:"logical",family:w[1],strength:w[2],spec:e}:{kind:t==="exact"?"exact":"concrete",spec:e}}u(me,"requestFor");function Te(e,t){const{input:n,output:r,cacheRead:w,cacheWrite:y}=e.cost;return n===0&&r===0&&w===0&&y===0?null:Number.isFinite(t)&&t>=0?t:null}u(Te,"usdEquivalent");function Ue(e,t){return e.compat?.allowedFallbackModels?.find(r=>r.provider===e.provider&&r.model===t)}u(Ue,"allowedFallback");function it(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}u(it,"llmCallerOf");function Je(e){return e instanceof Fe?e.code==="server_error"?new s(503,"upstream_model_unavailable",e.message):new s(404,"model_unavailable",e.message):e}u(Je,"mintFailure");async function at(e,t,n,r,w,y){const l=y?.payer==="app"?y:void 0;if(e.payer==="app"&&!l)throw new s(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&l)throw new s(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(l&&!l.inference_endpoint)throw new s(404,"model_unavailable",`${l.grantee} is app-paid but its grant carries no inference endpoint`);const i=l?.inference_endpoint??void 0;l||Ce(w);const g=await xe(),F=u(c=>c.routeId!=="concrete"&&c.routeId!=="exact","configured"),Y=u(c=>{const p=g.find(c.providerId,c.modelId);return p!==void 0&&(!e.reasoning_effort||p.reasoning)&&(e.seed===void 0&&e.response_format===void 0||p.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(p.api))},"matchesFeatures"),pe=u(()=>{const c=me(e.model,e.model_policy,r?.cwd,r?.profileId),p=re(c.kind==="exact"?{kind:"concrete",spec:c.spec}:c,r?.cwd,r?.profileId).filter(F);let a;if(c.kind==="logical")a=e.model_policy==="exact"?p.filter(m=>m.family===c.family&&m.strength===c.strength).slice(0,1):p;else{const m=se(c.spec),A=p.filter(j=>j.providerId===m?.providerId&&j.modelId===m.modelId&&(e.model_policy!=="exact"||j.thinkingLevel===m.thinkingLevel)&&Y(j));if(e.model_policy==="exact")a=A.slice(0,1);else if(A.length)a=A;else{const j=ie(r?.cwd,r?.profileId),x=[...Object.values(j.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[j.modelLadders.anthropic,j.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===c.spec)?.[0],f=me(void 0,"substitute",r?.cwd,r?.profileId);a=x&&f.kind==="logical"?re({...f,strength:x,spec:c.spec},r?.cwd,r?.profileId).filter(v=>F(v)&&v.strength===x):[]}}return a},"ownerCandidates");let I;if(i?I=Ne(i,e.model,e.model_policy==="exact").flatMap((c,p)=>{const a=se(c.model);return a?[{routeId:"app",credentialSource:"app",family:"app",strength:c.strength,...a,rank:p}]:[]}):I=pe(),I=I.filter(Y),I.length===0)throw e.model_policy==="exact"?new s(400,"substitution_refused","no eligible model route is configured"):new s(404,"model_unavailable","no eligible model route is configured");const ee=`chatcmpl-${be()}`;let R=1/0,b,z;for(const c of I){if(!l&&!we(c,g).authenticated)continue;const p=g.find(c.providerId,c.modelId);if(!p)continue;const a=i?{...p,baseUrl:`${i.base_url}/${p.provider}`}:p,m=c.providerId,A=!l&&H(m)?Me(m).filter(x=>!x.authFailure):[],j=A.filter(x=>de(x,a.id)<=Date.now());if(A.length&&!j.length){const x=Math.min(...A.map(f=>de(f,a.id)));x<R&&(R=x,z=`${a.provider}/${a.id}`);continue}const te=l?[void 0,void 0]:A.length?j:[void 0];for(const[x,f]of te.entries()){const v=Date.now();let oe=f?.access;if(f&&f.expires<=Date.now()&&H(m)){const o=g.getProvider(m)?.auth.oauth;if(!o)throw new s(503,"upstream_model_unavailable",`no OAuth refresh for ${m}`,void 0,{served_model:`${a.provider}/${a.id}`});oe=(await Ae(m,f.label,async(k,ne)=>{const W=await o.refresh({type:"oauth",refresh:k,access:"",expires:0,...ne?{clientId:ne}:{}},t??new AbortController().signal),V=W.clientId;return{refresh:W.refresh,access:W.access,expires:W.expires,...typeof V=="string"&&V?{clientId:V}:{}}})).access}const he=Pe(e);let N;if(l&&i)try{N=await Le({audience:i.base_url,sub:l.sub,grantee:l.grantee,initiating_app:l.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw Je(o)}const S=f||l?void 0:await g.getApiKeyAndHeaders(a);if(S&&!S.ok)continue;const h=`${a.provider}/${a.id}`,C=e.model??h;let q=!1,O,M=3e4,$;const B=[],X=[],D=[];let d,E;const P=u((o,_=null)=>({id:ee,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:h,served_model:h,requested_model:C,substituted:C!==h&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,delta:o,finish_reason:_}]}),"chunk"),T=u(o=>{B.push(o),n?.(o)},"emit"),_e=ve(a,he,{apiKey:N?.access_token??oe??(S?.ok?S.apiKey:void 0),...S?.ok?{headers:S.headers}:{},signal:t,reasoning:e.reasoning_effort??c.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:u(o=>{if(!o||typeof o!="object")return;const _=e.tool_choice,k=_==="required"?a.api==="anthropic-messages"?{type:"any"}:"required":typeof _=="object"&&_!==null?a.api==="anthropic-messages"?{type:"tool",name:_.function.name}:_:void 0;return{...o,...k?{tool_choice:k}:{},...e.stop!==void 0?{[a.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:u(async(o,_)=>{const k=await fetch(o,_);return O=k.status,k.status===429&&(q=!0,$=k.headers,M=K(k.headers)??15e3),k},"fetch"),onResponse:u(o=>{o.status===429&&(q=!0,$=o.headers,M=K(o.headers)??15e3)},"onResponse")});try{for await(const o of _e)o.type==="text_delta"&&(X.push(o.delta),T(P({content:o.delta}))),o.type==="thinking_delta"&&(D.push(o.delta),T(P({reasoning_content:o.delta}))),o.type==="done"&&(d=o.message),o.type==="error"&&(d=o.error)}catch(o){const _=qe(o);$===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Re(o.headers)).length&&($=o.headers);const k=ce({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(l)E=o;else{if(!q&&k.kind!=="rate-limit")throw B.length?new s(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:h}):o;q=!0,M=_??M}}if(l){if(O===401){if(N&&Oe(N.key),x===0)continue;throw new s(404,"model_unavailable",`${i.base_url} refuses this runtime's tokens`,void 0,{served_model:h})}if(q&&K($)===void 0)throw new s(503,"upstream_model_unavailable",`${h} was rate-limited without a retry-after`,void 0,{served_model:h});if(!q&&(E!==void 0||O!==void 0&&O>=500))throw new s(503,"upstream_model_unavailable",E instanceof Error?E.message:d?.errorMessage??"inference endpoint failed",void 0,{served_model:h})}if(!q&&d?.stopReason==="error"&&ce({message:d.errorMessage}).kind==="rate-limit"&&(q=!0,M=15e3),q){const o=Ie($,a.id);if(K($)===void 0&&o.resetAt!==void 0&&(M=Math.max(M,o.resetAt-Date.now())),b={provider:m,model:a.id,...f?{account:f.label}:{},observation:o},console.error(`[llm] 429 from ${h}${f?` account "${f.label}"`:""}: scope=${le(o.scope)} retry_after_ms=${M} headers=${JSON.stringify(o.headers)}`),f&&H(m)&&await ke(m,f.label,M,v,Date.now(),o.scope),Date.now()+Math.min(M,ae)<R&&(R=Date.now()+Math.min(M,ae),z=h),X.length||D.length)throw new s(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:h});if(l)break;continue}const U=Se(d);if(O===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(d?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(d?.errorMessage??""))throw new s(400,"invalid_request",d.errorMessage,"tool_choice",{served_model:h});if(!d||d.stopReason==="error"&&!U||d.stopReason==="aborted")throw new s(503,"upstream_model_unavailable",d?.errorMessage??"model request failed",void 0,{served_model:h});f&&H(m)&&$e(f,a.id)&&await je(m,f.label,v,a.id);const Z=d.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),G=U?"content_filter":d.stopReason==="toolUse"?"tool_calls":d.stopReason==="length"?"length":"stop",Q=d.responseModel?Ue(a,d.responseModel):void 0,L=Q?`${a.provider}/${Q.model}`:h,J={prompt_tokens:d.usage.input,completion_tokens:d.usage.output,total_tokens:d.usage.totalTokens,cache_read_tokens:d.usage.cacheRead,cache_write_tokens:d.usage.cacheWrite,usd_equivalent:Te(Q??a,d.usage.cost.total),served_model:L};l?ue(l.grantee,"app",L,d.usage,J.usd_equivalent):w&&ue(w.grantee,"user",L,d.usage,J.usd_equivalent);const ye={id:ee,object:"chat.completion",created:Math.floor(v/1e3),model:L,served_model:L,requested_model:C,substituted:C!==L&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,message:{role:"assistant",content:X.join("")||null,...D.length?{reasoning_content:D.join("")}:{},...Z.length?{tool_calls:Z}:{},...U?{refusal:d.errorMessage??"Content filtered"}:{}},finish_reason:G}],usage:J,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,_]of Z.entries())T(P({tool_calls:[{index:o,..._}]}));return T({...P({},G),...U?{choices:[{index:0,delta:{},finish_reason:G,message:{refusal:d.errorMessage??"Content filtered"}}]}:{},usage:J}),{completion:ye,chunks:B}}}throw R!==1/0?new s(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((R-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:z,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:le(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new s(400,"substitution_refused","the requested model is unavailable"):new s(404,"model_unavailable","no usable model route is available")}u(at,"runLlm");export{it as llmCallerOf,st as parseLlmRequest,at as runLlm};
@@ -3,6 +3,8 @@ export declare const ANTHROPIC_PROVIDER_ID = "anthropic";
3
3
  export declare const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
4
4
  /** pi's built-in `openai` provider signed in with a ChatGPT account (dynamic OAuth client). Distinct from Codex: its own pool, credential file and sign-in. */
5
5
  export declare const OPENAI_CHATGPT_PROVIDER_ID = "openai";
6
+ /** Longest a recorded 429 keeps an account or model family cooling, whatever the provider's Retry-After or window reset says: after this the next real call probes the provider, and a success clears the row. */
7
+ export declare const MAX_RATE_LIMIT_COOLDOWN_MS: number;
6
8
  export declare const INVALID_REFRESH_TOKEN_BACKOFF_MS: number;
7
9
  export type ManagedProviderId = typeof ANTHROPIC_PROVIDER_ID | typeof OPENAI_CODEX_PROVIDER_ID | typeof OPENAI_CHATGPT_PROVIDER_ID;
8
10
  export declare const MANAGED_PROVIDER_IDS: readonly ManagedProviderId[];
@@ -1,4 +1,4 @@
1
- var rt=Object.defineProperty;var o=(t,n)=>rt(t,"name",{value:n,configurable:!0});import{prepared as g}from"./sqlite-statements.js";import{createHash as ot,randomUUID as U}from"node:crypto";import{mkdirSync as st,readFileSync as ct,writeFileSync as lt}from"node:fs";import{join as q}from"node:path";import{brokerConfigSnapshot as ut}from"./config.js";import{LockedJsonFile as dt}from"./locked-file.js";import{secretsDir as mt}from"./layout.js";import{openScopedStore as ft}from"./scoped-state/db.js";import{providerStore as ht}from"./scoped-state/paths.js";import{providerModelCooldowns as T,providerModelCooldownsFor as bt,providerRowByReference as P,providerRows as pt,providerWrite as A}from"./scoped-state/providers.js";import{modelCooldownFamily as j}from"./rate-limit-scope.js";const H="anthropic",z="openai-codex",G="openai",At=720*60*60*1e3,qt=[H,z,G],J="strong",Q={anthropic:{label:"Claude",credentials:"anthropic-credentials.json"},"openai-codex":{label:"OpenAI Codex",credentials:"openai-codex-credentials.json"},openai:{label:"ChatGPT",credentials:"openai-credentials.json"}};function I(t){return{refresh:t.refresh,access:t.access,expires:t.expires,...t.accountId?{accountId:t.accountId}:{},...t.clientId?{clientId:t.clientId}:{}}}o(I,"stored");function W(t){return typeof t=="string"&&t.trim()?t.trim():void 0}o(W,"optionalString");function h(){return mt()}o(h,"agentDir");function K(t){return q(h(),Q[t].credentials)}o(K,"credentialFile");function X(t){return t==="ultra"||t==="strong"||t==="medium"||t==="light"?t:void 0}o(X,"normalizeStrength");function f(t){return t.toLowerCase()}o(f,"key");function yt(t){const n=typeof t.label=="string"?t.label.trim():"",e=typeof t.refresh=="string"?t.refresh.trim():"",a=typeof t.access=="string"?t.access.trim():"",i=Number(t.expires);if(!n||!e||!a||!Number.isFinite(i))return;const r=W(t.accountId),s=W(t.clientId);return{label:n,refresh:e,access:a,expires:i,rateLimitedUntil:Number.isFinite(Number(t.rateLimitedUntil))?Number(t.rateLimitedUntil):0,lastAttemptAt:Number.isFinite(Number(t.lastAttemptAt))?Number(t.lastAttemptAt):0,lastRateLimitedAt:Number.isFinite(Number(t.lastRateLimitedAt))?Number(t.lastRateLimitedAt):0,...t.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},...r?{accountId:r}:{},...s?{clientId:s}:{},...Y(t.modelCooldowns)?{modelCooldowns:Y(t.modelCooldowns)}:{}}}o(yt,"credential");function Y(t){if(!t||typeof t!="object"||Array.isArray(t))return;const n=Object.entries(t).filter(([e,a])=>e.trim()!==""&&Number.isFinite(Number(a))).map(([e,a])=>[e,Number(a)]);return n.length?Object.fromEntries(n):void 0}o(Y,"modelCooldowns");function N(t,n){if(!n.label?.trim())throw new Error(`${b(t)} subscription label cannot be empty`);const e=yt(n);if(!e)throw new Error(`Refusing to persist incomplete ${b(t)} subscription "${n.label.trim()}"; pool rows require both OAuth tokens.`);return e}o(N,"assertCredential");function Z(t,n){if(!n||n.trim()==="")return{version:1,accounts:{}};let e;try{e=JSON.parse(n)}catch(a){throw new Error(`managed credential file ${t} is corrupt: ${a instanceof Error?a.message:String(a)}`)}if(typeof e!="object"||e===null||Array.isArray(e)||e.version!==1||typeof e.accounts!="object"||e.accounts===null||Array.isArray(e.accounts))throw new Error(`managed credential file ${t} is corrupt`);return e}o(Z,"parseCredentials");function _t(t,n,e=[]){const a=n.accounts[t.id];if(!a||typeof a.refresh!="string"||typeof a.access!="string"||!Number.isFinite(a.expires))throw new Error(`managed ${t.providerId} account ${t.id} has no credential record`);return{label:t.label,refresh:a.refresh,access:a.access,expires:a.expires,rateLimitedUntil:t.rateLimitedUntil,lastAttemptAt:t.lastAttemptAt,lastRateLimitedAt:t.lastRateLimitedAt,...t.authFailure?{authFailure:t.authFailure}:{},...a.accountId?{accountId:a.accountId}:{},...a.clientId?{clientId:a.clientId}:{},...e.length?{modelCooldowns:Object.fromEntries(e.map(i=>[i.family,i.rateLimitedUntil]))}:{}}}o(_t,"toPublic");function V(t,n){const e=bt(h(),t);return pt(h(),t).map(a=>({row:a,entry:_t(a,n,e.get(a.id))}))}o(V,"rowsWithCredentials");function v(t){return new dt(K(t),!0,`{"version":1,"accounts":{}}
2
- `)}o(v,"managedCredentialFile");function gt(t){return Z(K(t),v(t).readUnlocked())}o(gt,"readFile");function tt(t,n){const e=t.accountId?.trim(),a=n.accountId?.trim();return!!(e&&a&&e!==a)}o(tt,"differentAccount");function _(t){return t.accountId?.trim()||(t.refresh.trim()?`refresh:${ot("sha256").update(t.refresh.trim()).digest("hex")}`:void 0)}o(_,"identity");function et(t,n){const e=W(n);return e?{...t,clientId:e}:t}o(et,"withClientId");function nt(t,n,e){const a=e.refresh?.trim()??"",i=e.access?.trim()??"",r=Number(e.expires);if(!a||!i||!Number.isFinite(r))throw new Error(`${b(t)} subscription "${n}" returned an incomplete credential; the stored credential was left unchanged.`);return{refresh:a,access:i,expires:r}}o(nt,"assertTokens");function Et(t,n){const e=j(n);return Math.max(t.rateLimitedUntil||0,e===void 0?0:t.modelCooldowns?.[e]??0)}o(Et,"coolingUntilFor");function wt(t,n=Date.now()){return[...(t.rateLimitedUntil||0)>n?[{scope:"account",until:t.rateLimitedUntil}]:[],...Object.entries(t.modelCooldowns??{}).filter(([,e])=>e>n).map(([e,a])=>({scope:e,until:a}))]}o(wt,"activeCooldowns");function zt(t,n=Date.now()){const e=wt(t,n).map(({scope:a,until:i})=>`${a==="account"?"":`${a} `}cooldown ${xt(i-n)}`);return e.length?e.join(", "):void 0}o(zt,"formatCooldowns");function xt(t){const n=Math.max(1,Math.ceil(t/6e4));if(n<60)return`${n}m`;const e=Math.floor(n/60);return e<24?`${e}h${n%60?` ${n%60}m`:""}`:`${Math.floor(e/24)}d${e%24?` ${e%24}h`:""}`}o(xt,"formatWait");function Lt(t,n){const e=j(n);return e!==void 0&&t.modelCooldowns?.[e]!==void 0}o(Lt,"hasModelCooldownRow");function Gt(t,n){return!!(t.rateLimitedUntil||t.authFailure)||Lt(t,n)}o(Gt,"subscriptionNeedsSuccessWrite");function Jt(t){return t===H||t===z||t===G}o(Jt,"isManagedProvider");function Qt(){const t=q(h(),"openai-device-id");try{const e=ct(t,"utf8").trim();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e))return e.toLowerCase()}catch{}const n=U();return st(h(),{recursive:!0,mode:448}),lt(t,`${n}
3
- `,{mode:384}),n}o(Qt,"openAIDeviceId");function b(t){return Q[t].label}o(b,"getProviderLabel");function Xt(t,n=Date.now(),e={}){const a=[],i=[];for(let r=0;r<t.length;r++){const s=t[r],c=s.registered?s.automaticFallback===!1?"non-managed-fallback":s.authenticated?(s.coolingUntil??0)>n?"cooling":void 0:"unauthenticated":"unregistered";if(!c)a.push(s);else if(i.push({candidate:s,reason:c}),e.pinnedToFirst&&r===0&&c!=="cooling")break}return{candidates:a,rejected:i}}o(Xt,"resolveProviderCandidates");class R extends Error{static{o(this,"DuplicateSubscriptionError")}constructor(n){super(n),this.name="DuplicateSubscriptionError"}}function D(t){return V(t,gt(t)).map(({entry:n})=>n)}o(D,"readSubscriptionPool");async function E(t,n){const e=K(t);return v(t).withLockAsync(async(a,i,r)=>{const s=Z(e,a);return{result:await n(s,V(t,s),c=>r(`${JSON.stringify(c)}
4
- `))}})}o(E,"locked");function M(t,n,e){g(t,"INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)").run(n,e.id,e.label,e.labelKey,e.position,e.lastAttemptAt,e.lastRateLimitedAt,e.rateLimitedUntil,e.authFailure??null)}o(M,"insert");function x(t,n){g(t,"UPDATE managed_accounts SET label=?,label_key=?,position=?,last_attempt_at=?,last_rate_limited_at=?,rate_limited_until=?,auth_failure=? WHERE provider_id=? AND id=?").run(n.label,n.labelKey,n.position,n.lastAttemptAt,n.lastRateLimitedAt,n.rateLimitedUntil,n.authFailure??null,n.providerId,n.id)}o(x,"update");function at(t,n,e,a,i,r){g(t,"INSERT INTO managed_account_model_cooldowns(provider_id,account_id,family,rate_limited_until,last_rate_limited_at) VALUES(?,?,?,?,?) ON CONFLICT(provider_id,account_id,family) DO UPDATE SET rate_limited_until=excluded.rate_limited_until,last_rate_limited_at=excluded.last_rate_limited_at").run(n,e,a,i,r)}o(at,"upsertModelCooldown");function C(t,n,e){e===void 0?g(t,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=?").run(n):g(t,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=? AND account_id=?").run(n,e)}o(C,"deleteModelCooldowns");function w(t,n){return V(t,n).map(({entry:e})=>e)}o(w,"publicPool");function $(t,n){try{n()}catch(e){throw new Error(`managed ${b(t)} credential file was published, but its SQL membership update failed; SQL membership remains authoritative: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}o($,"writeMembershipAfterCredentialPublish");async function Yt(t,n){return E(t,async(e,a,i)=>{const r=n.map(u=>N(t,u)),s=r.map((u,l)=>({entry:u,id:a[l]?.row.id??U()})),c={};for(const{entry:u,id:l}of s)c[l]=I(u);return i({version:1,accounts:c}),$(t,()=>A(h(),u=>{const l=T(u,t);g(u,"DELETE FROM managed_accounts WHERE provider_id=?").run(t),g(u,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=?").run(t),s.forEach(({entry:m,id:d},y)=>{M(u,t,{providerId:t,id:d,label:m.label,labelKey:f(m.label),position:y,lastAttemptAt:m.lastAttemptAt,lastRateLimitedAt:m.lastRateLimitedAt,rateLimitedUntil:m.rateLimitedUntil,...m.authFailure?{authFailure:m.authFailure}:{}});for(const[F,k]of Object.entries(m.modelCooldowns??{}))at(u,t,d,F,k,l.get(d)?.find(p=>p.family===F)?.lastRateLimitedAt??m.lastRateLimitedAt)})})),r})}o(Yt,"writeSubscriptionPool");function O(t,n){const e=n.trim().toLowerCase(),a=Number.parseInt(e,10);return Number.isFinite(a)&&String(a)===e&&a>=1&&a<=t.length?a-1:t.findIndex(({entry:i})=>f(i.label)===e)}o(O,"resolve");async function Rt(t,n){const e=N(t,n);return E(t,async(a,i,r)=>{if(i.some(({entry:l})=>f(l.label)===f(e.label)))throw new R(`${b(t)} subscription already exists: ${e.label}`);const s=_(e),c=i.find(({entry:l})=>_(l)===s);if(s&&c)throw new R(`This ${b(t)} account is already added as \u201C${c.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const u=U();return a.accounts[u]=I(e),r(a),$(t,()=>A(h(),l=>M(l,t,{providerId:t,id:u,label:e.label,labelKey:f(e.label),position:i.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil,...e.authFailure?{authFailure:e.authFailure}:{}}))),w(t,a)})}o(Rt,"addSubscription");async function Zt(t,n){const e=N(t,n);return D(t).find(i=>f(i.label)===f(e.label))?It(t,e):Rt(t,e)}o(Zt,"upsertSubscription");async function It(t,n){const e=N(t,n);return E(t,async(a,i,r)=>{const s=i.findIndex(({entry:d})=>f(d.label)===f(e.label)),c=i[s],u=i.find(({entry:d},y)=>y!==s&&_(d)===_(e));if(_(e)&&u)throw new R(`This ${b(t)} account is already added as \u201C${u.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);if(!c){const d=U();return a.accounts[d]=I(e),r(a),$(t,()=>A(h(),y=>M(y,t,{providerId:t,id:d,label:e.label,labelKey:f(e.label),position:i.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil}))),w(t,a)}const l=c.row,m=e.lastRateLimitedAt>=l.lastRateLimitedAt;return a.accounts[l.id]=I(e),r(a),$(t,()=>A(h(),d=>{x(d,{...l,label:e.label,labelKey:f(e.label),lastAttemptAt:Math.max(l.lastAttemptAt,e.lastAttemptAt),lastRateLimitedAt:m?e.lastRateLimitedAt:l.lastRateLimitedAt,rateLimitedUntil:m?e.rateLimitedUntil:l.rateLimitedUntil}),tt(c.entry,e)&&C(d,t,l.id)})),w(t,a)})}o(It,"upsertSubscriptionWithUniqueAccount");async function vt(t,n,e){return E(t,async(a,i)=>{const r=O(i,n);if(r<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const s=e.trim();if(!s)throw new Error(`${b(t)} subscription label cannot be empty`);if(i.some((c,u)=>u!==r&&f(c.entry.label)===f(s)))throw new R(`${b(t)} subscription already exists: ${s}`);return A(h(),c=>x(c,{...i[r].row,label:s,labelKey:f(s)})),w(t,a)})}o(vt,"renameSubscription");async function B(t,n){return E(t,async(e,a,i)=>{const r=O(a,n);if(r<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const s=a[r].row;return A(h(),c=>{g(c,"DELETE FROM managed_accounts WHERE provider_id=? AND id=?").run(t,s.id),C(c,t,s.id)}),delete e.accounts[s.id],i(e),w(t,e)})}o(B,"remove");async function te(t,n){return B(t,n)}o(te,"removeManagedAccount");async function ee(t,n){return B(t,n)}o(ee,"removeSubscription");async function $t(t){return E(t,async(n,e,a)=>{A(h(),i=>{g(i,"DELETE FROM managed_accounts WHERE provider_id=?").run(t),C(i,t)});for(const{row:i}of e)delete n.accounts[i.id];return a(n),e.length})}o($t,"removeAllManagedAccounts");async function ne(t,n){return n===void 0?(await $t(t),[]):B(t,n)}o(ne,"removeManagedProvider");async function ae(t,n){return E(t,async(e,a)=>{const i=O(a,n);if(i<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);return A(h(),r=>{[a[i],...a.filter((c,u)=>u!==i)].forEach((c,u)=>x(r,{...c.row,position:u}))}),w(t,e)})}o(ae,"promoteSubscription");async function it(t,n,e){return A(h(),a=>{const i=P(a,t,n);if(!i)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const r=e(i);r&&x(a,r)}),D(t)}o(it,"mutateHealth");async function ie(t,n,e=Date.now()){return it(t,n,a=>({...a,lastAttemptAt:Math.max(a.lastAttemptAt,e)}))}o(ie,"markSubscriptionAttempt");async function re(t,n,e,a,i=Date.now()){return E(t,async(r,s)=>{const c=s.find(({entry:u})=>f(u.label)===f(n));if(!c)throw new Error(`Unknown ${b(t)} subscription: ${n}`);return c.entry.refresh!==e.refresh||c.entry.access!==e.access||A(h(),u=>x(u,{...c.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(c.row.lastAttemptAt,i),rateLimitedUntil:Math.max(c.row.rateLimitedUntil,i+Math.max(0,a))})),w(t,r)})}o(re,"markSubscriptionAuthenticationFailed");async function oe(t,n,e,a=Date.now(),i=Date.now(),r={kind:"account"}){return r.kind==="account"?it(t,n,s=>i<s.lastRateLimitedAt?null:{...s,lastAttemptAt:Math.max(s.lastAttemptAt,a),lastRateLimitedAt:i,rateLimitedUntil:i+Math.max(0,e)}):(A(h(),s=>{const c=P(s,t,n);if(!c)throw new Error(`Unknown ${b(t)} subscription: ${n}`);x(s,{...c,lastAttemptAt:Math.max(c.lastAttemptAt,a)});const u=T(s,t).get(c.id)?.find(l=>l.family===r.family);u&&i<u.lastRateLimitedAt||at(s,t,c.id,r.family,i+Math.max(0,e),i)}),D(t))}o(oe,"markSubscriptionRateLimited");async function se(t,n,e=Date.now(),a){const i=j(a);return A(h(),r=>{const s=P(r,t,n);if(!s)throw new Error(`Unknown ${b(t)} subscription: ${n}`);if(e>=s.lastRateLimitedAt&&x(r,{...s,authFailure:void 0,lastAttemptAt:Math.max(s.lastAttemptAt,e),rateLimitedUntil:0}),i===void 0)return;const c=T(r,t).get(s.id)?.find(u=>u.family===i);c&&e>=c.lastRateLimitedAt&&g(r,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=? AND account_id=? AND family=?").run(t,s.id,i)}),D(t)}o(se,"markSubscriptionSuccess");async function ce(t,n,e){return E(t,async(a,i,r)=>{const s=O(i,n);if(s<0)throw new Error(`${b(t)} subscription "${n}" no longer exists`);const c=i[s];if(c.entry.expires>Date.now())return c.entry;const u=await e(c.entry.refresh,c.entry.clientId),l=et(nt(t,c.entry.label,u),u.clientId??c.entry.clientId);return a.accounts[c.row.id]={...a.accounts[c.row.id],...l},r(a),{...c.entry,...l}})}o(ce,"refreshSubscriptionCredential");function Ft(t){const n=t,e=[n?.errorMessage,n?.message,t instanceof Error?t.message:""].filter(i=>typeof i=="string").join(" ");return(typeof n?.status=="number"?n.status:Number(e.match(/\bstatus[=:]\s*(\d+)/i)?.[1]))===400&&/invalid_grant|refresh token .*invalid|refresh token .*not found/i.test(e)}o(Ft,"isInvalidRefreshTokenError");async function le(t,n,e){return E(t,async(a,i,r)=>{const s=new Set;let c;for(;s.size<i.length;){const u=n(i.filter(({entry:m})=>!s.has(m.label)).map(({entry:m})=>m));if(!u)break;const l=i.find(({entry:m})=>m.label===u.label);s.add(l.entry.label);try{const m=await e(l.entry);if(m){const d=et(nt(t,l.entry.label,m),m.clientId??l.entry.clientId);return a.accounts[l.row.id]={...a.accounts[l.row.id],...d},r(a),{...l.entry,...d}}return l.entry}catch(m){if(!Ft(m))throw m;c=m;const d=Date.now();A(h(),y=>x(y,{...l.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(l.row.lastAttemptAt,d),rateLimitedUntil:Math.max(l.row.rateLimitedUntil,d+At)}))}}if(c)throw c})}o(le,"modifyElectedSubscription");async function St(t,n){const e=n.accountId?.trim(),a=n.email?.trim();if(t!==H)return{...e?{accountId:e}:{},...a?{email:a}:{}};try{const i=await fetch("https://api.anthropic.com/api/oauth/profile",{headers:{Authorization:`Bearer ${n.access}`,Accept:"application/json"},signal:AbortSignal.timeout(3e3)});if(!i.ok)return e?{accountId:e}:{};const r=await i.json(),s=typeof r.account?.uuid=="string"&&r.account.uuid.trim()?r.account.uuid.trim():void 0,c=typeof r.account?.email=="string"&&r.account.email.trim()?r.account.email.trim():void 0;return{...s?{accountId:s}:{},...c?{email:c}:{}}}catch{return e?{accountId:e}:{}}}o(St,"enrichManagedLoginIdentity");async function ue(t,n,e){const a=await St(t,e);return E(t,async(i,r,s)=>{const c=e.autoLabel?void 0:n?.trim(),u=_({refresh:e.refresh,accountId:a.accountId}),l=(c?r.find(({entry:p})=>f(p.label)===f(c)):void 0)??r.find(({entry:p})=>_(p)===u);let m=l?.entry.label??c;if(!m&&e.autoLabel){const p=a.email||n?.trim()||`Account ${r.length+1}`;m=p;for(let S=2;r.some(({entry:L})=>f(L.label)===f(m));S++)m=`${p} (${S})`}if(!m)throw new Error(`${b(t)} subscription label cannot be empty`);const d=N(t,{label:m,refresh:e.refresh,access:e.access,expires:e.expires,...a.accountId?{accountId:a.accountId}:{},...e.clientId?{clientId:e.clientId}:{},rateLimitedUntil:0,lastAttemptAt:Date.now(),lastRateLimitedAt:e.lastRateLimitedAt});if(!l){if(r.some(({entry:L})=>f(L.label)===f(d.label)))throw new R(`${b(t)} subscription already exists: ${d.label}`);const p=r.find(({entry:L})=>_(L)===_(d));if(_(d)&&p)throw new R(`This ${b(t)} account is already added as \u201C${p.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const S=U();return i.accounts[S]=I(d),s(i),$(t,()=>A(h(),L=>M(L,t,{providerId:t,id:S,label:d.label,labelKey:f(d.label),position:r.length,lastAttemptAt:d.lastAttemptAt,lastRateLimitedAt:d.lastRateLimitedAt,rateLimitedUntil:d.rateLimitedUntil}))),w(t,i)}const y=l.row,F=r.find(({entry:p})=>p.label!==l.entry.label&&_(p)===_(d));if(_(d)&&F)throw new R(`This ${b(t)} account is already added as \u201C${F.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);i.accounts[y.id]=I(d),s(i);const k=d.lastRateLimitedAt>=y.lastRateLimitedAt;return $(t,()=>A(h(),p=>{x(p,{...y,authFailure:void 0,lastAttemptAt:Math.max(y.lastAttemptAt,d.lastAttemptAt),lastRateLimitedAt:k?d.lastRateLimitedAt:y.lastRateLimitedAt,rateLimitedUntil:k?0:y.rateLimitedUntil}),tt(l.entry,d)&&C(p,t,y.id)})),w(t,i)})}o(ue,"commitManagedLogin");function Ut(t,n=Date.now()){if(!t?.trim())return;const e=Number(t.trim());if(Number.isFinite(e))return Math.max(0,Math.round(e*1e3));const a=Date.parse(t);return Number.isFinite(a)?Math.max(0,a-n):void 0}o(Ut,"parseRetryAfterHeader");function Nt(t){if(!t)return;const n=o(a=>t instanceof Headers?t.get(a)??void 0:Object.entries(t).find(([i])=>i.toLowerCase()===a)?.[1],"get"),e=n("retry-after-ms");return e!==void 0&&e.trim()!==""&&Number.isFinite(Number(e))?Math.max(0,Number(e)):Ut(n("retry-after"))}o(Nt,"retryAfterMsFromHeaders");function de(t){if(!t||typeof t!="object"||!("headers"in t))return;const n=t.headers;if(!(!(n instanceof Headers)&&(!n||typeof n!="object"||Array.isArray(n))))return Nt(n)}o(de,"retryAfterMsFromError");function Dt(){const t=ut();if(t)return t.rotation;const n=g(ft(ht(h())),"SELECT default_fallback_strength,revert_when_available FROM rotation_settings WHERE singleton=1").get();return{defaultFallbackStrength:X(n?.default_fallback_strength)??J,revertWhenAvailable:n?.revert_when_available===void 0||n.revert_when_available===null?!0:!!n.revert_when_available}}o(Dt,"readRotationConfig");function me(t){const n=Dt(),e={defaultFallbackStrength:X(t.defaultFallbackStrength)??n.defaultFallbackStrength??J,revertWhenAvailable:t.revertWhenAvailable??n.revertWhenAvailable??!0};return A(h(),a=>g(a,"INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?) ON CONFLICT(singleton) DO UPDATE SET default_fallback_strength=excluded.default_fallback_strength,revert_when_available=excluded.revert_when_available").run(e.defaultFallbackStrength,e.revertWhenAvailable?1:0)),e}o(me,"writeRotationConfig");function fe(t,n=Date.now(),e){const a=D(t),i=a.filter(s=>s.authFailure===void 0&&Et(s,e)<=n),r=b(t);return i.length===0?`${r} pool exhausted`:`${r} ${i[0]?.label??t} (${i.length}/${a.length} ready)`}o(fe,"formatStatusLine");export{H as ANTHROPIC_PROVIDER_ID,R as DuplicateSubscriptionError,At as INVALID_REFRESH_TOKEN_BACKOFF_MS,qt as MANAGED_PROVIDER_IDS,G as OPENAI_CHATGPT_PROVIDER_ID,z as OPENAI_CODEX_PROVIDER_ID,wt as activeCooldowns,Rt as addSubscription,ue as commitManagedLogin,Et as coolingUntilFor,St as enrichManagedLoginIdentity,zt as formatCooldowns,fe as formatStatusLine,b as getProviderLabel,Ft as isInvalidRefreshTokenError,Jt as isManagedProvider,ie as markSubscriptionAttempt,re as markSubscriptionAuthenticationFailed,oe as markSubscriptionRateLimited,se as markSubscriptionSuccess,le as modifyElectedSubscription,Qt as openAIDeviceId,Ut as parseRetryAfterHeader,ae as promoteSubscription,Dt as readRotationConfig,D as readSubscriptionPool,ce as refreshSubscriptionCredential,$t as removeAllManagedAccounts,te as removeManagedAccount,ne as removeManagedProvider,ee as removeSubscription,vt as renameSubscription,Xt as resolveProviderCandidates,de as retryAfterMsFromError,Nt as retryAfterMsFromHeaders,Gt as subscriptionNeedsSuccessWrite,Zt as upsertSubscription,It as upsertSubscriptionWithUniqueAccount,me as writeRotationConfig,Yt as writeSubscriptionPool};
1
+ var rt=Object.defineProperty;var o=(t,n)=>rt(t,"name",{value:n,configurable:!0});import{prepared as g}from"./sqlite-statements.js";import{createHash as ot,randomUUID as N}from"node:crypto";import{mkdirSync as st,readFileSync as ct,writeFileSync as lt}from"node:fs";import{join as q}from"node:path";import{brokerConfigSnapshot as ut}from"./config.js";import{LockedJsonFile as dt}from"./locked-file.js";import{secretsDir as mt}from"./layout.js";import{openScopedStore as ft}from"./scoped-state/db.js";import{providerStore as ht}from"./scoped-state/paths.js";import{providerModelCooldowns as T,providerModelCooldownsFor as bt,providerRowByReference as P,providerRows as pt,providerWrite as A}from"./scoped-state/providers.js";import{modelCooldownFamily as j}from"./rate-limit-scope.js";const W="anthropic",z="openai-codex",G="openai",At=600*1e3,yt=720*60*60*1e3,zt=[W,z,G],J="strong",Q={anthropic:{label:"Claude",credentials:"anthropic-credentials.json"},"openai-codex":{label:"OpenAI Codex",credentials:"openai-codex-credentials.json"},openai:{label:"ChatGPT",credentials:"openai-credentials.json"}};function I(t){return{refresh:t.refresh,access:t.access,expires:t.expires,...t.accountId?{accountId:t.accountId}:{},...t.clientId?{clientId:t.clientId}:{}}}o(I,"stored");function H(t){return typeof t=="string"&&t.trim()?t.trim():void 0}o(H,"optionalString");function h(){return mt()}o(h,"agentDir");function K(t){return q(h(),Q[t].credentials)}o(K,"credentialFile");function X(t){return t==="ultra"||t==="strong"||t==="medium"||t==="light"?t:void 0}o(X,"normalizeStrength");function f(t){return t.toLowerCase()}o(f,"key");function _t(t){const n=typeof t.label=="string"?t.label.trim():"",e=typeof t.refresh=="string"?t.refresh.trim():"",a=typeof t.access=="string"?t.access.trim():"",i=Number(t.expires);if(!n||!e||!a||!Number.isFinite(i))return;const r=H(t.accountId),s=H(t.clientId);return{label:n,refresh:e,access:a,expires:i,rateLimitedUntil:Number.isFinite(Number(t.rateLimitedUntil))?Number(t.rateLimitedUntil):0,lastAttemptAt:Number.isFinite(Number(t.lastAttemptAt))?Number(t.lastAttemptAt):0,lastRateLimitedAt:Number.isFinite(Number(t.lastRateLimitedAt))?Number(t.lastRateLimitedAt):0,...t.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},...r?{accountId:r}:{},...s?{clientId:s}:{},...Y(t.modelCooldowns)?{modelCooldowns:Y(t.modelCooldowns)}:{}}}o(_t,"credential");function Y(t){if(!t||typeof t!="object"||Array.isArray(t))return;const n=Object.entries(t).filter(([e,a])=>e.trim()!==""&&Number.isFinite(Number(a))).map(([e,a])=>[e,Number(a)]);return n.length?Object.fromEntries(n):void 0}o(Y,"modelCooldowns");function U(t,n){if(!n.label?.trim())throw new Error(`${b(t)} subscription label cannot be empty`);const e=_t(n);if(!e)throw new Error(`Refusing to persist incomplete ${b(t)} subscription "${n.label.trim()}"; pool rows require both OAuth tokens.`);return e}o(U,"assertCredential");function Z(t,n){if(!n||n.trim()==="")return{version:1,accounts:{}};let e;try{e=JSON.parse(n)}catch(a){throw new Error(`managed credential file ${t} is corrupt: ${a instanceof Error?a.message:String(a)}`)}if(typeof e!="object"||e===null||Array.isArray(e)||e.version!==1||typeof e.accounts!="object"||e.accounts===null||Array.isArray(e.accounts))throw new Error(`managed credential file ${t} is corrupt`);return e}o(Z,"parseCredentials");function gt(t,n,e=[]){const a=n.accounts[t.id];if(!a||typeof a.refresh!="string"||typeof a.access!="string"||!Number.isFinite(a.expires))throw new Error(`managed ${t.providerId} account ${t.id} has no credential record`);return{label:t.label,refresh:a.refresh,access:a.access,expires:a.expires,rateLimitedUntil:t.rateLimitedUntil,lastAttemptAt:t.lastAttemptAt,lastRateLimitedAt:t.lastRateLimitedAt,...t.authFailure?{authFailure:t.authFailure}:{},...a.accountId?{accountId:a.accountId}:{},...a.clientId?{clientId:a.clientId}:{},...e.length?{modelCooldowns:Object.fromEntries(e.map(i=>[i.family,i.rateLimitedUntil]))}:{}}}o(gt,"toPublic");function V(t,n){const e=bt(h(),t);return pt(h(),t).map(a=>({row:a,entry:gt(a,n,e.get(a.id))}))}o(V,"rowsWithCredentials");function v(t){return new dt(K(t),!0,`{"version":1,"accounts":{}}
2
+ `)}o(v,"managedCredentialFile");function Et(t){return Z(K(t),v(t).readUnlocked())}o(Et,"readFile");function tt(t,n){const e=t.accountId?.trim(),a=n.accountId?.trim();return!!(e&&a&&e!==a)}o(tt,"differentAccount");function _(t){return t.accountId?.trim()||(t.refresh.trim()?`refresh:${ot("sha256").update(t.refresh.trim()).digest("hex")}`:void 0)}o(_,"identity");function et(t,n){const e=H(n);return e?{...t,clientId:e}:t}o(et,"withClientId");function nt(t,n,e){const a=e.refresh?.trim()??"",i=e.access?.trim()??"",r=Number(e.expires);if(!a||!i||!Number.isFinite(r))throw new Error(`${b(t)} subscription "${n}" returned an incomplete credential; the stored credential was left unchanged.`);return{refresh:a,access:i,expires:r}}o(nt,"assertTokens");function wt(t,n){const e=j(n);return Math.max(t.rateLimitedUntil||0,e===void 0?0:t.modelCooldowns?.[e]??0)}o(wt,"coolingUntilFor");function xt(t,n=Date.now()){return[...(t.rateLimitedUntil||0)>n?[{scope:"account",until:t.rateLimitedUntil}]:[],...Object.entries(t.modelCooldowns??{}).filter(([,e])=>e>n).map(([e,a])=>({scope:e,until:a}))]}o(xt,"activeCooldowns");function Gt(t,n=Date.now()){const e=xt(t,n).map(({scope:a,until:i})=>`${a==="account"?"":`${a} `}cooldown ${Lt(i-n)}`);return e.length?e.join(", "):void 0}o(Gt,"formatCooldowns");function Lt(t){const n=Math.max(1,Math.ceil(t/6e4));if(n<60)return`${n}m`;const e=Math.floor(n/60);return e<24?`${e}h${n%60?` ${n%60}m`:""}`:`${Math.floor(e/24)}d${e%24?` ${e%24}h`:""}`}o(Lt,"formatWait");function Rt(t,n){const e=j(n);return e!==void 0&&t.modelCooldowns?.[e]!==void 0}o(Rt,"hasModelCooldownRow");function Jt(t,n){return!!(t.rateLimitedUntil||t.authFailure)||Rt(t,n)}o(Jt,"subscriptionNeedsSuccessWrite");function Qt(t){return t===W||t===z||t===G}o(Qt,"isManagedProvider");function Xt(){const t=q(h(),"openai-device-id");try{const e=ct(t,"utf8").trim();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e))return e.toLowerCase()}catch{}const n=N();return st(h(),{recursive:!0,mode:448}),lt(t,`${n}
3
+ `,{mode:384}),n}o(Xt,"openAIDeviceId");function b(t){return Q[t].label}o(b,"getProviderLabel");function Yt(t,n=Date.now(),e={}){const a=[],i=[];for(let r=0;r<t.length;r++){const s=t[r],c=s.registered?s.automaticFallback===!1?"non-managed-fallback":s.authenticated?(s.coolingUntil??0)>n?"cooling":void 0:"unauthenticated":"unregistered";if(!c)a.push(s);else if(i.push({candidate:s,reason:c}),e.pinnedToFirst&&r===0&&c!=="cooling")break}return{candidates:a,rejected:i}}o(Yt,"resolveProviderCandidates");class R extends Error{static{o(this,"DuplicateSubscriptionError")}constructor(n){super(n),this.name="DuplicateSubscriptionError"}}function D(t){return V(t,Et(t)).map(({entry:n})=>n)}o(D,"readSubscriptionPool");async function E(t,n){const e=K(t);return v(t).withLockAsync(async(a,i,r)=>{const s=Z(e,a);return{result:await n(s,V(t,s),c=>r(`${JSON.stringify(c)}
4
+ `))}})}o(E,"locked");function k(t,n,e){g(t,"INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)").run(n,e.id,e.label,e.labelKey,e.position,e.lastAttemptAt,e.lastRateLimitedAt,e.rateLimitedUntil,e.authFailure??null)}o(k,"insert");function x(t,n){g(t,"UPDATE managed_accounts SET label=?,label_key=?,position=?,last_attempt_at=?,last_rate_limited_at=?,rate_limited_until=?,auth_failure=? WHERE provider_id=? AND id=?").run(n.label,n.labelKey,n.position,n.lastAttemptAt,n.lastRateLimitedAt,n.rateLimitedUntil,n.authFailure??null,n.providerId,n.id)}o(x,"update");function at(t,n,e,a,i,r){g(t,"INSERT INTO managed_account_model_cooldowns(provider_id,account_id,family,rate_limited_until,last_rate_limited_at) VALUES(?,?,?,?,?) ON CONFLICT(provider_id,account_id,family) DO UPDATE SET rate_limited_until=excluded.rate_limited_until,last_rate_limited_at=excluded.last_rate_limited_at").run(n,e,a,i,r)}o(at,"upsertModelCooldown");function C(t,n,e){e===void 0?g(t,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=?").run(n):g(t,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=? AND account_id=?").run(n,e)}o(C,"deleteModelCooldowns");function w(t,n){return V(t,n).map(({entry:e})=>e)}o(w,"publicPool");function $(t,n){try{n()}catch(e){throw new Error(`managed ${b(t)} credential file was published, but its SQL membership update failed; SQL membership remains authoritative: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}o($,"writeMembershipAfterCredentialPublish");async function Zt(t,n){return E(t,async(e,a,i)=>{const r=n.map(u=>U(t,u)),s=r.map((u,l)=>({entry:u,id:a[l]?.row.id??N()})),c={};for(const{entry:u,id:l}of s)c[l]=I(u);return i({version:1,accounts:c}),$(t,()=>A(h(),u=>{const l=T(u,t);g(u,"DELETE FROM managed_accounts WHERE provider_id=?").run(t),g(u,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=?").run(t),s.forEach(({entry:m,id:d},y)=>{k(u,t,{providerId:t,id:d,label:m.label,labelKey:f(m.label),position:y,lastAttemptAt:m.lastAttemptAt,lastRateLimitedAt:m.lastRateLimitedAt,rateLimitedUntil:m.rateLimitedUntil,...m.authFailure?{authFailure:m.authFailure}:{}});for(const[F,M]of Object.entries(m.modelCooldowns??{}))at(u,t,d,F,M,l.get(d)?.find(p=>p.family===F)?.lastRateLimitedAt??m.lastRateLimitedAt)})})),r})}o(Zt,"writeSubscriptionPool");function O(t,n){const e=n.trim().toLowerCase(),a=Number.parseInt(e,10);return Number.isFinite(a)&&String(a)===e&&a>=1&&a<=t.length?a-1:t.findIndex(({entry:i})=>f(i.label)===e)}o(O,"resolve");async function It(t,n){const e=U(t,n);return E(t,async(a,i,r)=>{if(i.some(({entry:l})=>f(l.label)===f(e.label)))throw new R(`${b(t)} subscription already exists: ${e.label}`);const s=_(e),c=i.find(({entry:l})=>_(l)===s);if(s&&c)throw new R(`This ${b(t)} account is already added as \u201C${c.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const u=N();return a.accounts[u]=I(e),r(a),$(t,()=>A(h(),l=>k(l,t,{providerId:t,id:u,label:e.label,labelKey:f(e.label),position:i.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil,...e.authFailure?{authFailure:e.authFailure}:{}}))),w(t,a)})}o(It,"addSubscription");async function vt(t,n){const e=U(t,n);return D(t).find(i=>f(i.label)===f(e.label))?$t(t,e):It(t,e)}o(vt,"upsertSubscription");async function $t(t,n){const e=U(t,n);return E(t,async(a,i,r)=>{const s=i.findIndex(({entry:d})=>f(d.label)===f(e.label)),c=i[s],u=i.find(({entry:d},y)=>y!==s&&_(d)===_(e));if(_(e)&&u)throw new R(`This ${b(t)} account is already added as \u201C${u.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);if(!c){const d=N();return a.accounts[d]=I(e),r(a),$(t,()=>A(h(),y=>k(y,t,{providerId:t,id:d,label:e.label,labelKey:f(e.label),position:i.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil}))),w(t,a)}const l=c.row,m=e.lastRateLimitedAt>=l.lastRateLimitedAt;return a.accounts[l.id]=I(e),r(a),$(t,()=>A(h(),d=>{x(d,{...l,label:e.label,labelKey:f(e.label),lastAttemptAt:Math.max(l.lastAttemptAt,e.lastAttemptAt),lastRateLimitedAt:m?e.lastRateLimitedAt:l.lastRateLimitedAt,rateLimitedUntil:m?e.rateLimitedUntil:l.rateLimitedUntil}),tt(c.entry,e)&&C(d,t,l.id)})),w(t,a)})}o($t,"upsertSubscriptionWithUniqueAccount");async function te(t,n,e){return E(t,async(a,i)=>{const r=O(i,n);if(r<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const s=e.trim();if(!s)throw new Error(`${b(t)} subscription label cannot be empty`);if(i.some((c,u)=>u!==r&&f(c.entry.label)===f(s)))throw new R(`${b(t)} subscription already exists: ${s}`);return A(h(),c=>x(c,{...i[r].row,label:s,labelKey:f(s)})),w(t,a)})}o(te,"renameSubscription");async function B(t,n){return E(t,async(e,a,i)=>{const r=O(a,n);if(r<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const s=a[r].row;return A(h(),c=>{g(c,"DELETE FROM managed_accounts WHERE provider_id=? AND id=?").run(t,s.id),C(c,t,s.id)}),delete e.accounts[s.id],i(e),w(t,e)})}o(B,"remove");async function ee(t,n){return B(t,n)}o(ee,"removeManagedAccount");async function ne(t,n){return B(t,n)}o(ne,"removeSubscription");async function Ft(t){return E(t,async(n,e,a)=>{A(h(),i=>{g(i,"DELETE FROM managed_accounts WHERE provider_id=?").run(t),C(i,t)});for(const{row:i}of e)delete n.accounts[i.id];return a(n),e.length})}o(Ft,"removeAllManagedAccounts");async function ae(t,n){return n===void 0?(await Ft(t),[]):B(t,n)}o(ae,"removeManagedProvider");async function ie(t,n){return E(t,async(e,a)=>{const i=O(a,n);if(i<0)throw new Error(`Unknown ${b(t)} subscription: ${n}`);return A(h(),r=>{[a[i],...a.filter((c,u)=>u!==i)].forEach((c,u)=>x(r,{...c.row,position:u}))}),w(t,e)})}o(ie,"promoteSubscription");async function it(t,n,e){return A(h(),a=>{const i=P(a,t,n);if(!i)throw new Error(`Unknown ${b(t)} subscription: ${n}`);const r=e(i);r&&x(a,r)}),D(t)}o(it,"mutateHealth");async function re(t,n,e=Date.now()){return it(t,n,a=>({...a,lastAttemptAt:Math.max(a.lastAttemptAt,e)}))}o(re,"markSubscriptionAttempt");async function oe(t,n,e,a,i=Date.now()){return E(t,async(r,s)=>{const c=s.find(({entry:u})=>f(u.label)===f(n));if(!c)throw new Error(`Unknown ${b(t)} subscription: ${n}`);return c.entry.refresh!==e.refresh||c.entry.access!==e.access||A(h(),u=>x(u,{...c.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(c.row.lastAttemptAt,i),rateLimitedUntil:Math.max(c.row.rateLimitedUntil,i+Math.max(0,a))})),w(t,r)})}o(oe,"markSubscriptionAuthenticationFailed");async function se(t,n,e,a=Date.now(),i=Date.now(),r={kind:"account"}){return e=Math.min(Math.max(0,e),At),r.kind==="account"?it(t,n,s=>i<s.lastRateLimitedAt?null:{...s,lastAttemptAt:Math.max(s.lastAttemptAt,a),lastRateLimitedAt:i,rateLimitedUntil:i+e}):(A(h(),s=>{const c=P(s,t,n);if(!c)throw new Error(`Unknown ${b(t)} subscription: ${n}`);x(s,{...c,lastAttemptAt:Math.max(c.lastAttemptAt,a)});const u=T(s,t).get(c.id)?.find(l=>l.family===r.family);u&&i<u.lastRateLimitedAt||at(s,t,c.id,r.family,i+e,i)}),D(t))}o(se,"markSubscriptionRateLimited");async function ce(t,n,e=Date.now(),a){const i=j(a);return A(h(),r=>{const s=P(r,t,n);if(!s)throw new Error(`Unknown ${b(t)} subscription: ${n}`);if(e>=s.lastRateLimitedAt&&x(r,{...s,authFailure:void 0,lastAttemptAt:Math.max(s.lastAttemptAt,e),rateLimitedUntil:0}),i===void 0)return;const c=T(r,t).get(s.id)?.find(u=>u.family===i);c&&e>=c.lastRateLimitedAt&&g(r,"DELETE FROM managed_account_model_cooldowns WHERE provider_id=? AND account_id=? AND family=?").run(t,s.id,i)}),D(t)}o(ce,"markSubscriptionSuccess");async function le(t,n,e){return E(t,async(a,i,r)=>{const s=O(i,n);if(s<0)throw new Error(`${b(t)} subscription "${n}" no longer exists`);const c=i[s];if(c.entry.expires>Date.now())return c.entry;const u=await e(c.entry.refresh,c.entry.clientId),l=et(nt(t,c.entry.label,u),u.clientId??c.entry.clientId);return a.accounts[c.row.id]={...a.accounts[c.row.id],...l},r(a),{...c.entry,...l}})}o(le,"refreshSubscriptionCredential");function St(t){const n=t,e=[n?.errorMessage,n?.message,t instanceof Error?t.message:""].filter(i=>typeof i=="string").join(" ");return(typeof n?.status=="number"?n.status:Number(e.match(/\bstatus[=:]\s*(\d+)/i)?.[1]))===400&&/invalid_grant|refresh token .*invalid|refresh token .*not found/i.test(e)}o(St,"isInvalidRefreshTokenError");async function ue(t,n,e){return E(t,async(a,i,r)=>{const s=new Set;let c;for(;s.size<i.length;){const u=n(i.filter(({entry:m})=>!s.has(m.label)).map(({entry:m})=>m));if(!u)break;const l=i.find(({entry:m})=>m.label===u.label);s.add(l.entry.label);try{const m=await e(l.entry);if(m){const d=et(nt(t,l.entry.label,m),m.clientId??l.entry.clientId);return a.accounts[l.row.id]={...a.accounts[l.row.id],...d},r(a),{...l.entry,...d}}return l.entry}catch(m){if(!St(m))throw m;c=m;const d=Date.now();A(h(),y=>x(y,{...l.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(l.row.lastAttemptAt,d),rateLimitedUntil:Math.max(l.row.rateLimitedUntil,d+yt)}))}}if(c)throw c})}o(ue,"modifyElectedSubscription");async function Nt(t,n){const e=n.accountId?.trim(),a=n.email?.trim();if(t!==W)return{...e?{accountId:e}:{},...a?{email:a}:{}};try{const i=await fetch("https://api.anthropic.com/api/oauth/profile",{headers:{Authorization:`Bearer ${n.access}`,Accept:"application/json"},signal:AbortSignal.timeout(3e3)});if(!i.ok)return e?{accountId:e}:{};const r=await i.json(),s=typeof r.account?.uuid=="string"&&r.account.uuid.trim()?r.account.uuid.trim():void 0,c=typeof r.account?.email=="string"&&r.account.email.trim()?r.account.email.trim():void 0;return{...s?{accountId:s}:{},...c?{email:c}:{}}}catch{return e?{accountId:e}:{}}}o(Nt,"enrichManagedLoginIdentity");async function de(t,n,e){const a=await Nt(t,e);return E(t,async(i,r,s)=>{const c=e.autoLabel?void 0:n?.trim(),u=_({refresh:e.refresh,accountId:a.accountId}),l=(c?r.find(({entry:p})=>f(p.label)===f(c)):void 0)??r.find(({entry:p})=>_(p)===u);let m=l?.entry.label??c;if(!m&&e.autoLabel){const p=a.email||n?.trim()||`Account ${r.length+1}`;m=p;for(let S=2;r.some(({entry:L})=>f(L.label)===f(m));S++)m=`${p} (${S})`}if(!m)throw new Error(`${b(t)} subscription label cannot be empty`);const d=U(t,{label:m,refresh:e.refresh,access:e.access,expires:e.expires,...a.accountId?{accountId:a.accountId}:{},...e.clientId?{clientId:e.clientId}:{},rateLimitedUntil:0,lastAttemptAt:Date.now(),lastRateLimitedAt:e.lastRateLimitedAt});if(!l){if(r.some(({entry:L})=>f(L.label)===f(d.label)))throw new R(`${b(t)} subscription already exists: ${d.label}`);const p=r.find(({entry:L})=>_(L)===_(d));if(_(d)&&p)throw new R(`This ${b(t)} account is already added as \u201C${p.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const S=N();return i.accounts[S]=I(d),s(i),$(t,()=>A(h(),L=>k(L,t,{providerId:t,id:S,label:d.label,labelKey:f(d.label),position:r.length,lastAttemptAt:d.lastAttemptAt,lastRateLimitedAt:d.lastRateLimitedAt,rateLimitedUntil:d.rateLimitedUntil}))),w(t,i)}const y=l.row,F=r.find(({entry:p})=>p.label!==l.entry.label&&_(p)===_(d));if(_(d)&&F)throw new R(`This ${b(t)} account is already added as \u201C${F.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);i.accounts[y.id]=I(d),s(i);const M=d.lastRateLimitedAt>=y.lastRateLimitedAt;return $(t,()=>A(h(),p=>{x(p,{...y,authFailure:void 0,lastAttemptAt:Math.max(y.lastAttemptAt,d.lastAttemptAt),lastRateLimitedAt:M?d.lastRateLimitedAt:y.lastRateLimitedAt,rateLimitedUntil:M?0:y.rateLimitedUntil}),tt(l.entry,d)&&C(p,t,y.id)})),w(t,i)})}o(de,"commitManagedLogin");function Ut(t,n=Date.now()){if(!t?.trim())return;const e=Number(t.trim());if(Number.isFinite(e))return Math.max(0,Math.round(e*1e3));const a=Date.parse(t);return Number.isFinite(a)?Math.max(0,a-n):void 0}o(Ut,"parseRetryAfterHeader");function Dt(t){if(!t)return;const n=o(a=>t instanceof Headers?t.get(a)??void 0:Object.entries(t).find(([i])=>i.toLowerCase()===a)?.[1],"get"),e=n("retry-after-ms");return e!==void 0&&e.trim()!==""&&Number.isFinite(Number(e))?Math.max(0,Number(e)):Ut(n("retry-after"))}o(Dt,"retryAfterMsFromHeaders");function me(t){if(!t||typeof t!="object"||!("headers"in t))return;const n=t.headers;if(!(!(n instanceof Headers)&&(!n||typeof n!="object"||Array.isArray(n))))return Dt(n)}o(me,"retryAfterMsFromError");function Mt(){const t=ut();if(t)return t.rotation;const n=g(ft(ht(h())),"SELECT default_fallback_strength,revert_when_available FROM rotation_settings WHERE singleton=1").get();return{defaultFallbackStrength:X(n?.default_fallback_strength)??J,revertWhenAvailable:n?.revert_when_available===void 0||n.revert_when_available===null?!0:!!n.revert_when_available}}o(Mt,"readRotationConfig");function fe(t){const n=Mt(),e={defaultFallbackStrength:X(t.defaultFallbackStrength)??n.defaultFallbackStrength??J,revertWhenAvailable:t.revertWhenAvailable??n.revertWhenAvailable??!0};return A(h(),a=>g(a,"INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?) ON CONFLICT(singleton) DO UPDATE SET default_fallback_strength=excluded.default_fallback_strength,revert_when_available=excluded.revert_when_available").run(e.defaultFallbackStrength,e.revertWhenAvailable?1:0)),e}o(fe,"writeRotationConfig");function he(t,n=Date.now(),e){const a=D(t),i=a.filter(s=>s.authFailure===void 0&&wt(s,e)<=n),r=b(t);return i.length===0?`${r} pool exhausted`:`${r} ${i[0]?.label??t} (${i.length}/${a.length} ready)`}o(he,"formatStatusLine");export{W as ANTHROPIC_PROVIDER_ID,R as DuplicateSubscriptionError,yt as INVALID_REFRESH_TOKEN_BACKOFF_MS,zt as MANAGED_PROVIDER_IDS,At as MAX_RATE_LIMIT_COOLDOWN_MS,G as OPENAI_CHATGPT_PROVIDER_ID,z as OPENAI_CODEX_PROVIDER_ID,xt as activeCooldowns,It as addSubscription,de as commitManagedLogin,wt as coolingUntilFor,Nt as enrichManagedLoginIdentity,Gt as formatCooldowns,he as formatStatusLine,b as getProviderLabel,St as isInvalidRefreshTokenError,Qt as isManagedProvider,re as markSubscriptionAttempt,oe as markSubscriptionAuthenticationFailed,se as markSubscriptionRateLimited,ce as markSubscriptionSuccess,ue as modifyElectedSubscription,Xt as openAIDeviceId,Ut as parseRetryAfterHeader,ie as promoteSubscription,Mt as readRotationConfig,D as readSubscriptionPool,le as refreshSubscriptionCredential,Ft as removeAllManagedAccounts,ee as removeManagedAccount,ae as removeManagedProvider,ne as removeSubscription,te as renameSubscription,Yt as resolveProviderCandidates,me as retryAfterMsFromError,Dt as retryAfterMsFromHeaders,Jt as subscriptionNeedsSuccessWrite,vt as upsertSubscription,$t as upsertSubscriptionWithUniqueAccount,fe as writeRotationConfig,Zt as writeSubscriptionPool};
@@ -1 +1 @@
1
- var Re=Object.defineProperty;var a=(e,t)=>Re(e,"name",{value:t,configurable:!0});import{prepared as X}from"../../../core/sqlite-statements.js";import{envProfileId as Ie}from"../../../shared/env.js";import{pausedCanvasProfiles as Oe}from"../../../core/profiles/manifest.js";import{existsSync as N,realpathSync as Z,statSync as q}from"node:fs";import{isAbsolute as G,resolve as T}from"node:path";import{appendSituationalContext as Ae,formatSituationalProse as $e}from"../../../core/runtime/situational-context.js";import{closeNode as Ce}from"../../../core/runtime/close.js";import{reviveNode as Ne}from"../../../core/runtime/revive.js";import{nowIso as B}from"../../../core/fs-utils.js";import{assertLaunchModelRegistered as x,forkNode as Te,resolveForkSource as Ee,spawnChildPrepared as Pe}from"../../../core/runtime/spawn.js";import{forkSourceNode as De,newNodeId as ee}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as ne,childrenOf as Me,completeCreateRequest as te,findCreateRequest as Le,getNode as R,recordCreateRequestNode as je,reserveCreateRequest as oe,reserveCreateRequestNode as Fe,listNodes as re,recordRespawnAttempt as Ge,subscribersOf as Be,subscriptionsOf as ie,setMessageWait as xe,updateNode as C}from"../../../core/canvas/canvas.js";import{subtreeIds as Ke}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as K}from"../../../core/canvas/db.js";import{markNodeRead as We}from"../../../core/canvas/recovery.js";import{nodeObject as Ve}from"../../../core/graph/objects.js";import{recordActedOn as ze}from"../../../core/graph/edges.js";import{publish as Je}from"../../../core/graph/events.js";import{readerFor as Ue}from"../reader.js";import{relocateSessionCwd as Ye,unbindSession as He}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Qe}from"../../../core/canvas/attention.js";import{isSafeNodeId as Xe}from"../../../core/canvas/paths.js";import{contextDir as de,nodeAgentDir as W}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as Ze}from"../../cron/authority.js";import{cronBirthPlacement as qe}from"../../cron/armed-context.js";import{existsBeneath as en,isAbsentOrRefused as nn,isBeneathRefusal as tn,readdirBeneath as on}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as rn,readNodeSession as dn,readNodeSnapshot as sn,transcriptMarkdown as an}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as ln}from"../../../core/substrate/subject.js";import{reviveAll as cn}from"../../../core/runtime/revive-all.js";import{promoteAsync as fn,requestYieldAsync as un,reshapeNodeAsync as V}from"../../../core/runtime/promote.js";import{recycleNode as pn}from"../../../core/runtime/recycle.js";import{relaunchRoot as mn}from"../../../core/runtime/reset.js";import{assertReopenGate as hn}from"../../../core/runtime/reopen.js";import{writeYieldMessage as wn,readGoal as yn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as _n,hasRoadmap as gn}from"../../../core/runtime/roadmap.js";import{renameWindow as bn}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as vn,explicitModelIntent as kn,normalizeModel as Sn,readMergedLaunchConfigAsync as se}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as Rn}from"../../../core/model-routes.js";import{persistDormantModel as In,setModelLive as On}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as ae}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as An}from"../../../core/runtime/broker-request.js";import{boundFleet as E}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as $n}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Cn}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as le}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as Nn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Tn}from"../../../core/human-actions.js";import{parseDurationMs as En}from"../../../core/wake.js";import{claimWarmNode as Pn,refillWarmPool as ce,resumeWarmClaim as Dn,warmPoolEnabled as Mn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as z,isLaunchKind as Ln,resolveLaunchTarget as jn}from"../../../core/runtime/launch-target.js";import{fullName as Fn}from"../../../core/canvas/labels.js";import{reportsForNode as fe}from"./reports.js";import{requireUsableProfile as Gn}from"./profiles.js";import{assertProfileActive as Bn,loadExactProfileManifest as xn}from"../../../core/profiles/manifest.js";import{getCron as ue}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Kn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Wn}from"../../control.js";import{notFound as P,usage as h}from"../../../core/errors.js";import{assertScope as Vn,validateScopes as pe}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as zn,toNodeDetailDTO as J,toNodeSummaryDTO as Jn,toReviveResultDTO as Un}from"../map.js";import{ApiError as u}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{actsAsPerson as Yn,brokerMayReach as U,canReadNode as me,resolvedScopes as Hn}from"../router.js";import{forwardVerb as Qn,queryWithoutMachine as Xn,relayError as Zn,unknownError as qn,withMachine as et}from"../../peer/forward.js";import{fileRoot as nt}from"../../../core/spaces/file-root.js";import{activeGrant as tt,terminalGrant as ot}from"../../../core/grants/mirror.js";import{appRungForGrant as rt}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as it}from"../../../core/model-routes.js";import{readConfig as dt}from"../../../core/config.js";import{hasConfiguredProviderCredential as st,NO_PROVIDER_CREDENTIAL_MESSAGE as he}from"../../../core/runtime/provider-credential-gate.js";function w(e){const t=R(e);if(t===null)throw P(`unknown node: ${e}`,{received:e});return t}a(w,"requireMeta");function Y(e){return{subscribesTo:ie(e),subscribers:Be(e),children:Me(e)}}a(Y,"edgesFor");function g(e){const t=w(e);return J(t,Y(e))}a(g,"detailOf");function at(e){let t=fe(e).length;try{t+=on(W(e),de(e)).length}catch(n){if(!nn(n))throw n}return t}a(at,"countFiles");function lt(e){if(typeof e!="object"||e===null)throw h("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw h("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw h("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw h("creator must be a non-empty node id when provided");if(t.scopes!==void 0&&pe(t.scopes),t.isolated!==void 0&&typeof t.isolated!="boolean")throw new u(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw h("root_lifecycle must be 'resident' or 'terminal'");if(t.request_key!==void 0&&(typeof t.request_key!="string"||t.request_key.trim()===""||t.request_key.length>128))throw h("request_key must be a non-empty string of at most 128 characters when provided");return t}a(lt,"parseCreateBody");function ct(e){if(e===void 0)return;const t=En(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new u(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}a(ct,"parseDeadline");function ft(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new u(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!Nn.test(e.action))throw new u(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new u(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new u(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>le)throw new u(413,"payload_too_large",`serialized payload exceeds ${le} bytes`)}return e}}a(ft,"parseOutcomeDelivery");function ut(e,t){const n=Tn(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new u(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new u(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}a(ut,"resolveOutcomeDelivery");function pt(e,t,n){const r={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),t!==void 0&&(r.parent=t),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=T(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}a(pt,"buildRecipe");function mt(e,t,n){return!Mn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}a(mt,"warmRequestFor");import{resolveCreateKind as pr}from"../../../core/runtime/launch-target.js";function we(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Rn(e.model,t,e.modelExact===!0)}a(we,"requestFromLaunch");function ht(e,t){if(t===null)return e;if(e.scopes===void 0)return{...e,scopes:[...t]};const n=e.scopes.filter(r=>!O(t,r));if(n.length===0)return e;throw new u(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${n.join(", ")}`,{scopes:n,ceiling:t})}a(ht,"withinCeiling");async function ye(e,t,n){const r=(await vn(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await x(we(r),{cwd:e.cwd,profileId:e.profile_id??null},n)}a(ye,"assertNodeModelChangeRegistered");function _e(e,t){const n=e.principal;if(n.class!=="broker"&&n.class!=="cron")return;const r=nt({app:n.app,resolved:Hn(n),launched:n.scopes},t,"read");if("root"in r)return;const o="missing"in r?r.missing:null;throw new u(403,"scope_missing",o?`the child's directory ${t} needs missing scope ${o}`:`no permission of this run names the child's directory ${t}`,void 0,void 0,o?{scope:o}:void 0)}a(_e,"assertCallerReaches");const H=new Map;async function wt(e,t={},n={}){const r=ht(lt(e.body),e.ceiling);if(e.principal.class==="broker"){const c=e.principal;if(r.prefer_warm===!0&&c.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const i=w(r.parent);if(i.grantee!==c.app)throw new u(403,"other_app_run","cannot create a child under another app's node");if(!U(c,r.parent,i.grantee??"app:terminal"))throw P(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==c.node)throw new u(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let i=null;try{i=De(Ee(r.fork_from))}catch{}if(i?.grantee!==c.app||!U(c,i.node_id,i.grantee))throw new u(403,"other_app_run","cannot fork another app's conversation")}r.creator=c.node}if(e.principal.class==="cron"){const c=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new u(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1;const i=Ze({grantee:c.app,sub:c.sub,grant_id:c.grant,scopes:c.scopes});if(!i.allowed)throw new u(i.reason==="scope_missing"?403:401,i.reason==="scope_missing"?"scope_missing":"grant_revoked",i.message);if(r.scopes!==void 0){const l=r.scopes.find(p=>!O(i.effectiveScopes,p)||!O(c.scopes,p));if(l!==void 0)throw new u(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else c.scopes!==null&&(r.scopes=[...c.scopes]);r.node_id=ee(),c.isolated&&(r.isolated=!0,r.cwd=W(r.node_id,c.app))}r.creator!==void 0&&Vn(w(r.creator),"crtr:act");const o=r.request_key?.trim();if(o===void 0||r.node_id!==void 0&&Xe(r.node_id)&&R(r.node_id)!==null&&Le(o)?.nodeId!==r.node_id)return D(e,r,t,n);const s=H.get(o);if(s!==void 0)return s;const d=yt(e,r,o,t,n);H.set(o,d);try{return await d}finally{H.delete(o)}}a(wt,"handleCreate");async function yt(e,t,n,r,o){const s=oe(n);if(s.nodeId!==null&&R(s.nodeId)!==null){if(s.state!=="warm_claimed"){const d=R(s.nodeId);if(e.principal.class!=="person"&&!me(e.principal,d.grantee??"app:terminal",s.nodeId))throw new u(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:g(s.nodeId)}}return D(e,t,r,o,s)}try{return await D(e,t,r,o,s)}catch(d){const c=oe(n);throw(c.nodeId===null||R(c.nodeId)===null)&&ne(n,c.nodeId),d}}a(yt,"handleKeyedCreateRequest");async function D(e,t,n,r,o=void 0){const s=r.deadlineAt??ct(t.deadline),d=ft(t.outcome_delivery),c=e.principal.class==="cron"?qe({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:ue(e.principal.cron)?.created_by??null},t.node_id):null;c!==null&&(t.root=c.root===!0);const i=c?.parent??t.parent??void 0;if(i==null&&t.root!==!0)throw h("a node create requires a parent (or root: true for an independent root)");let l=null;if(t.output_schema!==void 0){try{l=JSON.parse(t.output_schema)}catch{throw h("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw h("output_schema must be a JSON schema object");await Cn(l)}const{profileId:p,kind:m,cwd:f,launch:b}=await jn(t,{validateKind:Se});_e(e,f),t.worktree!==void 0&&_e(e,T(t.pin_cwd??t.cwd??f));const v={...t,kind:m},_=d===void 0?void 0:ut(d,f);if(await x(we(b),{cwd:f,profileId:p},n.modelRegistry),!await st(p))throw new u(412,"no_provider_credential",he,{error:"no_provider_credential",message:he,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let L=null;{const A=o===void 0||o.nodeId===null||o.state==="warm_claimed"?mt(v,f,p):null,j=l===null&&r.beforeBrokerLaunch===void 0?void 0:S=>{l!==null&&$n(S,"terminal",l),r.beforeBrokerLaunch?.(S)};if(o?.state==="warm_claimed"&&o.nodeId!==null){const S=A===null?null:await Dn(A,o.nodeId,j);if(S===null)throw ne(o.requestKey,o.nodeId),new u(503,"create_resume_failed",`could not resume warm claim ${o.nodeId}; retry the create`);return te(o.requestKey,S),{status:201,body:g(S)}}if(A!==null){const S=await Pn(A,{...s===void 0?{}:{deadlineAt:s},..._===void 0?{}:{outcomeDelivery:_},...o===void 0?{}:{requestKey:o.requestKey}},j);if(S!==null)return o!==void 0&&te(o.requestKey,S),ce(A),{status:201,body:g(S)};L=A}const F=o?.nodeId??t.node_id??(o===void 0?void 0:ee());o!==void 0&&o.nodeId===null&&Fe(o.requestKey,F);const I=pt(F===void 0?v:{...v,node_id:F},i,f);c!==null&&(c.rootLifecycle!==void 0&&(I.rootLifecycle=c.rootLifecycle),c.scopes!==void 0&&v.scopes===void 0&&(I.scopes=c.scopes),c.run!==void 0&&(I.run=c.run),c.withinCreate!==void 0&&(I.withinCreate=c.withinCreate)),s!==void 0&&(I.deadlineAt=s),_!==void 0&&(I.outcomeDelivery=_),I.readiness=t.root===!0?"await":"launch";const Q=await Pe(I,j,()=>{L!==null&&ce(L)});return o!==void 0&&je(o.requestKey,Q.node.node_id),{status:201,body:g(Q.node.node_id)}}}a(D,"handleCreateRequest");function k(e,t){const n=e.query.getAll(t);if(n.length>1)throw h(`${t} must appear at most once`);return n[0]}a(k,"singleQueryValue");function ge(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw h(`${t} must be true or false`)}}a(ge,"optionalBoolean");function M(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw h(`${t} must be one of: ${n.join(", ")}`)}}a(M,"oneOf");function _t(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[b]of e.query)if(!t.has(b))throw h(`unknown nodes query parameter: ${b}`);const n=M(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=M(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),o=k(e,"kind"),s=M(k(e,"mode"),"mode",["base","orchestrator"]),d=k(e,"profile_id"),c=k(e,"profile_prefix"),i=k(e,"parent"),l=ge(k(e,"top_level"),"top_level"),p=k(e,"under"),m=ge(k(e,"hanging"),"hanging"),f=M(k(e,"include"),"include",["activity"]);if(i!==void 0&&l===!0)throw h("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...r!==void 0?{lifecycle:r}:{},...o!==void 0?{kind:o}:{},...s!==void 0?{mode:s}:{},...d!==void 0?{profile_id:d}:{},...c!==void 0?{profile_prefix:c}:{},...i!==void 0?{parent:i}:{},...l!==void 0?{top_level:l}:{},...p!==void 0?{under:p}:{},...m!==void 0?{hanging:m}:{},...f!==void 0?{include:f}:{}}}a(_t,"parseListQuery");function gt(e){const t=_t(e);let n=t.status!==void 0?re({status:t.status}):re();if(e.principal.class!=="person"&&(n=n.filter(d=>me(e.principal,d.grantee??"app:terminal",d.node_id))),t.lifecycle!==void 0&&(n=n.filter(d=>d.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(d=>d.kind===t.kind)),t.mode!==void 0&&(n=n.filter(d=>d.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(d=>d.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(d=>d.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(d=>d.parent===t.parent)),t.top_level===!0&&(n=n.filter(d=>d.parent===null)),t.under!==void 0){const d=new Set(Ke(t.under));n=n.filter(c=>d.has(c.node_id))}t.hanging===!0&&(n=n.filter(d=>d.parent!==null&&R(d.parent)===null));const r=t.include==="activity"?Qe(n.map(d=>d.node_id)):null,o=n.length>0?Oe():new Set;return{status:200,body:n.map(d=>{const c=Jn(d,d.profile_id!==null&&o.has(d.profile_id));if(r!==null){const i=fe(d.node_id);c.activity={latest_report:i[0]??null,final_report:d.final_report===null?null:i.find(l=>l.name===d.final_report)??null,pending_human_count:r[d.node_id]??0}}return c})}}a(gt,"handleList");async function bt(e){const t=e.params.id,n=await Qn(e,t,{method:"GET",path:`/v1/nodes/${encodeURIComponent(t)}`,query:Xn(e)});if(n.kind==="unknown")throw qn(t,n.unreachable);if(n.kind==="remote"){if(n.status>=400)throw Zn(n.status,n.body);return{status:n.status,body:et(n.body,n.machine)}}return w(t),{status:200,body:g(t)}}a(bt,"handleDetail");async function vt(e){const t=e.params.id;w(t);const n=await sn(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.turnReplies===void 0?{}:{turnReplies:n.snapshot.turnReplies},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(o=>({name:o.name,description:o.description,source:o.source})),captured_at:B()}}}a(vt,"handleSnapshot");async function kt(e){const t=e.params.id,n=ln(t);if(n===null)throw P(`unknown node: ${t}`,{received:t});return{status:200,body:n}}a(kt,"handleSubject");function St(e){for(const[s]of e.query)if(s!=="cursor"&&s!=="limit")throw h(`unknown messages query parameter: ${s}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw h("cursor must appear at most once");if(n.length>1)throw h("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const r=n[0],o=Number(r);if(!Number.isSafeInteger(o)||r==="")throw h("limit must be an integer from 1 through 500");return t.length===0?{limit:o}:{cursor:t[0],limit:o}}a(St,"parseMessagesQuery");async function Rt(e){const t=e.params.id,n=await rn(t,St(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:B()}}}a(Rt,"handleMessages");function It(e){const t=e.params.id;w(t);const n=dn(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:B()}}}a(It,"handleSession");async function Ot(e){const t=e.params.id;return w(t),{status:200,body:{node_id:t,markdown:await an(t)}}}a(Ot,"handleTranscript");function At(e){const t=e.params.id;w(t);const n=a((o,s)=>({node_id:o,label:R(o)?.name??o,dir:de(o),self:s,files:at(o)}),"root"),r=[n(t,!0),...ie(t).map(o=>n(o.node_id,!1))].filter(o=>$t(o.node_id,o.dir)||o.files>0);return{status:200,body:{node_id:t,roots:r}}}a(At,"handleContext");function $t(e,t){try{return en(W(e),t)}catch(n){if(tn(n))return!1;throw n}}a($t,"hasDir");async function Ct(e){const t=w(e.params.id),n=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=n===null?void 0:t.scopes==null?[...n]:[...new Set([...t.scopes.filter(s=>O(n,s)),...n.filter(s=>O(t.scopes,s))])],o=await Te(t.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:g(o.node.node_id)}}a(Ct,"handleFork");const Nt=1e4;async function Tt(e){const t=e.params.id;w(t);const n=e.body,r=n?.resume??!0,o=n?.reopen??!1;hn(t,o);const s=!r&&n?.cron_id!==void 0?ue(n.cron_id):null,d=await Ne(t,{resume:r,capacity:"refuse",...s!==null?{wakeReason:Kn(s,"schedule_revive")}:{}});d.outcome!=="already-live"&&Ge(t,{failures:0,notBefore:null});const c=R(t)?.status??"active",i=(d.launch??E().get(t)?.handle)?.exited,l=d.outcome!=="frozen"&&await ae(t,i,Nt);return{status:200,body:Un(t,d,c,l)}}a(Tt,"handleRevive");async function Et(e){const t=e.params.id;return{status:200,body:{newNodeId:(await mn(t))?.newNodeId??null}}}a(Et,"handleRelaunchRoot");function Pt(e){const t=e.params.id;w(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw h("caller_pid must be a positive integer when provided");const r=Wn(),o=Ce(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:zn(o)}}a(Pt,"handleClose");function Dt(e){if(!Yn(e.principal))throw new u(403,"permission_error","only the person marks a conversation read");const t=e.params.id;return w(t),We(t),{status:204}}a(Dt,"handleMarkRead");async function Mt(e){const t=e.params.id;w(t);const n=await pn(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}a(Mt,"handleRecycle");async function Lt(e){const t=e.params.id;return w(t),await V(t,{lifecycle:"terminal"}),$(e,t,["lifecycle"]),{status:200,body:g(t)}}a(Lt,"handleDemote");async function jt(e,t={}){const n=e.params.id,r=w(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await ye(r,{kind:o.kind??r.kind,mode:"orchestrator",lifecycle:o.resident===!0?"resident":r.lifecycle,model:o.model},t.modelRegistry);const s=await fn(n,{...o.kind!==void 0?{kind:o.kind}:{},...o.resident===!0?{resident:!0}:{},...o.model!==void 0?{model:o.model}:{}});$(e,n,["mode",...o.kind!==void 0?["kind"]:[],...o.resident===!0?["lifecycle"]:[],...o.model!==void 0?["model"]:[]]);const d=J(s.meta,Y(n));return d.roadmap_written=s.roadmapWritten,d.roadmap_ref=s.roadmapRef,d.goal_path=s.goalPath,{status:200,body:d}}a(jt,"handlePromote");async function Ft(e,t={}){const n=e.params.id,r=w(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await ye(r,{kind:o.kind??r.kind,mode:o.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:o.model},t.modelRegistry);const s=o.note??"Refresh: continue against your roadmap or goal.";wn(n,s);const d=await un(n,{...o.promote===!0?{promote:!0}:{},...o.kind!==void 0?{kind:o.kind}:{},...o.model!==void 0?{model:o.model}:{}});return{status:200,body:J(d.meta,Y(n))}}a(Ft,"handleYield");function Gt(e){const t=e.params.id;w(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw h("a wait requires a controller node id");const r=R(n.controller);if(r===null)throw P(`unknown controller: ${n.controller}`,{received:n.controller});if(r.status!=="active"&&r.status!=="idle")throw new u(422,"unprocessable",`controller ${n.controller} is ${r.status}`);return xe(t,n.controller),{status:200,body:g(t)}}a(Gt,"handleWait");async function Bt(e){const t=e.principal,n=await cn(t.class==="broker"?o=>o.grantee===t.app&&U(t,o.node_id,o.grantee):void 0);return{status:200,body:{revived:[...n.revived],failed:[...n.failed],frozen:[...n.frozen]}}}a(Bt,"handleReviveAll");const xt=new Set(["interrupt","steer","after-turn","next-turn"]);function Kt(e){if(e===null)return null;const t=a(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return t("listen must be an object or null");const n=Object.entries(e);if(n.length===0)return t("listen must name at least one level");for(const[r,o]of n)/^(?:[1-9]|10)$/.test(r)||t(`listen level must be 1..10: ${r}`),(typeof o!="string"||!xt.has(o))&&t(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(o)}`);return JSON.stringify(Object.fromEntries(n))}a(Kt,"listenJson");function $(e,t,n,r){n.length===0&&r===void 0||K(o=>{if(r?.(o),n.length===0)return;const s=Ve(o,t),d=Ue(o,e),c=d.class==="person"?d.person:d.class==="app"?d.app:d.node;ze(o,c,s),Je(o,{event:"configured",object:s,actor:c,attrs:{changed:n.join(",")}})})}a($,"recordConfigured");function be(e){const t=E().get(e);if(t===void 0)return!1;try{return process.kill(t.pid,"SIGTERM"),!0}catch{return!1}}a(be,"restartLiveBroker");function ve(e,t){try{return Z(e)===Z(t)}catch{return!1}}a(ve,"sameDirectory");async function Wt(e,t={}){const n=e.params.id,r=e.body;let o;if(r===void 0)o={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))o=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(o.profile!==void 0){if(typeof o.profile!="string"||o.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:o.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(o).some(m=>m!=="profile"&&m!=="restart"&&o[m]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const i=w(n),l=Gn(e,o.profile);Bn(l.profileId);const p=xn(l.profileId).manifest.grantee??"app:terminal";if(p!==(i.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${p}, node ${n} to ${i.grantee}`,received:o.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(i.profile_id??null)!==l.profileId&&(Ln(i.kind)?(await z(i.kind,i.cwd,l.profileId),await V(n,{profileId:l.profileId})):C(n,{profile_id:l.profileId}),$(e,n,["profile"])),o.restart===!0&&be(n),{status:200,body:g(n)}}if(Object.prototype.hasOwnProperty.call(o,"cwd")){const i=o.cwd;if(typeof i!="string"||i==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:i,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(o).some(f=>f!=="cwd"&&f!=="keep_session"&&f!=="restart"&&o[f]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:o,field:"cwd",next:"Send cwd as the only config field."});const l=w(n),p=N(l.cwd);if(o.keep_session===!0||p&&G(i)&&N(i)&&ve(l.cwd,i)){if(!G(i))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const f=T(i);let b=!1;try{b=q(f).isDirectory()}catch{}if(!b)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${f}`,received:i,field:"cwd",next:"Send an existing absolute directory."});if(p&&!ve(l.cwd,f))throw new y({error:"cwd_not_same_directory",message:`${f} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:i,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot relocate its cwd`,received:i,field:"cwd",next:"Reconcile the managed worktree first."});const v=l.cwd;return v!==f&&(K(_=>{C(n,{cwd:f}),X(_,"UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(f,n,v),Ye(n,v,f)}),$(e,n,["cwd"])),o.restart===!0&&be(n),{status:200,body:g(n)}}if(E().has(n)){const f=`${n} cannot repair its cwd while its broker is live`;throw new u(409,"cwd_node_live",f,{error:"cwd_node_live",message:f,received:i,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:i,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:i,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(N(l.cwd))throw new y({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:i,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!G(i))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const m=T(i);if(!N(m))throw new y({error:"cwd_missing",message:`cwd does not exist: ${m}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!q(m).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${m}`,received:i,field:"cwd",next:"Send an existing absolute directory."})}catch(f){throw f instanceof y?f:new y({error:"cwd_missing",message:`cwd does not exist: ${m}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return K(()=>{C(n,{cwd:m}),He(n)}),$(e,n,["cwd"]),{status:200,body:g(n)}}let s=w(n);const d=o.listen===void 0?void 0:Kt(o.listen);if(o.scopes!==void 0){const i=pe(o.scopes),l=s.grantee==="app:terminal"?ot():s.grant_id?tt(s.grant_id):null,p=s.grantee==="app:terminal"&&!dt("user").runtime?.issuer;if(!i.every(m=>O(s.scopes,m)&&(l?O(l.resolved,m):p)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:i,field:"scopes",next:"Send only scopes the node currently holds."});if(i.includes("crtr:act")&&!O(i,"crtr:llm"))throw new u(400,"invalid_scope","crtr:act requires crtr:llm");s=C(n,{scopes:i})}if(o.situational_context!==void 0&&Ae(n,$e(o.situational_context)),o.model!==void 0){const i=(await se(s.cwd,s.profile_id??null)).modelLadders,l=kn(o.model,i),p=rt(s.grant_id,o.model,l===void 0),m=p?{family:it,strength:p.strength}:l,f=p?p.model:Sn(o.model,i);await x({kind:"concrete",spec:f},{cwd:s.cwd,profileId:s.profile_id??null},t.modelRegistry);const b=E();let v=!1;if(b.isClaimed(n)&&await ae(n,b.get(n)?.handle.exited)&&(v=await On(n,f,m).then(()=>!0,_=>{if(_ instanceof An)return!1;throw _})),!v){if(b.isClaimed(n)){const _=`${n}'s broker did not accept the model switch; the model was not changed`;throw new u(409,"broker_not_ready",_,{error:"broker_not_ready",message:_,received:o.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!f.includes("/"))throw h(`model must resolve to a provider/id spec: ${o.model}`);In(n,f,m)}s=w(n)}if(o.kind!==void 0||o.mode!==void 0||o.lifecycle!==void 0){o.kind!==void 0&&await Se(o.kind);const i=o.kind??s.kind,l=o.mode??s.mode,p=o.lifecycle??s.lifecycle;let m;l==="orchestrator"&&!gn(n)&&(m=a(()=>{const f=yn(n);_n(n,f!==null&&f.trim()!==""?{goal:f.trim()}:{})},"beforePersist")),s=await V(n,{...o.kind!==void 0?{kind:i}:{},...o.mode!==void 0?{mode:l}:{},...o.lifecycle!==void 0?{lifecycle:p}:{}},m)}o.name!==void 0&&(s=C(n,{name:o.name}),s.window&&bn(s.window,Fn(s)));const c=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(i=>o[i]!==void 0);return $(e,n,c,d===void 0?void 0:i=>{X(i,"UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(d,n)}),{status:200,body:g(n)}}a(Wt,"handleConfig");async function ke(){return(await se(process.cwd(),Ie()||null)).kinds}a(ke,"daemonKinds");async function Se(e){const t=Object.keys(await ke());if(!t.includes(e))throw h(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}a(Se,"assertKindServer");async function Vt(){const e=await ke();return{status:200,body:{kinds:Object.keys(e).sort().map(n=>({kind:n,when_to_use:e[n]?.whenToUse??null,available_to:e[n]?.availableTo??null}))}}}a(Vt,"handleListKinds");const cr=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:wt},{method:"GET",pattern:"/v1/nodes",handler:gt},{method:"GET",pattern:"/v1/kinds",handler:a(()=>Vt(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:Bt},{method:"GET",pattern:"/v1/nodes/:id",handler:bt},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:vt},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:kt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:Rt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:It},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:Ot},{method:"GET",pattern:"/v1/nodes/:id/context",handler:At},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Ct},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Tt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:Et},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Pt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:Dt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Mt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Lt},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:jt},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Ft},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Gt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:Wt}];export{Wt as handleConfig,wt as handleCreate,Ct as handleFork,gt as handleList,jt as handlePromote,Ft as handleYield,cr as nodeRoutes,pr as resolveCreateKind};
1
+ var Oe=Object.defineProperty;var a=(e,t)=>Oe(e,"name",{value:t,configurable:!0});import{prepared as Z}from"../../../core/sqlite-statements.js";import{envProfileId as Ie}from"../../../shared/env.js";import{pausedCanvasProfiles as Ae}from"../../../core/profiles/manifest.js";import{existsSync as N,realpathSync as q,statSync as ee}from"node:fs";import{isAbsolute as F,resolve as T}from"node:path";import{appendSituationalContext as $e,formatSituationalProse as Ce}from"../../../core/runtime/situational-context.js";import{closeNode as Ne}from"../../../core/runtime/close.js";import{reviveNode as Te}from"../../../core/runtime/revive.js";import{nowIso as B}from"../../../core/fs-utils.js";import{appPaidLaunch as Ee,assertLaunchModelRegistered as K,forkNode as Pe,resolveForkSource as De,spawnChildPrepared as Le}from"../../../core/runtime/spawn.js";import{forkSourceNode as Me,newNodeId as ne}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as te,childrenOf as je,completeCreateRequest as oe,findCreateRequest as Ge,getNode as R,recordCreateRequestNode as Fe,reserveCreateRequest as re,reserveCreateRequestNode as Be,listNodes as ie,recordRespawnAttempt as Ke,subscribersOf as We,subscriptionsOf as de,setMessageWait as xe,updateNode as C}from"../../../core/canvas/canvas.js";import{subtreeIds as Ve}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as W}from"../../../core/canvas/db.js";import{markNodeRead as ze}from"../../../core/canvas/recovery.js";import{nodeObject as Je}from"../../../core/graph/objects.js";import{recordActedOn as Ue}from"../../../core/graph/edges.js";import{publish as Ye}from"../../../core/graph/events.js";import{readerFor as He}from"../reader.js";import{relocateSessionCwd as Qe,unbindSession as Xe}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as Ze}from"../../../core/canvas/attention.js";import{isSafeNodeId as qe}from"../../../core/canvas/paths.js";import{contextDir as se,nodeAgentDir as x}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as en}from"../../cron/authority.js";import{cronBirthPlacement as nn}from"../../cron/armed-context.js";import{existsBeneath as tn,isAbsentOrRefused as on,isBeneathRefusal as rn,readdirBeneath as dn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as sn,readNodeSession as an,readNodeSnapshot as ln,transcriptMarkdown as cn}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as fn}from"../../../core/substrate/subject.js";import{reviveAll as un}from"../../../core/runtime/revive-all.js";import{promoteAsync as pn,requestYieldAsync as mn,reshapeNodeAsync as V}from"../../../core/runtime/promote.js";import{recycleNode as hn}from"../../../core/runtime/recycle.js";import{relaunchRoot as wn}from"../../../core/runtime/reset.js";import{assertReopenGate as yn}from"../../../core/runtime/reopen.js";import{writeYieldMessage as _n,readGoal as gn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as bn,hasRoadmap as vn}from"../../../core/runtime/roadmap.js";import{renameWindow as kn}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as Sn,explicitModelIntent as Rn,normalizeModel as On,readMergedLaunchConfigAsync as ae}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as In}from"../../../core/model-routes.js";import{persistDormantModel as An,setModelLive as $n}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as le}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as Cn}from"../../../core/runtime/broker-request.js";import{boundFleet as E}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as Nn}from"../../structured-requests/sidecar.js";import{assertOutputSchemaAccepted as Tn}from"../../../core/runtime/structured-output.js";import{OUTCOME_PAYLOAD_MAX_BYTES as ce}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as En}from"../../../core/human/action-binding.js";import{resolveHumanAction as Pn}from"../../../core/human-actions.js";import{parseDurationMs as Dn}from"../../../core/wake.js";import{claimWarmNode as Ln,refillWarmPool as fe,resumeWarmClaim as Mn,warmPoolEnabled as jn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as z,isLaunchKind as Gn,resolveLaunchTarget as Fn}from"../../../core/runtime/launch-target.js";import{fullName as Bn}from"../../../core/canvas/labels.js";import{reportsForNode as ue}from"./reports.js";import{requireUsableProfile as Kn}from"./profiles.js";import{assertProfileActive as Wn,loadExactProfileManifest as xn}from"../../../core/profiles/manifest.js";import{getCron as pe}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Vn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as zn}from"../../control.js";import{notFound as P,usage as h}from"../../../core/errors.js";import{assertScope as Jn,validateScopes as me}from"../../../core/scopes.js";import{scopeAllowed as I}from"../../../shared/env.js";import{toCloseResultDTO as Un,toNodeDetailDTO as J,toNodeSummaryDTO as Yn,toReviveResultDTO as Hn}from"../map.js";import{ApiError as u}from"../../../api/index.js";import{InputError as y}from"../../../core/io.js";import{actsAsPerson as Qn,brokerMayReach as U,canReadNode as he,resolvedScopes as Xn}from"../router.js";import{forwardVerb as Zn,queryWithoutMachine as qn,relayError as et,unknownError as nt,withMachine as tt}from"../../peer/forward.js";import{fileRoot as ot}from"../../../core/spaces/file-root.js";import{activeGrant as rt,payerOfGrant as it,terminalGrant as dt}from"../../../core/grants/mirror.js";import{appRungForGrant as st}from"../../../core/llm/app-rungs.js";import{APP_FAMILY as at}from"../../../core/model-routes.js";import{readConfig as lt}from"../../../core/config.js";import{hasConfiguredProviderCredential as ct,NO_PROVIDER_CREDENTIAL_MESSAGE as we}from"../../../core/runtime/provider-credential-gate.js";function w(e){const t=R(e);if(t===null)throw P(`unknown node: ${e}`,{received:e});return t}a(w,"requireMeta");function Y(e){return{subscribesTo:de(e),subscribers:We(e),children:je(e)}}a(Y,"edgesFor");function g(e){const t=w(e);return J(t,Y(e))}a(g,"detailOf");function ft(e){let t=ue(e).length;try{t+=dn(x(e),se(e)).length}catch(n){if(!on(n))throw n}return t}a(ft,"countFiles");function ut(e){if(typeof e!="object"||e===null)throw h("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw h("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw h("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw h("creator must be a non-empty node id when provided");if(t.scopes!==void 0&&me(t.scopes),t.isolated!==void 0&&typeof t.isolated!="boolean")throw new u(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw h("root_lifecycle must be 'resident' or 'terminal'");if(t.request_key!==void 0&&(typeof t.request_key!="string"||t.request_key.trim()===""||t.request_key.length>128))throw h("request_key must be a non-empty string of at most 128 characters when provided");return t}a(ut,"parseCreateBody");function pt(e){if(e===void 0)return;const t=Dn(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new u(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}a(pt,"parseDeadline");function mt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new u(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!En.test(e.action))throw new u(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new u(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new u(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>ce)throw new u(413,"payload_too_large",`serialized payload exceeds ${ce} bytes`)}return e}}a(mt,"parseOutcomeDelivery");function ht(e,t){const n=Pn(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new u(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new u(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}a(ht,"resolveOutcomeDelivery");function wt(e,t,n){const r={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),t!==void 0&&(r.parent=t),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=T(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}a(wt,"buildRecipe");function yt(e,t,n){return!jn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}a(yt,"warmRequestFor");import{resolveCreateKind as wr}from"../../../core/runtime/launch-target.js";function ye(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return In(e.model,t,e.modelExact===!0)}a(ye,"requestFromLaunch");function _t(e,t){if(t===null)return e;if(e.scopes===void 0)return{...e,scopes:[...t]};const n=e.scopes.filter(r=>!I(t,r));if(n.length===0)return e;throw new u(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${n.join(", ")}`,{scopes:n,ceiling:t})}a(_t,"withinCeiling");async function _e(e,t,n){const r=(await Sn(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await K(ye(r),{cwd:e.cwd,profileId:e.profile_id??null},n)}a(_e,"assertNodeModelChangeRegistered");function ge(e,t){const n=e.principal;if(n.class!=="broker"&&n.class!=="cron")return;const r=ot({app:n.app,resolved:Xn(n),launched:n.scopes},t,"read");if("root"in r)return;const o="missing"in r?r.missing:null;throw new u(403,"scope_missing",o?`the child's directory ${t} needs missing scope ${o}`:`no permission of this run names the child's directory ${t}`,void 0,void 0,o?{scope:o}:void 0)}a(ge,"assertCallerReaches");const H=new Map;async function gt(e,t={},n={}){const r=_t(ut(e.body),e.ceiling);if(e.principal.class==="broker"){const c=e.principal;if(r.prefer_warm===!0&&c.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const i=w(r.parent);if(i.grantee!==c.app)throw new u(403,"other_app_run","cannot create a child under another app's node");if(!U(c,r.parent,i.grantee??"app:terminal"))throw P(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==c.node)throw new u(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let i=null;try{i=Me(De(r.fork_from))}catch{}if(i?.grantee!==c.app||!U(c,i.node_id,i.grantee))throw new u(403,"other_app_run","cannot fork another app's conversation")}r.creator=c.node}if(e.principal.class==="cron"){const c=e.principal;for(const l of["parent","creator","fork_from","node_id"])if(r[l]!=null)throw new u(403,"permission_error",`a cron cannot set ${l} on a node it starts`);r.prefer_warm=!1;const i=en({grantee:c.app,sub:c.sub,grant_id:c.grant,scopes:c.scopes});if(!i.allowed)throw new u(i.reason==="scope_missing"?403:401,i.reason==="scope_missing"?"scope_missing":"grant_revoked",i.message);if(r.scopes!==void 0){const l=r.scopes.find(p=>!I(i.effectiveScopes,p)||!I(c.scopes,p));if(l!==void 0)throw new u(403,"scope_missing",`scope ${l} is not held by this cron`,void 0,void 0,{scope:l})}else c.scopes!==null&&(r.scopes=[...c.scopes]);r.node_id=ne(),c.isolated&&(r.isolated=!0,r.cwd=x(r.node_id,c.app))}r.creator!==void 0&&Jn(w(r.creator),"crtr:act");const o=r.request_key?.trim();if(o===void 0||r.node_id!==void 0&&qe(r.node_id)&&R(r.node_id)!==null&&Ge(o)?.nodeId!==r.node_id)return D(e,r,t,n);const s=H.get(o);if(s!==void 0)return s;const d=bt(e,r,o,t,n);H.set(o,d);try{return await d}finally{H.delete(o)}}a(gt,"handleCreate");async function bt(e,t,n,r,o){const s=re(n);if(s.nodeId!==null&&R(s.nodeId)!==null){if(s.state!=="warm_claimed"){const d=R(s.nodeId);if(e.principal.class!=="person"&&!he(e.principal,d.grantee??"app:terminal",s.nodeId))throw new u(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:g(s.nodeId)}}return D(e,t,r,o,s)}try{return await D(e,t,r,o,s)}catch(d){const c=re(n);throw(c.nodeId===null||R(c.nodeId)===null)&&te(n,c.nodeId),d}}a(bt,"handleKeyedCreateRequest");async function D(e,t,n,r,o=void 0){const s=r.deadlineAt??pt(t.deadline),d=mt(t.outcome_delivery),c=e.principal.class==="cron"?nn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:pe(e.principal.cron)?.created_by??null},t.node_id):null;c!==null&&(t.root=c.root===!0);const i=c?.parent??t.parent??void 0;if(i==null&&t.root!==!0)throw h("a node create requires a parent (or root: true for an independent root)");let l=null;if(t.output_schema!==void 0){try{l=JSON.parse(t.output_schema)}catch{throw h("output_schema must be a JSON schema string")}if(l===null||typeof l!="object"||Array.isArray(l))throw h("output_schema must be a JSON schema object");await Tn(l)}const{profileId:p,kind:m,cwd:f,launch:b}=await Fn(t,{validateKind:Re});ge(e,f),t.worktree!==void 0&&ge(e,T(t.pin_cwd??t.cwd??f));const v={...t,kind:m},_=d===void 0?void 0:ht(d,f),Q=("grant"in e.principal?e.principal.grant:null)??(i==null?null:R(i)?.grant_id??null);if(await K(ye(Ee(b,Q,t.model)),{cwd:f,profileId:p},n.modelRegistry),it(Q)!=="app"&&!await ct(p))throw new u(412,"no_provider_credential",we,{error:"no_provider_credential",message:we,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let M=null;{const A=o===void 0||o.nodeId===null||o.state==="warm_claimed"?yt(v,f,p):null,j=l===null&&r.beforeBrokerLaunch===void 0?void 0:S=>{l!==null&&Nn(S,"terminal",l),r.beforeBrokerLaunch?.(S)};if(o?.state==="warm_claimed"&&o.nodeId!==null){const S=A===null?null:await Mn(A,o.nodeId,j);if(S===null)throw te(o.requestKey,o.nodeId),new u(503,"create_resume_failed",`could not resume warm claim ${o.nodeId}; retry the create`);return oe(o.requestKey,S),{status:201,body:g(S)}}if(A!==null){const S=await Ln(A,{...s===void 0?{}:{deadlineAt:s},..._===void 0?{}:{outcomeDelivery:_},...o===void 0?{}:{requestKey:o.requestKey}},j);if(S!==null)return o!==void 0&&oe(o.requestKey,S),fe(A),{status:201,body:g(S)};M=A}const G=o?.nodeId??t.node_id??(o===void 0?void 0:ne());o!==void 0&&o.nodeId===null&&Be(o.requestKey,G);const O=wt(G===void 0?v:{...v,node_id:G},i,f);c!==null&&(c.rootLifecycle!==void 0&&(O.rootLifecycle=c.rootLifecycle),c.scopes!==void 0&&v.scopes===void 0&&(O.scopes=c.scopes),c.run!==void 0&&(O.run=c.run),c.withinCreate!==void 0&&(O.withinCreate=c.withinCreate)),s!==void 0&&(O.deadlineAt=s),_!==void 0&&(O.outcomeDelivery=_),O.readiness=t.root===!0?"await":"launch";const X=await Le(O,j,()=>{M!==null&&fe(M)});return o!==void 0&&Fe(o.requestKey,X.node.node_id),{status:201,body:g(X.node.node_id)}}}a(D,"handleCreateRequest");function k(e,t){const n=e.query.getAll(t);if(n.length>1)throw h(`${t} must appear at most once`);return n[0]}a(k,"singleQueryValue");function be(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw h(`${t} must be true or false`)}}a(be,"optionalBoolean");function L(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw h(`${t} must be one of: ${n.join(", ")}`)}}a(L,"oneOf");function vt(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[b]of e.query)if(!t.has(b))throw h(`unknown nodes query parameter: ${b}`);const n=L(k(e,"status"),"status",["active","idle","done","dead","canceled"]),r=L(k(e,"lifecycle"),"lifecycle",["terminal","resident"]),o=k(e,"kind"),s=L(k(e,"mode"),"mode",["base","orchestrator"]),d=k(e,"profile_id"),c=k(e,"profile_prefix"),i=k(e,"parent"),l=be(k(e,"top_level"),"top_level"),p=k(e,"under"),m=be(k(e,"hanging"),"hanging"),f=L(k(e,"include"),"include",["activity"]);if(i!==void 0&&l===!0)throw h("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...r!==void 0?{lifecycle:r}:{},...o!==void 0?{kind:o}:{},...s!==void 0?{mode:s}:{},...d!==void 0?{profile_id:d}:{},...c!==void 0?{profile_prefix:c}:{},...i!==void 0?{parent:i}:{},...l!==void 0?{top_level:l}:{},...p!==void 0?{under:p}:{},...m!==void 0?{hanging:m}:{},...f!==void 0?{include:f}:{}}}a(vt,"parseListQuery");function kt(e){const t=vt(e);let n=t.status!==void 0?ie({status:t.status}):ie();if(e.principal.class!=="person"&&(n=n.filter(d=>he(e.principal,d.grantee??"app:terminal",d.node_id))),t.lifecycle!==void 0&&(n=n.filter(d=>d.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(d=>d.kind===t.kind)),t.mode!==void 0&&(n=n.filter(d=>d.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(d=>d.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(d=>d.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(d=>d.parent===t.parent)),t.top_level===!0&&(n=n.filter(d=>d.parent===null)),t.under!==void 0){const d=new Set(Ve(t.under));n=n.filter(c=>d.has(c.node_id))}t.hanging===!0&&(n=n.filter(d=>d.parent!==null&&R(d.parent)===null));const r=t.include==="activity"?Ze(n.map(d=>d.node_id)):null,o=n.length>0?Ae():new Set;return{status:200,body:n.map(d=>{const c=Yn(d,d.profile_id!==null&&o.has(d.profile_id));if(r!==null){const i=ue(d.node_id);c.activity={latest_report:i[0]??null,final_report:d.final_report===null?null:i.find(l=>l.name===d.final_report)??null,pending_human_count:r[d.node_id]??0}}return c})}}a(kt,"handleList");async function St(e){const t=e.params.id,n=await Zn(e,t,{method:"GET",path:`/v1/nodes/${encodeURIComponent(t)}`,query:qn(e)});if(n.kind==="unknown")throw nt(t,n.unreachable);if(n.kind==="remote"){if(n.status>=400)throw et(n.status,n.body);return{status:n.status,body:tt(n.body,n.machine)}}return w(t),{status:200,body:g(t)}}a(St,"handleDetail");async function Rt(e){const t=e.params.id;w(t);const n=await ln(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.turnReplies===void 0?{}:{turnReplies:n.snapshot.turnReplies},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(o=>({name:o.name,description:o.description,source:o.source})),captured_at:B()}}}a(Rt,"handleSnapshot");async function Ot(e){const t=e.params.id,n=fn(t);if(n===null)throw P(`unknown node: ${t}`,{received:t});return{status:200,body:n}}a(Ot,"handleSubject");function It(e){for(const[s]of e.query)if(s!=="cursor"&&s!=="limit")throw h(`unknown messages query parameter: ${s}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw h("cursor must appear at most once");if(n.length>1)throw h("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const r=n[0],o=Number(r);if(!Number.isSafeInteger(o)||r==="")throw h("limit must be an integer from 1 through 500");return t.length===0?{limit:o}:{cursor:t[0],limit:o}}a(It,"parseMessagesQuery");async function At(e){const t=e.params.id,n=await sn(t,It(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:B()}}}a(At,"handleMessages");function $t(e){const t=e.params.id;w(t);const n=an(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:B()}}}a($t,"handleSession");async function Ct(e){const t=e.params.id;return w(t),{status:200,body:{node_id:t,markdown:await cn(t)}}}a(Ct,"handleTranscript");function Nt(e){const t=e.params.id;w(t);const n=a((o,s)=>({node_id:o,label:R(o)?.name??o,dir:se(o),self:s,files:ft(o)}),"root"),r=[n(t,!0),...de(t).map(o=>n(o.node_id,!1))].filter(o=>Tt(o.node_id,o.dir)||o.files>0);return{status:200,body:{node_id:t,roots:r}}}a(Nt,"handleContext");function Tt(e,t){try{return tn(x(e),t)}catch(n){if(rn(n))return!1;throw n}}a(Tt,"hasDir");async function Et(e){const t=w(e.params.id),n=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=n===null?void 0:t.scopes==null?[...n]:[...new Set([...t.scopes.filter(s=>I(n,s)),...n.filter(s=>I(t.scopes,s))])],o=await Pe(t.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:g(o.node.node_id)}}a(Et,"handleFork");const Pt=1e4;async function Dt(e){const t=e.params.id;w(t);const n=e.body,r=n?.resume??!0,o=n?.reopen??!1;yn(t,o);const s=!r&&n?.cron_id!==void 0?pe(n.cron_id):null,d=await Te(t,{resume:r,capacity:"refuse",...s!==null?{wakeReason:Vn(s,"schedule_revive")}:{}});d.outcome!=="already-live"&&Ke(t,{failures:0,notBefore:null});const c=R(t)?.status??"active",i=(d.launch??E().get(t)?.handle)?.exited,l=d.outcome!=="frozen"&&await le(t,i,Pt);return{status:200,body:Hn(t,d,c,l)}}a(Dt,"handleRevive");async function Lt(e){const t=e.params.id;return{status:200,body:{newNodeId:(await wn(t))?.newNodeId??null}}}a(Lt,"handleRelaunchRoot");function Mt(e){const t=e.params.id;w(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw h("caller_pid must be a positive integer when provided");const r=zn(),o=Ne(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Un(o)}}a(Mt,"handleClose");function jt(e){if(!Qn(e.principal))throw new u(403,"permission_error","only the person marks a conversation read");const t=e.params.id;return w(t),ze(t),{status:204}}a(jt,"handleMarkRead");async function Gt(e){const t=e.params.id;w(t);const n=await hn(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}a(Gt,"handleRecycle");async function Ft(e){const t=e.params.id;return w(t),await V(t,{lifecycle:"terminal"}),$(e,t,["lifecycle"]),{status:200,body:g(t)}}a(Ft,"handleDemote");async function Bt(e,t={}){const n=e.params.id,r=w(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await _e(r,{kind:o.kind??r.kind,mode:"orchestrator",lifecycle:o.resident===!0?"resident":r.lifecycle,model:o.model},t.modelRegistry);const s=await pn(n,{...o.kind!==void 0?{kind:o.kind}:{},...o.resident===!0?{resident:!0}:{},...o.model!==void 0?{model:o.model}:{}});$(e,n,["mode",...o.kind!==void 0?["kind"]:[],...o.resident===!0?["lifecycle"]:[],...o.model!==void 0?["model"]:[]]);const d=J(s.meta,Y(n));return d.roadmap_written=s.roadmapWritten,d.roadmap_ref=s.roadmapRef,d.goal_path=s.goalPath,{status:200,body:d}}a(Bt,"handlePromote");async function Kt(e,t={}){const n=e.params.id,r=w(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await _e(r,{kind:o.kind??r.kind,mode:o.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:o.model},t.modelRegistry);const s=o.note??"Refresh: continue against your roadmap or goal.";_n(n,s);const d=await mn(n,{...o.promote===!0?{promote:!0}:{},...o.kind!==void 0?{kind:o.kind}:{},...o.model!==void 0?{model:o.model}:{}});return{status:200,body:J(d.meta,Y(n))}}a(Kt,"handleYield");function Wt(e){const t=e.params.id;w(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw h("a wait requires a controller node id");const r=R(n.controller);if(r===null)throw P(`unknown controller: ${n.controller}`,{received:n.controller});if(r.status!=="active"&&r.status!=="idle")throw new u(422,"unprocessable",`controller ${n.controller} is ${r.status}`);return xe(t,n.controller),{status:200,body:g(t)}}a(Wt,"handleWait");async function xt(e){const t=e.principal,n=await un(t.class==="broker"?o=>o.grantee===t.app&&U(t,o.node_id,o.grantee):void 0);return{status:200,body:{revived:[...n.revived],failed:[...n.failed],frozen:[...n.frozen]}}}a(xt,"handleReviveAll");const Vt=new Set(["interrupt","steer","after-turn","next-turn"]);function zt(e){if(e===null)return null;const t=a(r=>{throw new y({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return t("listen must be an object or null");const n=Object.entries(e);if(n.length===0)return t("listen must name at least one level");for(const[r,o]of n)/^(?:[1-9]|10)$/.test(r)||t(`listen level must be 1..10: ${r}`),(typeof o!="string"||!Vt.has(o))&&t(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(o)}`);return JSON.stringify(Object.fromEntries(n))}a(zt,"listenJson");function $(e,t,n,r){n.length===0&&r===void 0||W(o=>{if(r?.(o),n.length===0)return;const s=Je(o,t),d=He(o,e),c=d.class==="person"?d.person:d.class==="app"?d.app:d.node;Ue(o,c,s),Ye(o,{event:"configured",object:s,actor:c,attrs:{changed:n.join(",")}})})}a($,"recordConfigured");function ve(e){const t=E().get(e);if(t===void 0)return!1;try{return process.kill(t.pid,"SIGTERM"),!0}catch{return!1}}a(ve,"restartLiveBroker");function ke(e,t){try{return q(e)===q(t)}catch{return!1}}a(ke,"sameDirectory");async function Jt(e,t={}){const n=e.params.id,r=e.body;let o;if(r===void 0)o={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))o=r;else throw new y({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(o.profile!==void 0){if(typeof o.profile!="string"||o.profile==="")throw new y({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:o.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(o).some(m=>m!=="profile"&&m!=="restart"&&o[m]!==void 0))throw new y({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const i=w(n),l=Kn(e,o.profile);Wn(l.profileId);const p=xn(l.profileId).manifest.grantee??"app:terminal";if(p!==(i.grantee??"app:terminal"))throw new y({error:"profile_grantee_mismatch",message:`profile ${l.profileId} belongs to ${p}, node ${n} to ${i.grantee}`,received:o.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(i.profile_id??null)!==l.profileId&&(Gn(i.kind)?(await z(i.kind,i.cwd,l.profileId),await V(n,{profileId:l.profileId})):C(n,{profile_id:l.profileId}),$(e,n,["profile"])),o.restart===!0&&ve(n),{status:200,body:g(n)}}if(Object.prototype.hasOwnProperty.call(o,"cwd")){const i=o.cwd;if(typeof i!="string"||i==="")throw new y({error:"cwd_invalid",message:"cwd must be a non-empty string",received:i,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(o).some(f=>f!=="cwd"&&f!=="keep_session"&&f!=="restart"&&o[f]!==void 0))throw new y({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:o,field:"cwd",next:"Send cwd as the only config field."});const l=w(n),p=N(l.cwd);if(o.keep_session===!0||p&&F(i)&&N(i)&&ke(l.cwd,i)){if(!F(i))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const f=T(i);let b=!1;try{b=ee(f).isDirectory()}catch{}if(!b)throw new y({error:"cwd_missing",message:`cwd is not an existing directory: ${f}`,received:i,field:"cwd",next:"Send an existing absolute directory."});if(p&&!ke(l.cwd,f))throw new y({error:"cwd_not_same_directory",message:`${f} is not the same directory as the recorded ${l.cwd}; --keep-session only relocates an alias`,received:i,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot relocate its cwd`,received:i,field:"cwd",next:"Reconcile the managed worktree first."});const v=l.cwd;return v!==f&&(W(_=>{C(n,{cwd:f}),Z(_,"UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(f,n,v),Qe(n,v,f)}),$(e,n,["cwd"])),o.restart===!0&&ve(n),{status:200,body:g(n)}}if(E().has(n)){const f=`${n} cannot repair its cwd while its broker is live`;throw new u(409,"cwd_node_live",f,{error:"cwd_node_live",message:f,received:i,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(l.fork_from!=null)throw new y({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${l.cwd}`,received:i,field:"cwd",next:`Restore ${l.cwd}, then revive the fork normally.`});if(l.managed_worktree?.state==="open")throw new y({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:i,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(N(l.cwd))throw new y({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${l.cwd}; cwd repair is not a relocation command`,received:i,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!F(i))throw new y({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const m=T(i);if(!N(m))throw new y({error:"cwd_missing",message:`cwd does not exist: ${m}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!ee(m).isDirectory())throw new y({error:"cwd_not_a_directory",message:`cwd is not a directory: ${m}`,received:i,field:"cwd",next:"Send an existing absolute directory."})}catch(f){throw f instanceof y?f:new y({error:"cwd_missing",message:`cwd does not exist: ${m}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return W(()=>{C(n,{cwd:m}),Xe(n)}),$(e,n,["cwd"]),{status:200,body:g(n)}}let s=w(n);const d=o.listen===void 0?void 0:zt(o.listen);if(o.scopes!==void 0){const i=me(o.scopes),l=s.grantee==="app:terminal"?dt():s.grant_id?rt(s.grant_id):null,p=s.grantee==="app:terminal"&&!lt("user").runtime?.issuer;if(!i.every(m=>I(s.scopes,m)&&(l?I(l.resolved,m):p)))throw new y({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:i,field:"scopes",next:"Send only scopes the node currently holds."});if(i.includes("crtr:act")&&!I(i,"crtr:llm"))throw new u(400,"invalid_scope","crtr:act requires crtr:llm");s=C(n,{scopes:i})}if(o.situational_context!==void 0&&$e(n,Ce(o.situational_context)),o.model!==void 0){const i=(await ae(s.cwd,s.profile_id??null)).modelLadders,l=Rn(o.model,i),p=st(s.grant_id,o.model,l===void 0),m=p?{family:at,strength:p.strength}:l,f=p?p.model:On(o.model,i);await K({kind:"concrete",spec:f},{cwd:s.cwd,profileId:s.profile_id??null},t.modelRegistry);const b=E();let v=!1;if(b.isClaimed(n)&&await le(n,b.get(n)?.handle.exited)&&(v=await $n(n,f,m).then(()=>!0,_=>{if(_ instanceof Cn)return!1;throw _})),!v){if(b.isClaimed(n)){const _=`${n}'s broker did not accept the model switch; the model was not changed`;throw new u(409,"broker_not_ready",_,{error:"broker_not_ready",message:_,received:o.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!f.includes("/"))throw h(`model must resolve to a provider/id spec: ${o.model}`);An(n,f,m)}s=w(n)}if(o.kind!==void 0||o.mode!==void 0||o.lifecycle!==void 0){o.kind!==void 0&&await Re(o.kind);const i=o.kind??s.kind,l=o.mode??s.mode,p=o.lifecycle??s.lifecycle;let m;l==="orchestrator"&&!vn(n)&&(m=a(()=>{const f=gn(n);bn(n,f!==null&&f.trim()!==""?{goal:f.trim()}:{})},"beforePersist")),s=await V(n,{...o.kind!==void 0?{kind:i}:{},...o.mode!==void 0?{mode:l}:{},...o.lifecycle!==void 0?{lifecycle:p}:{}},m)}o.name!==void 0&&(s=C(n,{name:o.name}),s.window&&kn(s.window,Bn(s)));const c=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(i=>o[i]!==void 0);return $(e,n,c,d===void 0?void 0:i=>{Z(i,"UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(d,n)}),{status:200,body:g(n)}}a(Jt,"handleConfig");async function Se(){return(await ae(process.cwd(),Ie()||null)).kinds}a(Se,"daemonKinds");async function Re(e){const t=Object.keys(await Se());if(!t.includes(e))throw h(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}a(Re,"assertKindServer");async function Ut(){const e=await Se();return{status:200,body:{kinds:Object.keys(e).sort().map(n=>({kind:n,when_to_use:e[n]?.whenToUse??null,available_to:e[n]?.availableTo??null}))}}}a(Ut,"handleListKinds");const pr=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:gt},{method:"GET",pattern:"/v1/nodes",handler:kt},{method:"GET",pattern:"/v1/kinds",handler:a(()=>Ut(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:xt},{method:"GET",pattern:"/v1/nodes/:id",handler:St},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:Rt},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:Ot},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:At},{method:"GET",pattern:"/v1/nodes/:id/session",handler:$t},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:Ct},{method:"GET",pattern:"/v1/nodes/:id/context",handler:Nt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Et},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Dt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:Lt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:Mt},{method:"POST",pattern:"/v1/nodes/:id/read",handler:jt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Gt},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Ft},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Bt},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Kt},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Wt},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:Jt}];export{Jt as handleConfig,gt as handleCreate,Et as handleFork,kt as handleList,Bt as handlePromote,Kt as handleYield,pr as nodeRoutes,wr as resolveCreateKind};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.505",
3
+ "version": "0.3.506",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  "license": "UNLICENSED",
140
140
  "dependencies": {
141
- "@north-light/identity": "0.3.505",
141
+ "@north-light/identity": "0.3.506",
142
142
  "@earendil-works/pi-agent-core": "1.1.0",
143
143
  "@earendil-works/pi-ai": "1.1.0",
144
144
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.505",
3
+ "version": "0.3.506",
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.505",
3
+ "version": "0.3.506",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.505",
9
+ "version": "0.3.506",
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.505",
21
+ "@north-light/identity": "0.3.506",
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.505",
12119
+ "version": "0.3.506",
12120
12120
  "license": "UNLICENSED"
12121
12121
  },
12122
12122
  "packages/crouter-env-docker": {
12123
12123
  "name": "@north-light/env-docker",
12124
- "version": "0.3.505",
12124
+ "version": "0.3.506",
12125
12125
  "license": "UNLICENSED"
12126
12126
  },
12127
12127
  "packages/crouter-identity": {
12128
12128
  "name": "@north-light/identity",
12129
- "version": "0.3.505",
12129
+ "version": "0.3.506",
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.505",
12137
+ "version": "0.3.506",
12138
12138
  "license": "UNLICENSED",
12139
12139
  "dependencies": {
12140
- "@north-light/api": "0.3.505",
12141
- "@north-light/identity": "0.3.505"
12140
+ "@north-light/api": "0.3.506",
12141
+ "@north-light/identity": "0.3.506"
12142
12142
  }
12143
12143
  },
12144
12144
  "packages/crouter-sdk": {
12145
12145
  "name": "@north-light/sdk",
12146
- "version": "0.3.505",
12146
+ "version": "0.3.506",
12147
12147
  "license": "UNLICENSED",
12148
12148
  "dependencies": {
12149
- "@north-light/api": "0.3.505",
12150
- "@north-light/identity": "0.3.505",
12149
+ "@north-light/api": "0.3.506",
12150
+ "@north-light/identity": "0.3.506",
12151
12151
  "jose": "^6.2.1"
12152
12152
  },
12153
12153
  "bin": {