@code-yeongyu/senpi 2026.10.7 → 2026.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/bundle/chunks/{anthropic-messages-4MNFPQ66.js → anthropic-messages-CVXI6CLT.js} +1 -1
  3. package/dist/bundle/chunks/{app-server-command-SO5RJ2N7.js → app-server-command-2HNDZGTR.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-BE66QJ3Z.js → chunk-3YXB7Z7O.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-JJNIU2A2.js → chunk-CB77NQMN.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-EUU6W5B3.js → chunk-DERNLWDS.js} +43 -43
  7. package/dist/bundle/chunks/{chunk-K4AZKFRB.js → chunk-J5MUMVWB.js} +2 -2
  8. package/dist/bundle/chunks/{chunk-D2W3MXRF.js → chunk-LSE7KE2C.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-V2VQ4BHG.js → chunk-M2IHGL3M.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-7SMFF2QJ.js → chunk-M3BQ2PAQ.js} +4 -4
  11. package/dist/bundle/chunks/{chunk-HY4AOLON.js → chunk-MJGHZT4N.js} +3 -3
  12. package/dist/bundle/chunks/{chunk-7A3WRAKP.js → chunk-Q2ZTPMWD.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-ESSQUSRC.js → chunk-SB22X6ZR.js} +1 -1
  14. package/dist/bundle/chunks/{cli-main-XBQN73O2.js → cli-main-VMDAGZCA.js} +1 -1
  15. package/dist/bundle/chunks/{help-fast-path-FUMH5NSA.js → help-fast-path-JBQLYO7W.js} +1 -1
  16. package/dist/bundle/chunks/{host-command-YXQAXNKK.js → host-command-HTYYQBSG.js} +1 -1
  17. package/dist/bundle/chunks/{host-lifecycle-L4XQIATP.js → host-lifecycle-XZF6IKKO.js} +1 -1
  18. package/dist/bundle/chunks/host-lifecycle.js +3 -3
  19. package/dist/bundle/chunks/{interactive-mode-ROO5W56P.js → interactive-mode-U7IH4VMJ.js} +1 -1
  20. package/dist/bundle/chunks/{list-tips-JQDZPB6C.js → list-tips-IIRFXBTO.js} +1 -1
  21. package/dist/bundle/chunks/{multi-session-host-5WTKAQJM.js → multi-session-host-HHIC6N7C.js} +1 -1
  22. package/dist/bundle/chunks/{package-manager-cli-NCD5FQGV.js → package-manager-cli-2FXWPM2U.js} +1 -1
  23. package/dist/bundle/chunks/{rotation-stream-7E37KOCX.js → rotation-stream-ZJQ6I2RZ.js} +1 -1
  24. package/dist/bundle/chunks/{rpc-mode-MWURKCP2.js → rpc-mode-K5YGBGQO.js} +1 -1
  25. package/dist/bundle/chunks/{schedule-command-UTXB465F.js → schedule-command-CVAPK2WQ.js} +1 -1
  26. package/dist/bundle/chunks/{sdk-EO76I33H.js → sdk-U52J75K2.js} +50 -50
  27. package/dist/bundle/chunks/{session-control-endpoint-J6RHZXWB.js → session-control-endpoint-THEF3K7M.js} +1 -1
  28. package/dist/bundle/chunks/{session-picker-VTTRFGE7.js → session-picker-R5N2EKUS.js} +1 -1
  29. package/dist/bundle/chunks/session-worker.js +104 -104
  30. package/dist/bundle/cli.js +1 -1
  31. package/dist/bundle/index.js +1 -1
  32. package/dist/bundle/rpc-entry.js +1 -1
  33. package/dist/bundle/runtime-manifest.json +1 -1
  34. package/dist/core/agent-session.d.ts +7 -2
  35. package/dist/core/agent-session.js +31 -5
  36. package/dist/core/continue-from-leaf.d.ts +21 -0
  37. package/dist/core/continue-from-leaf.js +39 -0
  38. package/dist/core/dynamic-prompt/handoff.js +3 -3
  39. package/dist/core/dynamic-prompt/intent-gate.js +1 -1
  40. package/dist/core/dynamic-prompt/style.js +1 -1
  41. package/dist/core/extensions/builtin/permission-system/index.js +4 -0
  42. package/dist/core/extensions/builtin/permission-system/prompt.js +10 -2
  43. package/dist/core/extensions/builtin/permission-system/types.d.ts +3 -1
  44. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +2 -2
  45. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +2 -2
  46. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.js +2 -2
  47. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +2 -2
  48. package/dist/core/extensions/builtin/prompt-preset/claude-sonnet-5-5.js +2 -2
  49. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +3 -3
  50. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +3 -3
  51. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +2 -2
  52. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +4 -4
  53. package/dist/core/extensions/builtin/prompt-preset/gpt-surface.js +2 -2
  54. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +2 -2
  55. package/dist/core/extensions/builtin/prompt-preset/grok-4.6.js +1 -1
  56. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js +1 -1
  57. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +2 -2
  58. package/dist/core/extensions/types.d.ts +4 -0
  59. package/dist/modes/rpc/connection-handler.js +11 -2
  60. package/dist/modes/rpc/host-lifecycle.js +5 -28
  61. package/dist/modes/rpc/host-run-activity.d.ts +13 -0
  62. package/dist/modes/rpc/host-run-activity.js +39 -0
  63. package/dist/modes/rpc/rpc-types.d.ts +5 -0
  64. package/docs/rpc.md +13 -0
  65. package/package.json +7 -7
@@ -8,7 +8,7 @@ import{HOST_INSTANCE_ID_ENV}from"./chunk-CIRZTP7W.js";import{HOST_DAEMON_DIR_ENV
8
8
  `,{mode:CRASH_RECORD_FILE_MODE}),pruneHostCrashRecords(daemonDir)}catch{}}function readHostCrashRecords(daemonDir){let raw;try{raw=readFileSync2(hostCrashRecordFile(daemonDir),"utf8")}catch{return[]}let records=[];for(let line of raw.split(`
9
9
  `))if(line.trim()!=="")try{let value=JSON.parse(line);typeof value=="object"&&value!==null&&typeof Reflect.get(value,"at")=="string"&&records.push(value)}catch{}return records}function pruneHostCrashRecords(daemonDir){let records=readHostCrashRecords(daemonDir);if(records.length<=HOST_CRASH_RECORD_LIMIT)return;let kept=records.slice(records.length-HOST_CRASH_RECORD_LIMIT);writeFileSync2(hostCrashRecordFile(daemonDir),`${kept.map(r=>JSON.stringify(r)).join(`
10
10
  `)}
11
- `,{mode:CRASH_RECORD_FILE_MODE})}function classifyChildExit(code,signal){return code===0&&signal===null?{reason:"rpc host exited on its own idle policy",exitCode:0}:{reason:`rpc host process exited unexpectedly (${code??signal})`,exitCode:1}}function noteChildExit(daemonDir,code,signal,childStartedAt,now=Date.now()){classifyChildExit(code,signal).exitCode!==0&&recordHostCrash(daemonDir,{at:new Date(now).toISOString(),...signal===null?{code:code??void 0}:{signal},uptimeMs:Math.max(0,now-childStartedAt),kind:"rpc-host",detection:"supervisor",...crashingRuntimeVersions()})}var OBSERVE_REQUEST_FIELD="observe",OBSERVING_COMMANDS=new Set(["get_protocol_info","list_sessions"]);function isObservingRequest(line){let request;try{request=JSON.parse(line)}catch{return!1}if(typeof request!="object"||request===null||Array.isArray(request))return!1;let record=request;return record.type==="warm"?!0:record[OBSERVE_REQUEST_FIELD]===!0&&OBSERVING_COMMANDS.has(record.type)}var MAX_CLASSIFIED_LINE_BYTES=64*1024,NEWLINE=10,ClientOccupancy=class{constructor(onAttach){this.clients=new Set,this.observers=new Set,this.attached=new Set,this.onAttach=onAttach}get attachedCount(){return this.attached.size}get unclassifiedCount(){return this.clients.size-this.observers.size-this.attached.size}admit(client){this.clients.add(client);let pending=Buffer.alloc(0),attach=()=>{client.off("data",classify),pending=Buffer.alloc(0),this.observers.delete(client),this.attached.add(client),this.onAttach()},classify=chunk=>{pending=Buffer.concat([pending,chunk]);for(let newline=pending.indexOf(NEWLINE);newline!==-1;newline=pending.indexOf(NEWLINE)){let line=pending.subarray(0,newline).toString("utf8");if(pending=pending.subarray(newline+1),!isObservingRequest(line)){attach();return}this.observers.add(client)}pending.length>MAX_CLASSIFIED_LINE_BYTES&&attach()};client.on("data",classify)}release(client){this.clients.delete(client),this.observers.delete(client),this.attached.delete(client)}destroyAll(){for(let client of this.clients)client.destroy()}};function rpcHostExecArgv(execArgv=process.execArgv,bun=process.versions.bun!==void 0){let args=[];for(let index=0;index<execArgv.length;index++){let arg=execArgv[index];if(bun){if(arg==="-e"||arg==="--eval"||arg==="-p"||arg==="--print"||arg==="-pe"){index++;continue}if(arg.startsWith("-e")||arg.startsWith("-p"))continue}if(arg==="-e"||arg==="--eval"||arg==="-pe"||arg==="--input-type"||arg==="--input_type"){index++;continue}if(arg==="-p"||arg==="--print"){execArgv[index+1]!==void 0&&!execArgv[index+1].startsWith("-")&&index++;continue}arg==="-i"||arg==="--interactive"||arg.startsWith("--interactive=")||arg.startsWith("--eval=")||arg.startsWith("--print=")||arg.startsWith("--input-type=")||arg.startsWith("--input_type=")||args.push(arg)}return args}var HOST_COLD_START_ENV="SENPI_RPC_HOST_COLD_START",HOST_IDLE_EXIT_MS_ENV="SENPI_RPC_HOST_IDLE_EXIT_MS",DEFAULT_HOST_IDLE_EXIT_MS=9e5,HANDOFF_GRACE_MS_ENV="SENPI_RPC_HANDOFF_GRACE_MS",DEFAULT_HANDOFF_GRACE_MS=6e5;function parseColdStart(value){return value==="transient"||value==="persistent"?value:void 0}function parseIdleExitMs(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isFinite(parsed)&&parsed>0?parsed:void 0}function resolveHostPolicy(settings,env){let record=isRecord(settings)?settings:{},coldStart=parseColdStart(env[HOST_COLD_START_ENV])??parseColdStart(asOptionalString(record.coldStart))??"transient",idleExitMs=parseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV])??parseIdleExitMs(asOptionalString(record.idleExitMs))??9e5;return{coldStart,idleExitMs}}var IdleExitDecider=class{constructor(idleExitMs,now=Date.now){this.idleExitMs=idleExitMs,this.now=now}update(activity){return activity.connections>0||activity.activeTurns>0?(this.idleSince=void 0,"active"):this.idleExitMs===Number.POSITIVE_INFINITY?"idle":this.idleSince===void 0?(this.idleSince=this.now(),"idle"):this.now()-this.idleSince>=this.idleExitMs?"exit":"idle"}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function asOptionalString(value){return typeof value=="string"?value:typeof value=="number"?String(value):void 0}function hostCrashCleanupPaths(targets){let publicEntry=targets.platform==="win32"?[targets.publicSocket]:[];return targets.successor?publicEntry:[targets.generationPidFile,targets.settingsFile,...publicEntry,targets.pointerFile]}var SUPERSESSION_POLL_MS=1e3,ABSENT_CONFIRMATIONS=3;function watchForSupersession(endpoint,onLost){if(endpoint.identity===void 0||process.platform==="win32")return()=>{};let absentPolls=0,lost=!1,lose=loss=>{lost||(lost=!0,stop(),onLost(loss))},timer=setInterval(()=>{endpoint.settled?.()!==!0&&classifyEndpointOwnership(endpoint.path,endpoint.identity).then(ownership=>{if(endpoint.settled?.()!==!0)switch(ownership){case"replaced":lose("replaced");return;case"absent":if(absentPolls+=1,absentPolls<ABSENT_CONFIRMATIONS)return;lose("absent");return;case"held":case"unknown":absentPolls=0;return}},ignore)},SUPERSESSION_POLL_MS);timer.unref?.();let stop=()=>clearInterval(timer);return stop}function ignore(){}import{rmSync as rmSync2}from"node:fs";import{rm}from"node:fs/promises";import{Socket}from"node:net";var HOST_WATCH_FD_ENV="SENPI_RPC_HOST_WATCH_FD",HOST_SCRATCH_DIR_ENV="SENPI_RPC_HOST_SCRATCH_DIR",HOST_PUBLIC_SOCKET_ENV="SENPI_RPC_HOST_PUBLIC_SOCKET",HOST_WATCH_PPID_ENV="SENPI_RPC_HOST_WATCH_PPID",HOST_WATCH_PPID_INTERVAL_MS=250,HOST_CLEANUP_PATHS_ENV="SENPI_RPC_HOST_CLEANUP_PATHS";function parsePositiveInteger(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isSafeInteger(parsed)&&parsed>0?parsed:void 0}function readHostWatchdogConfig(env=process.env){let fd=parsePositiveInteger(env[HOST_WATCH_FD_ENV]),ppid=parsePositiveInteger(env[HOST_WATCH_PPID_ENV]);if(fd===void 0&&ppid===void 0)return;let scratchDir=env[HOST_SCRATCH_DIR_ENV],cleanupPaths=env[HOST_CLEANUP_PATHS_ENV]?.split(`
12
- `).filter(Boolean),publicSocket=env[HOST_PUBLIC_SOCKET_ENV];return{fd,ppid,scratchDir:scratchDir===void 0||scratchDir===""?void 0:scratchDir,cleanupPaths,publicSocket:publicSocket===""?void 0:publicSocket}}function readHostWatchdogConfigFromBrandEnv(){return readHostWatchdogConfig({[HOST_WATCH_FD_ENV]:process.env[HOST_WATCH_FD_ENV]??envValue("RPC_HOST_WATCH_FD"),[HOST_WATCH_PPID_ENV]:process.env[HOST_WATCH_PPID_ENV]??envValue("RPC_HOST_WATCH_PPID"),[HOST_SCRATCH_DIR_ENV]:process.env[HOST_SCRATCH_DIR_ENV]??envValue("RPC_HOST_SCRATCH_DIR"),[HOST_PUBLIC_SOCKET_ENV]:process.env[HOST_PUBLIC_SOCKET_ENV]??envValue("RPC_HOST_PUBLIC_SOCKET"),[HOST_CLEANUP_PATHS_ENV]:process.env[HOST_CLEANUP_PATHS_ENV]??envValue("RPC_HOST_CLEANUP_PATHS")})}function armHostWatchdog(config,onSupervisorGone){if(!config)return()=>{};let fire=reason=>{disarm();let captured=captureBeforeCleanup(config);if(process.platform==="win32"){let cleanup=captured.then(()=>cleanupWatchdogPaths(config));onSupervisorGone(reason,cleanup)}else captured.then(()=>cleanupWatchdogPaths(config)).finally(()=>onSupervisorGone(reason))},disarmers=[],disarm=()=>{for(let stop of disarmers.splice(0))stop()};return config.fd!==void 0&&disarmers.push(watchFdForEof(config.fd,fire)),config.ppid!==void 0&&disarmers.push(watchPpid(config.ppid,fire)),disarm}function watchFdForEof(fd,fire){let stream,streamFailed=!1,fired=!1,fireOnce=reason=>{fired||(fired=!0,fire(reason))};try{stream=new Socket({fd,readable:!0,writable:!1})}catch{return()=>{}}stream.resume();let onEnd=()=>fireOnce(`supervisor pipe fd ${fd} closed`),onClose=()=>{streamFailed||onEnd()},onError=()=>{streamFailed=!0};return stream.once("end",onEnd),process.platform==="win32"&&stream.once("close",onClose),stream.once("error",onError),()=>{stream.off("end",onEnd),stream.off("close",onClose),stream.off("error",onError),stream.destroy()}}function watchPpid(supervisorPid,fire){if(supervisorPid===process.pid)return()=>{};let timer=setInterval(()=>{if(!processAlive(supervisorPid)){fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`);return}process.ppid!==supervisorPid&&fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`)},HOST_WATCH_PPID_INTERVAL_MS);return timer.unref?.(),()=>clearInterval(timer)}function processAlive(pid){try{return process.kill(pid,0),!0}catch(cause){return cause instanceof Error&&"code"in cause&&cause.code!=="ESRCH"}}function captureBeforeCleanup(config){return config.beforeCleanup===void 0?Promise.resolve():Promise.resolve().then(config.beforeCleanup).catch(()=>{})}async function cleanupWatchdogPaths(config){let paths=[...config.cleanupPaths??[],...config.scratchDir?[config.scratchDir]:[]];for(let path of paths)try{process.platform==="win32"?rmSync2(path,{recursive:!0,force:!0,maxRetries:10,retryDelay:100}):await rm(path,{recursive:!0,force:!0})}catch{}}function activeTurnsForIdleDecision(input){return input.healthy?input.observedBusy:input.unhealthySince===void 0||input.now-input.unhealthySince<input.unknownGraceMs?1:0}function createObserverLink(options){let current,healthy=!1,unhealthySince,retry,armRetry=()=>{retry!==void 0||options.settled()||(retry=options.setTimer(()=>{retry=void 0,open().catch(armRetry)},options.retryDelayMs))};async function open(){let socket=await options.open();current=socket,healthy=!0,unhealthySince=void 0,socket.onLost(()=>{current!==socket||options.settled()||(healthy=!1,unhealthySince??=options.now(),current=void 0,armRetry())})}return{open,healthy:()=>healthy,unhealthySince:()=>unhealthySince,stop:()=>{retry?.cancel(),retry=void 0,current=void 0}}}var CHILD_STOP_TIMEOUT_MS=5e3,WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS=2e3,CHILD_WATCH_FD=3;async function createInternalSocketPath(baseDir=tmpdir(),platform=process.platform){if(platform==="win32"){let dir2=join3(baseDir,`internal-${randomUUID()}`);return await mkdir(dir2,{recursive:!0,mode:448}),{socket:`\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,dir:dir2,secretPath:join3(dir2,"secret")}}let dir=join3(tmpdir(),`senpi-rpc-host-internal-${randomUUID().slice(0,8)}`);return await mkdir(dir,{recursive:!1,mode:448}),await writeFile(join3(dir,".owner"),JSON.stringify({pid:process.pid,processStartTime:await readProcessStartTime(process.pid),createdAt:Date.now()}),{mode:384}),{socket:join3(dir,"host.sock"),dir,secretPath:join3(dir,".secret")}}var INTERNAL_SUPERVISOR_FLAG="--internal-rpc-host-supervisor",INJECTABLE_PREFIX_FLAGS=new Set(["--extension"]);function findInternalSupervisorArgs(argv){for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg===INTERNAL_SUPERVISOR_FLAG)return argv.slice(index+1);if(!INJECTABLE_PREFIX_FLAGS.has(arg)||index+1>=argv.length)return;index++}}function parseSupervisorArgs(argv){let hostArgs=[],socket,childCommand,childArgs,agentDir,bindSocket,replaceIdentity;for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg==="--socket"&&index+1<argv.length){socket=argv[++index];continue}if(arg==="--child-command"&&index+1<argv.length){childCommand=argv[++index];continue}if(arg==="--child-args"&&index+1<argv.length){try{let parsed=JSON.parse(argv[++index]);Array.isArray(parsed)&&parsed.every(value=>typeof value=="string")&&(childArgs=parsed)}catch{return}continue}if(arg==="--agent-dir"&&index+1<argv.length){agentDir=argv[++index];continue}if(arg==="--bind"&&index+1<argv.length){bindSocket=argv[++index];continue}if(arg==="--replace"&&index+1<argv.length){replaceIdentity=parseSocketIdentity(argv[++index]);continue}hostArgs.push(arg)}return socket===void 0?void 0:{socket,hostArgs,childCommand,childArgs,agentDir,bindSocket,replaceIdentity}}function parseSocketIdentity(value){let match=/^(\d+):(\d+)$/.exec(value);return match?{dev:Number(match[1]),ino:Number(match[2])}:void 0}function resolveCliMainPath(modulePath=fileURLToPath(import.meta.url),bundled=isBundledNode){let declared=bundled?resolveDeclaredCliEntry(modulePath):void 0;if(declared!==void 0)return declared;let extension=modulePath.endsWith(".ts")?".ts":".js",unbundled=resolve(dirname(modulePath),"..","..",`cli-main${extension}`);return existsSync(unbundled)?unbundled:resolveDeclaredCliEntry(modulePath)??unbundled}function resolveDeclaredCliEntry(modulePath){let dir=dirname(modulePath);for(let depth=0;depth<8;depth+=1){let manifestPath=resolve(dir,"package.json");if(existsSync(manifestPath)){try{let declared=JSON.parse(readFileSync3(manifestPath,"utf8")).bin,candidates=typeof declared=="string"?[declared]:Object.values(declared??{});for(let candidate of candidates){let entry=resolve(dir,candidate);if(existsSync(entry))return entry}}catch{}return}let parent=dirname(dir);if(parent===dir)return;dir=parent}}function resolveHostChildLaunch(launch,internalSocket,compiled=isBunBinary){return launch.childCommand?{command:launch.childCommand,args:[...launch.childArgs??[],"--listen",`unix://${internalSocket}`]}:{command:process.execPath,args:[...compiled?[]:[...rpcHostExecArgv(),resolveCliMainPath()],"--mode","rpc","--multi-session","--listen",`unix://${internalSocket}`,...launch.hostArgs]}}function quoteWindowsShellArg(value){return`"${value.replace(/(\\*)"/g,'$1$1\\"').replace(/(\\*)$/,"$1$1").replace(/([()%!^"<>&|;,])/g,"^$1")}"`}function spawnableChildLaunch(launch,platform=process.platform){let extension=extname(launch.command).toLowerCase();return platform!=="win32"||extension!==".cmd"&&extension!==".bat"?{...launch,shell:!1}:{command:quoteWindowsShellArg(launch.command),args:launch.args.map(quoteWindowsShellArg),shell:!0}}async function runHostSupervisor(launch){let paths=createHostDaemonPaths({socket:launch.socket,agentDir:launch.agentDir??getAgentDir()}),told=process.env[HOST_INSTANCE_ID_ENV],instanceId=told!==void 0&&told.trim()!==""?told:randomUUID(),generation=generationPaths(paths,instanceId),policy=resolveHostPolicy(await readSettingsFile(paths.settingsFile),process.env),publicSocket=launch.socket,bindSocket=launch.bindSocket??publicSocket,successor=launch.bindSocket!==void 0,publicSecret=process.platform==="win32"?await ensurePublicSocketSecret(publicSocket):void 0,internal=await createInternalSocketPath(paths.dir),internalSocket=internal.socket,internalSecretPath=internal.secretPath??socketSecretPath(internalSocket),internalSecret=process.platform==="win32"?await createSocketSecret(internalSecretPath):void 0,clients=new ClientOccupancy(()=>decider.update(currentActivity())),busySessions=new Map,observerSocket,observerLink=createObserverLink({open:async()=>{let secret=internalSecret,next=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,secret));return secret&&sendSocketHandshake(next,secret),await waitForConnect(next,5e3),observerSocket=next,attachJsonlLineReader(next,observeHostEvent,{maxLineLength:MAX_RPC_LINE_CHARACTERS}),{onLost:handler=>{next.once("close",handler),next.once("error",handler)}}},settled:()=>shuttingDown,retryDelayMs:250,now:Date.now,setTimer:(run,ms)=>{let timer=setTimeout(run,ms);return timer.unref?.(),{cancel:()=>clearTimeout(timer)}}}),childExitWatchTimer,stopSupersessionWatch,shuttingDown=!1,draining=!1,endpointReplaced=!1,handoffGraceTimer,shutdownPromise,childLaunch=spawnableChildLaunch(resolveHostChildLaunch(launch,internalSocket)),child=spawn(childLaunch.command,childLaunch.args,{env:{...process.env,...launch.agentDir?{SENPI_CODING_AGENT_DIR:launch.agentDir}:{},[HOST_DAEMON_DIR_ENV]:paths.dir,[HOST_INSTANCE_ID_ENV]:instanceId,[HOST_WATCH_FD_ENV]:String(CHILD_WATCH_FD),[HOST_WATCH_PPID_ENV]:String(process.pid),...internal.dir?{[HOST_SCRATCH_DIR_ENV]:internal.dir}:{},...internalSecret?{[SOCKET_SECRET_FILE_ENV]:internalSecretPath}:{},[HOST_CLEANUP_PATHS_ENV]:hostCrashCleanupPaths({pointerFile:paths.pointerFile,generationPidFile:generation.pidFile,settingsFile:paths.settingsFile,publicSocket,successor:!!successor,platform:process.platform}).join(`
13
- `),...process.platform==="win32"?{}:{[HOST_PUBLIC_SOCKET_ENV]:publicSocket}},shell:childLaunch.shell,stdio:["ignore","ignore","inherit","pipe"],windowsHide:!0}),childStartedAt=Date.now();child.stdio[CHILD_WATCH_FD]?.on("error",()=>{}),child.once("exit",(code,signal)=>{if(shuttingDown)return;let{reason,exitCode}=classifyChildExit(code,signal);noteChildExit(paths.dir,code,signal,childStartedAt),shutdown(reason,exitCode)});let server=createServer(client=>{let accept=()=>{if(shuttingDown||draining){client.destroy();return}let internal2=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,internalSecret));internalSecret&&sendSocketHandshake(internal2,internalSecret),clients.admit(client);let detach=()=>{clients.release(client),decider.update(currentActivity()),internal2.destroy(),client.destroy()};client.pipe(internal2),internal2.pipe(client),client.once("close",detach),client.once("error",detach),internal2.once("end",()=>client.end(()=>client.destroy())),internal2.once("close",()=>{internal2.readableEnded||detach()}),internal2.once("error",detach)};publicSecret?authenticateSocket(client,publicSecret,accept):accept()});server.once("error",cause=>{shuttingDown||shutdown(`public socket listener failed: ${errorMessage(cause)}`,1)});let decider=new IdleExitDecider(policy.coldStart==="persistent"?Number.POSITIVE_INFINITY:policy.idleExitMs),tickIntervalMs=Math.max(20,Math.min(1e3,policy.idleExitMs/4)),ticker=setInterval(()=>{!draining&&decider.update(currentActivity())==="exit"&&clients.unclassifiedCount===0&&shutdown("idle",0)},tickIntervalMs);function currentActivity(){return{connections:clients.attachedCount,activeTurns:activeTurnsForIdleDecision({healthy:observerLink.healthy(),unhealthySince:observerLink.unhealthySince(),now:Date.now(),unknownGraceMs:decider.idleExitMs,observedBusy:countBusySessions()})}}function countBusySessions(){let busy=0;for(let count of busySessions.values())count>0&&busy++;return busy}function observeHostEvent(line){let event;try{event=JSON.parse(line)}catch{return}if(typeof event!="object"||event===null)return;let{type,sessionId}=event;if(typeof sessionId=="string"){if(type==="agent_start")busySessions.set(sessionId,(busySessions.get(sessionId)??0)+1);else if(type==="agent_settled")busySessions.set(sessionId,Math.max(0,(busySessions.get(sessionId)??1)-1));else return;decider.update(currentActivity())}}async function shutdown(reason,exitCode){return shutdownPromise??=performShutdown(reason,exitCode),shutdownPromise}async function performShutdown(reason,exitCode){shuttingDown&&process.exit(exitCode),shuttingDown=!0,clearInterval(ticker),handoffGraceTimer&&clearTimeout(handoffGraceTimer),childExitWatchTimer&&clearInterval(childExitWatchTimer),stopSupersessionWatch?.();let hardExit=process.platform==="win32"?setTimeout(()=>process.exit(exitCode),WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS):void 0;try{writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`),clients.destroyAll(),draining||await shieldSocketDuringClose(publicSocket,()=>closeServer(server)),internal.dir&&await rm2(internal.dir,{recursive:!0,force:!0}),await stopChild(child),observerLink.stop(),observerSocket?.destroy(),publicSocketOwned&&process.platform!=="win32"&&await unlinkOwnedSocket(publicSocket,publicSocketIdentity,supervisorLog),await releaseGeneration(paths,{instanceId,pid:process.pid,superseded:endpointReplaced})}finally{hardExit&&clearTimeout(hardExit),process.exit(exitCode)}}let publicSocketOwned=!1,publicSocketIdentity;function supervisorLog(message){writeStderrLine(`senpi rpc host supervisor: ${message}`)}function drainForHandoff(){if(draining||shuttingDown)return;draining=!0,supervisorLog("draining into the next generation");let graceMs=parseIdleExitMs(process.env[HANDOFF_GRACE_MS_ENV])??6e5;handoffGraceTimer=setTimeout(()=>{supervisorLog(JSON.stringify({event:"handoff_grace_expired",graceMs})),requestChildDrain()},graceMs),handoffGraceTimer.unref(),requestChildDrain()}function requestChildDrain(){if(child.pid!==void 0&&child.exitCode===null&&child.signalCode===null)try{process.kill(child.pid,"SIGUSR1")}catch(cause){supervisorLog(`could not ask the host to drain: ${errorMessage(cause)}`)}}registerSupervisorSignals(shutdown,drainForHandoff);try{await waitForListener(internalSocket,3e4,internalSecret),await observerLink.open(),await prepareSocketPath(bindSocket),await listen(server,bindSocket,publicSecret),publicSocketOwned=!0,successor&&await adoptPublicSocket(bindSocket,publicSocket,launch.replaceIdentity),publicSocketIdentity=await statSocketIdentity(publicSocket),publicSocketIdentity&&internal.dir&&await writeSocketIdentityFile(join3(internal.dir,PUBLIC_SOCKET_IDENTITY_FILE),publicSocketIdentity),stopSupersessionWatch=watchForSupersession({path:publicSocket,identity:publicSocketIdentity,settled:()=>shuttingDown||draining},loss=>{loss==="replaced"&&(endpointReplaced=!0),supervisorLog(loss==="absent"?"the public socket entry is gone; nothing can reach this generation; draining":"another generation owns the public socket; draining this one"),drainForHandoff()})}catch(cause){await shutdown(`startup failed: ${errorMessage(cause)}`,1)}if(process.platform==="win32"&&child.pid!==void 0){let childStartTime=await readProcessStartTime(child.pid,process.platform,1e3).catch(()=>{}),missingIdentityChecks=0,checkingChildIdentity=!1;childExitWatchTimer=setInterval(()=>{shuttingDown||checkingChildIdentity||child.exitCode!==null||child.signalCode!==null||(checkingChildIdentity=!0,readProcessStartTime(child.pid,process.platform,1e3).then(currentStartTime=>{currentStartTime===void 0&&!processIsLive(child.pid)?missingIdentityChecks++:currentStartTime!==void 0&&(missingIdentityChecks=0),(childStartTime!==void 0&&currentStartTime!==void 0&&currentStartTime!==childStartTime||missingIdentityChecks>=2)&&shutdown("rpc host child exit observed by identity watchdog",0)}).catch(()=>{}).finally(()=>{checkingChildIdentity=!1}))},500),childExitWatchTimer.unref?.()}writeStderrLine(`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${policy.coldStart==="persistent"?"never":String(policy.idleExitMs)})`),await new Promise(()=>{})}function registerSupervisorSignals(shutdown,drain){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{shutdown(`signal:${signal}`,signal==="SIGHUP"?129:143)});process.platform!=="win32"&&process.on("SIGUSR1",drain)}async function adoptPublicSocket(bindSocket,publicSocket,expected){if(expected===void 0)throw new Error(`${publicSocket}: a generation launch must name the entry it replaces`);let current=await statSocketIdentity(publicSocket);if(current===void 0||current.dev!==expected.dev||current.ino!==expected.ino)throw new Error(`${publicSocket}: owned by another socket entry now; refusing to replace it`);await rename(bindSocket,publicSocket)}async function ensurePublicSocketSecret(publicSocket){let secretPath=socketSecretPath(publicSocket);try{return await ensureSocketSecret(secretPath)}catch(cause){throw new Error(`senpi rpc host supervisor: cannot provision public socket secret ${secretPath}`,{cause})}}async function readSettingsFile(settingsFile){try{return JSON.parse(await readFile(settingsFile,"utf8"))}catch{return}}async function stopChild(child){if(!(child.exitCode!==null||child.signalCode!==null)){try{child.kill("SIGTERM")}catch{return}if(!await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS)){try{child.kill("SIGKILL")}catch{return}await waitForChildExit(child,2e3)}}}function waitForChildExit(child,timeoutMs){return child.exitCode!==null||child.signalCode!==null?Promise.resolve(!0):new Promise(resolve2=>{let timer=setTimeout(()=>{child.off("exit",onExit2),resolve2(!1)},timeoutMs),onExit2=()=>{clearTimeout(timer),resolve2(!0)};child.once("exit",onExit2)})}async function waitForListener(socketPath,timeoutMs,secret){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await canConnect(socketPath,secret))return;await delay(50)}throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`)}function canConnect(socketPath,secret){return new Promise(resolve2=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform,secret));secret&&sendSocketHandshake(socket,secret);let settle=value=>{socket.destroy(),resolve2(value)};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1))})}function waitForConnect(socket,timeoutMs){return new Promise((resolve2,reject)=>{let timer=setTimeout(()=>{cleanup(),reject(new Error(`observer connection to internal host timed out after ${timeoutMs}ms`))},timeoutMs),onConnect=()=>{cleanup(),resolve2()},onError=cause=>{cleanup(),reject(cause)},cleanup=()=>{clearTimeout(timer),socket.off("connect",onConnect),socket.off("error",onError)};socket.once("connect",onConnect),socket.once("error",onError)})}async function prepareSocketPath(socketPath){if(process.platform!=="win32"){if(Buffer.byteLength(socketPath)>MAX_SOCKET_PATH_BYTES)throw new Error(`${socketPath}: socket path is ${Buffer.byteLength(socketPath)} bytes, over the ${MAX_SOCKET_PATH_BYTES}-byte limit.`);await mkdir(dirname(socketPath),{recursive:!0,mode:448});try{await access(socketPath)}catch(cause){if(isNodeErrorCode(cause,"ENOENT"))return;throw cause}if(await canConnect(socketPath))throw new Error(`${socketPath}: address already in use by a live server.`);await unlink(socketPath)}}function listen(server,socketPath,secret){return new Promise((resolve2,reject)=>{server.once("error",reject),server.listen({path:resolveSocketTransportAddress(socketPath,process.platform,secret),readableAll:!1,writableAll:!1},async()=>{server.off("error",reject);try{process.platform!=="win32"&&!socketPath.startsWith("\0")&&await chmod(socketPath,384),resolve2()}catch(cause){reject(cause)}})})}function closeServer(server){return new Promise(resolve2=>{server.close(()=>resolve2())})}function writeStderrLine(text){try{writeSync(2,`${text}
11
+ `,{mode:CRASH_RECORD_FILE_MODE})}function classifyChildExit(code,signal){return code===0&&signal===null?{reason:"rpc host exited on its own idle policy",exitCode:0}:{reason:`rpc host process exited unexpectedly (${code??signal})`,exitCode:1}}function noteChildExit(daemonDir,code,signal,childStartedAt,now=Date.now()){classifyChildExit(code,signal).exitCode!==0&&recordHostCrash(daemonDir,{at:new Date(now).toISOString(),...signal===null?{code:code??void 0}:{signal},uptimeMs:Math.max(0,now-childStartedAt),kind:"rpc-host",detection:"supervisor",...crashingRuntimeVersions()})}var OBSERVE_REQUEST_FIELD="observe",OBSERVING_COMMANDS=new Set(["get_protocol_info","list_sessions"]);function isObservingRequest(line){let request;try{request=JSON.parse(line)}catch{return!1}if(typeof request!="object"||request===null||Array.isArray(request))return!1;let record=request;return record.type==="warm"?!0:record[OBSERVE_REQUEST_FIELD]===!0&&OBSERVING_COMMANDS.has(record.type)}var MAX_CLASSIFIED_LINE_BYTES=64*1024,NEWLINE=10,ClientOccupancy=class{constructor(onAttach){this.clients=new Set,this.observers=new Set,this.attached=new Set,this.onAttach=onAttach}get attachedCount(){return this.attached.size}get unclassifiedCount(){return this.clients.size-this.observers.size-this.attached.size}admit(client){this.clients.add(client);let pending=Buffer.alloc(0),attach=()=>{client.off("data",classify),pending=Buffer.alloc(0),this.observers.delete(client),this.attached.add(client),this.onAttach()},classify=chunk=>{pending=Buffer.concat([pending,chunk]);for(let newline=pending.indexOf(NEWLINE);newline!==-1;newline=pending.indexOf(NEWLINE)){let line=pending.subarray(0,newline).toString("utf8");if(pending=pending.subarray(newline+1),!isObservingRequest(line)){attach();return}this.observers.add(client)}pending.length>MAX_CLASSIFIED_LINE_BYTES&&attach()};client.on("data",classify)}release(client){this.clients.delete(client),this.observers.delete(client),this.attached.delete(client)}destroyAll(){for(let client of this.clients)client.destroy()}};function rpcHostExecArgv(execArgv=process.execArgv,bun=process.versions.bun!==void 0){let args=[];for(let index=0;index<execArgv.length;index++){let arg=execArgv[index];if(bun){if(arg==="-e"||arg==="--eval"||arg==="-p"||arg==="--print"||arg==="-pe"){index++;continue}if(arg.startsWith("-e")||arg.startsWith("-p"))continue}if(arg==="-e"||arg==="--eval"||arg==="-pe"||arg==="--input-type"||arg==="--input_type"){index++;continue}if(arg==="-p"||arg==="--print"){execArgv[index+1]!==void 0&&!execArgv[index+1].startsWith("-")&&index++;continue}arg==="-i"||arg==="--interactive"||arg.startsWith("--interactive=")||arg.startsWith("--eval=")||arg.startsWith("--print=")||arg.startsWith("--input-type=")||arg.startsWith("--input_type=")||args.push(arg)}return args}var HOST_COLD_START_ENV="SENPI_RPC_HOST_COLD_START",HOST_IDLE_EXIT_MS_ENV="SENPI_RPC_HOST_IDLE_EXIT_MS",DEFAULT_HOST_IDLE_EXIT_MS=9e5,HANDOFF_GRACE_MS_ENV="SENPI_RPC_HANDOFF_GRACE_MS",DEFAULT_HANDOFF_GRACE_MS=6e5;function parseColdStart(value){return value==="transient"||value==="persistent"?value:void 0}function parseIdleExitMs(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isFinite(parsed)&&parsed>0?parsed:void 0}function resolveHostPolicy(settings,env){let record=isRecord(settings)?settings:{},coldStart=parseColdStart(env[HOST_COLD_START_ENV])??parseColdStart(asOptionalString(record.coldStart))??"transient",idleExitMs=parseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV])??parseIdleExitMs(asOptionalString(record.idleExitMs))??9e5;return{coldStart,idleExitMs}}var IdleExitDecider=class{constructor(idleExitMs,now=Date.now){this.idleExitMs=idleExitMs,this.now=now}update(activity){return activity.connections>0||activity.activeTurns>0?(this.idleSince=void 0,"active"):this.idleExitMs===Number.POSITIVE_INFINITY?"idle":this.idleSince===void 0?(this.idleSince=this.now(),"idle"):this.now()-this.idleSince>=this.idleExitMs?"exit":"idle"}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function asOptionalString(value){return typeof value=="string"?value:typeof value=="number"?String(value):void 0}function hostCrashCleanupPaths(targets){let publicEntry=targets.platform==="win32"?[targets.publicSocket]:[];return targets.successor?publicEntry:[targets.generationPidFile,targets.settingsFile,...publicEntry,targets.pointerFile]}var SessionRunActivity=class{#running=new Set;observe(line){let event=parseHostEvent(line);if(event===void 0)return!1;if(event.type==="agent_start")this.#running.add(event.sessionId);else if(event.type==="agent_settled"||event.type==="session_closed")this.#running.delete(event.sessionId);else return!1;return!0}get busySessions(){return this.#running.size}};function parseHostEvent(line){let event;try{event=JSON.parse(line)}catch{return}if(typeof event!="object"||event===null)return;let{type,sessionId}=event;return typeof sessionId=="string"?{type,sessionId}:void 0}var SUPERSESSION_POLL_MS=1e3,ABSENT_CONFIRMATIONS=3;function watchForSupersession(endpoint,onLost){if(endpoint.identity===void 0||process.platform==="win32")return()=>{};let absentPolls=0,lost=!1,lose=loss=>{lost||(lost=!0,stop(),onLost(loss))},timer=setInterval(()=>{endpoint.settled?.()!==!0&&classifyEndpointOwnership(endpoint.path,endpoint.identity).then(ownership=>{if(endpoint.settled?.()!==!0)switch(ownership){case"replaced":lose("replaced");return;case"absent":if(absentPolls+=1,absentPolls<ABSENT_CONFIRMATIONS)return;lose("absent");return;case"held":case"unknown":absentPolls=0;return}},ignore)},SUPERSESSION_POLL_MS);timer.unref?.();let stop=()=>clearInterval(timer);return stop}function ignore(){}import{rmSync as rmSync2}from"node:fs";import{rm}from"node:fs/promises";import{Socket}from"node:net";var HOST_WATCH_FD_ENV="SENPI_RPC_HOST_WATCH_FD",HOST_SCRATCH_DIR_ENV="SENPI_RPC_HOST_SCRATCH_DIR",HOST_PUBLIC_SOCKET_ENV="SENPI_RPC_HOST_PUBLIC_SOCKET",HOST_WATCH_PPID_ENV="SENPI_RPC_HOST_WATCH_PPID",HOST_WATCH_PPID_INTERVAL_MS=250,HOST_CLEANUP_PATHS_ENV="SENPI_RPC_HOST_CLEANUP_PATHS";function parsePositiveInteger(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isSafeInteger(parsed)&&parsed>0?parsed:void 0}function readHostWatchdogConfig(env=process.env){let fd=parsePositiveInteger(env[HOST_WATCH_FD_ENV]),ppid=parsePositiveInteger(env[HOST_WATCH_PPID_ENV]);if(fd===void 0&&ppid===void 0)return;let scratchDir=env[HOST_SCRATCH_DIR_ENV],cleanupPaths=env[HOST_CLEANUP_PATHS_ENV]?.split(`
12
+ `).filter(Boolean),publicSocket=env[HOST_PUBLIC_SOCKET_ENV];return{fd,ppid,scratchDir:scratchDir===void 0||scratchDir===""?void 0:scratchDir,cleanupPaths,publicSocket:publicSocket===""?void 0:publicSocket}}function readHostWatchdogConfigFromBrandEnv(){return readHostWatchdogConfig({[HOST_WATCH_FD_ENV]:process.env[HOST_WATCH_FD_ENV]??envValue("RPC_HOST_WATCH_FD"),[HOST_WATCH_PPID_ENV]:process.env[HOST_WATCH_PPID_ENV]??envValue("RPC_HOST_WATCH_PPID"),[HOST_SCRATCH_DIR_ENV]:process.env[HOST_SCRATCH_DIR_ENV]??envValue("RPC_HOST_SCRATCH_DIR"),[HOST_PUBLIC_SOCKET_ENV]:process.env[HOST_PUBLIC_SOCKET_ENV]??envValue("RPC_HOST_PUBLIC_SOCKET"),[HOST_CLEANUP_PATHS_ENV]:process.env[HOST_CLEANUP_PATHS_ENV]??envValue("RPC_HOST_CLEANUP_PATHS")})}function armHostWatchdog(config,onSupervisorGone){if(!config)return()=>{};let fire=reason=>{disarm();let captured=captureBeforeCleanup(config);if(process.platform==="win32"){let cleanup=captured.then(()=>cleanupWatchdogPaths(config));onSupervisorGone(reason,cleanup)}else captured.then(()=>cleanupWatchdogPaths(config)).finally(()=>onSupervisorGone(reason))},disarmers=[],disarm=()=>{for(let stop of disarmers.splice(0))stop()};return config.fd!==void 0&&disarmers.push(watchFdForEof(config.fd,fire)),config.ppid!==void 0&&disarmers.push(watchPpid(config.ppid,fire)),disarm}function watchFdForEof(fd,fire){let stream,streamFailed=!1,fired=!1,fireOnce=reason=>{fired||(fired=!0,fire(reason))};try{stream=new Socket({fd,readable:!0,writable:!1})}catch{return()=>{}}stream.resume();let onEnd=()=>fireOnce(`supervisor pipe fd ${fd} closed`),onClose=()=>{streamFailed||onEnd()},onError=()=>{streamFailed=!0};return stream.once("end",onEnd),process.platform==="win32"&&stream.once("close",onClose),stream.once("error",onError),()=>{stream.off("end",onEnd),stream.off("close",onClose),stream.off("error",onError),stream.destroy()}}function watchPpid(supervisorPid,fire){if(supervisorPid===process.pid)return()=>{};let timer=setInterval(()=>{if(!processAlive(supervisorPid)){fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`);return}process.ppid!==supervisorPid&&fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`)},HOST_WATCH_PPID_INTERVAL_MS);return timer.unref?.(),()=>clearInterval(timer)}function processAlive(pid){try{return process.kill(pid,0),!0}catch(cause){return cause instanceof Error&&"code"in cause&&cause.code!=="ESRCH"}}function captureBeforeCleanup(config){return config.beforeCleanup===void 0?Promise.resolve():Promise.resolve().then(config.beforeCleanup).catch(()=>{})}async function cleanupWatchdogPaths(config){let paths=[...config.cleanupPaths??[],...config.scratchDir?[config.scratchDir]:[]];for(let path of paths)try{process.platform==="win32"?rmSync2(path,{recursive:!0,force:!0,maxRetries:10,retryDelay:100}):await rm(path,{recursive:!0,force:!0})}catch{}}function activeTurnsForIdleDecision(input){return input.healthy?input.observedBusy:input.unhealthySince===void 0||input.now-input.unhealthySince<input.unknownGraceMs?1:0}function createObserverLink(options){let current,healthy=!1,unhealthySince,retry,armRetry=()=>{retry!==void 0||options.settled()||(retry=options.setTimer(()=>{retry=void 0,open().catch(armRetry)},options.retryDelayMs))};async function open(){let socket=await options.open();current=socket,healthy=!0,unhealthySince=void 0,socket.onLost(()=>{current!==socket||options.settled()||(healthy=!1,unhealthySince??=options.now(),current=void 0,armRetry())})}return{open,healthy:()=>healthy,unhealthySince:()=>unhealthySince,stop:()=>{retry?.cancel(),retry=void 0,current=void 0}}}var CHILD_STOP_TIMEOUT_MS=5e3,WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS=2e3,CHILD_WATCH_FD=3;async function createInternalSocketPath(baseDir=tmpdir(),platform=process.platform){if(platform==="win32"){let dir2=join3(baseDir,`internal-${randomUUID()}`);return await mkdir(dir2,{recursive:!0,mode:448}),{socket:`\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,dir:dir2,secretPath:join3(dir2,"secret")}}let dir=join3(tmpdir(),`senpi-rpc-host-internal-${randomUUID().slice(0,8)}`);return await mkdir(dir,{recursive:!1,mode:448}),await writeFile(join3(dir,".owner"),JSON.stringify({pid:process.pid,processStartTime:await readProcessStartTime(process.pid),createdAt:Date.now()}),{mode:384}),{socket:join3(dir,"host.sock"),dir,secretPath:join3(dir,".secret")}}var INTERNAL_SUPERVISOR_FLAG="--internal-rpc-host-supervisor",INJECTABLE_PREFIX_FLAGS=new Set(["--extension"]);function findInternalSupervisorArgs(argv){for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg===INTERNAL_SUPERVISOR_FLAG)return argv.slice(index+1);if(!INJECTABLE_PREFIX_FLAGS.has(arg)||index+1>=argv.length)return;index++}}function parseSupervisorArgs(argv){let hostArgs=[],socket,childCommand,childArgs,agentDir,bindSocket,replaceIdentity;for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg==="--socket"&&index+1<argv.length){socket=argv[++index];continue}if(arg==="--child-command"&&index+1<argv.length){childCommand=argv[++index];continue}if(arg==="--child-args"&&index+1<argv.length){try{let parsed=JSON.parse(argv[++index]);Array.isArray(parsed)&&parsed.every(value=>typeof value=="string")&&(childArgs=parsed)}catch{return}continue}if(arg==="--agent-dir"&&index+1<argv.length){agentDir=argv[++index];continue}if(arg==="--bind"&&index+1<argv.length){bindSocket=argv[++index];continue}if(arg==="--replace"&&index+1<argv.length){replaceIdentity=parseSocketIdentity(argv[++index]);continue}hostArgs.push(arg)}return socket===void 0?void 0:{socket,hostArgs,childCommand,childArgs,agentDir,bindSocket,replaceIdentity}}function parseSocketIdentity(value){let match=/^(\d+):(\d+)$/.exec(value);return match?{dev:Number(match[1]),ino:Number(match[2])}:void 0}function resolveCliMainPath(modulePath=fileURLToPath(import.meta.url),bundled=isBundledNode){let declared=bundled?resolveDeclaredCliEntry(modulePath):void 0;if(declared!==void 0)return declared;let extension=modulePath.endsWith(".ts")?".ts":".js",unbundled=resolve(dirname(modulePath),"..","..",`cli-main${extension}`);return existsSync(unbundled)?unbundled:resolveDeclaredCliEntry(modulePath)??unbundled}function resolveDeclaredCliEntry(modulePath){let dir=dirname(modulePath);for(let depth=0;depth<8;depth+=1){let manifestPath=resolve(dir,"package.json");if(existsSync(manifestPath)){try{let declared=JSON.parse(readFileSync3(manifestPath,"utf8")).bin,candidates=typeof declared=="string"?[declared]:Object.values(declared??{});for(let candidate of candidates){let entry=resolve(dir,candidate);if(existsSync(entry))return entry}}catch{}return}let parent=dirname(dir);if(parent===dir)return;dir=parent}}function resolveHostChildLaunch(launch,internalSocket,compiled=isBunBinary){return launch.childCommand?{command:launch.childCommand,args:[...launch.childArgs??[],"--listen",`unix://${internalSocket}`]}:{command:process.execPath,args:[...compiled?[]:[...rpcHostExecArgv(),resolveCliMainPath()],"--mode","rpc","--multi-session","--listen",`unix://${internalSocket}`,...launch.hostArgs]}}function quoteWindowsShellArg(value){return`"${value.replace(/(\\*)"/g,'$1$1\\"').replace(/(\\*)$/,"$1$1").replace(/([()%!^"<>&|;,])/g,"^$1")}"`}function spawnableChildLaunch(launch,platform=process.platform){let extension=extname(launch.command).toLowerCase();return platform!=="win32"||extension!==".cmd"&&extension!==".bat"?{...launch,shell:!1}:{command:quoteWindowsShellArg(launch.command),args:launch.args.map(quoteWindowsShellArg),shell:!0}}async function runHostSupervisor(launch){let paths=createHostDaemonPaths({socket:launch.socket,agentDir:launch.agentDir??getAgentDir()}),told=process.env[HOST_INSTANCE_ID_ENV],instanceId=told!==void 0&&told.trim()!==""?told:randomUUID(),generation=generationPaths(paths,instanceId),policy=resolveHostPolicy(await readSettingsFile(paths.settingsFile),process.env),publicSocket=launch.socket,bindSocket=launch.bindSocket??publicSocket,successor=launch.bindSocket!==void 0,publicSecret=process.platform==="win32"?await ensurePublicSocketSecret(publicSocket):void 0,internal=await createInternalSocketPath(paths.dir),internalSocket=internal.socket,internalSecretPath=internal.secretPath??socketSecretPath(internalSocket),internalSecret=process.platform==="win32"?await createSocketSecret(internalSecretPath):void 0,clients=new ClientOccupancy(()=>decider.update(currentActivity())),runs=new SessionRunActivity,observerSocket,observerLink=createObserverLink({open:async()=>{let secret=internalSecret,next=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,secret));return secret&&sendSocketHandshake(next,secret),await waitForConnect(next,5e3),observerSocket=next,attachJsonlLineReader(next,observeHostEvent,{maxLineLength:MAX_RPC_LINE_CHARACTERS}),{onLost:handler=>{next.once("close",handler),next.once("error",handler)}}},settled:()=>shuttingDown,retryDelayMs:250,now:Date.now,setTimer:(run,ms)=>{let timer=setTimeout(run,ms);return timer.unref?.(),{cancel:()=>clearTimeout(timer)}}}),childExitWatchTimer,stopSupersessionWatch,shuttingDown=!1,draining=!1,endpointReplaced=!1,handoffGraceTimer,shutdownPromise,childLaunch=spawnableChildLaunch(resolveHostChildLaunch(launch,internalSocket)),child=spawn(childLaunch.command,childLaunch.args,{env:{...process.env,...launch.agentDir?{SENPI_CODING_AGENT_DIR:launch.agentDir}:{},[HOST_DAEMON_DIR_ENV]:paths.dir,[HOST_INSTANCE_ID_ENV]:instanceId,[HOST_WATCH_FD_ENV]:String(CHILD_WATCH_FD),[HOST_WATCH_PPID_ENV]:String(process.pid),...internal.dir?{[HOST_SCRATCH_DIR_ENV]:internal.dir}:{},...internalSecret?{[SOCKET_SECRET_FILE_ENV]:internalSecretPath}:{},[HOST_CLEANUP_PATHS_ENV]:hostCrashCleanupPaths({pointerFile:paths.pointerFile,generationPidFile:generation.pidFile,settingsFile:paths.settingsFile,publicSocket,successor:!!successor,platform:process.platform}).join(`
13
+ `),...process.platform==="win32"?{}:{[HOST_PUBLIC_SOCKET_ENV]:publicSocket}},shell:childLaunch.shell,stdio:["ignore","ignore","inherit","pipe"],windowsHide:!0}),childStartedAt=Date.now();child.stdio[CHILD_WATCH_FD]?.on("error",()=>{}),child.once("exit",(code,signal)=>{if(shuttingDown)return;let{reason,exitCode}=classifyChildExit(code,signal);noteChildExit(paths.dir,code,signal,childStartedAt),shutdown(reason,exitCode)});let server=createServer(client=>{let accept=()=>{if(shuttingDown||draining){client.destroy();return}let internal2=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,internalSecret));internalSecret&&sendSocketHandshake(internal2,internalSecret),clients.admit(client);let detach=()=>{clients.release(client),decider.update(currentActivity()),internal2.destroy(),client.destroy()};client.pipe(internal2),internal2.pipe(client),client.once("close",detach),client.once("error",detach),internal2.once("end",()=>client.end(()=>client.destroy())),internal2.once("close",()=>{internal2.readableEnded||detach()}),internal2.once("error",detach)};publicSecret?authenticateSocket(client,publicSecret,accept):accept()});server.once("error",cause=>{shuttingDown||shutdown(`public socket listener failed: ${errorMessage(cause)}`,1)});let decider=new IdleExitDecider(policy.coldStart==="persistent"?Number.POSITIVE_INFINITY:policy.idleExitMs),tickIntervalMs=Math.max(20,Math.min(1e3,policy.idleExitMs/4)),ticker=setInterval(()=>{!draining&&decider.update(currentActivity())==="exit"&&clients.unclassifiedCount===0&&shutdown("idle",0)},tickIntervalMs);function currentActivity(){return{connections:clients.attachedCount,activeTurns:activeTurnsForIdleDecision({healthy:observerLink.healthy(),unhealthySince:observerLink.unhealthySince(),now:Date.now(),unknownGraceMs:decider.idleExitMs,observedBusy:runs.busySessions})}}function observeHostEvent(line){runs.observe(line)&&decider.update(currentActivity())}async function shutdown(reason,exitCode){return shutdownPromise??=performShutdown(reason,exitCode),shutdownPromise}async function performShutdown(reason,exitCode){shuttingDown&&process.exit(exitCode),shuttingDown=!0,clearInterval(ticker),handoffGraceTimer&&clearTimeout(handoffGraceTimer),childExitWatchTimer&&clearInterval(childExitWatchTimer),stopSupersessionWatch?.();let hardExit=process.platform==="win32"?setTimeout(()=>process.exit(exitCode),WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS):void 0;try{writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`),clients.destroyAll(),draining||await shieldSocketDuringClose(publicSocket,()=>closeServer(server)),internal.dir&&await rm2(internal.dir,{recursive:!0,force:!0}),await stopChild(child),observerLink.stop(),observerSocket?.destroy(),publicSocketOwned&&process.platform!=="win32"&&await unlinkOwnedSocket(publicSocket,publicSocketIdentity,supervisorLog),await releaseGeneration(paths,{instanceId,pid:process.pid,superseded:endpointReplaced})}finally{hardExit&&clearTimeout(hardExit),process.exit(exitCode)}}let publicSocketOwned=!1,publicSocketIdentity;function supervisorLog(message){writeStderrLine(`senpi rpc host supervisor: ${message}`)}function drainForHandoff(){if(draining||shuttingDown)return;draining=!0,supervisorLog("draining into the next generation");let graceMs=parseIdleExitMs(process.env[HANDOFF_GRACE_MS_ENV])??6e5;handoffGraceTimer=setTimeout(()=>{supervisorLog(JSON.stringify({event:"handoff_grace_expired",graceMs})),requestChildDrain()},graceMs),handoffGraceTimer.unref(),requestChildDrain()}function requestChildDrain(){if(child.pid!==void 0&&child.exitCode===null&&child.signalCode===null)try{process.kill(child.pid,"SIGUSR1")}catch(cause){supervisorLog(`could not ask the host to drain: ${errorMessage(cause)}`)}}registerSupervisorSignals(shutdown,drainForHandoff);try{await waitForListener(internalSocket,3e4,internalSecret),await observerLink.open(),await prepareSocketPath(bindSocket),await listen(server,bindSocket,publicSecret),publicSocketOwned=!0,successor&&await adoptPublicSocket(bindSocket,publicSocket,launch.replaceIdentity),publicSocketIdentity=await statSocketIdentity(publicSocket),publicSocketIdentity&&internal.dir&&await writeSocketIdentityFile(join3(internal.dir,PUBLIC_SOCKET_IDENTITY_FILE),publicSocketIdentity),stopSupersessionWatch=watchForSupersession({path:publicSocket,identity:publicSocketIdentity,settled:()=>shuttingDown||draining},loss=>{loss==="replaced"&&(endpointReplaced=!0),supervisorLog(loss==="absent"?"the public socket entry is gone; nothing can reach this generation; draining":"another generation owns the public socket; draining this one"),drainForHandoff()})}catch(cause){await shutdown(`startup failed: ${errorMessage(cause)}`,1)}if(process.platform==="win32"&&child.pid!==void 0){let childStartTime=await readProcessStartTime(child.pid,process.platform,1e3).catch(()=>{}),missingIdentityChecks=0,checkingChildIdentity=!1;childExitWatchTimer=setInterval(()=>{shuttingDown||checkingChildIdentity||child.exitCode!==null||child.signalCode!==null||(checkingChildIdentity=!0,readProcessStartTime(child.pid,process.platform,1e3).then(currentStartTime=>{currentStartTime===void 0&&!processIsLive(child.pid)?missingIdentityChecks++:currentStartTime!==void 0&&(missingIdentityChecks=0),(childStartTime!==void 0&&currentStartTime!==void 0&&currentStartTime!==childStartTime||missingIdentityChecks>=2)&&shutdown("rpc host child exit observed by identity watchdog",0)}).catch(()=>{}).finally(()=>{checkingChildIdentity=!1}))},500),childExitWatchTimer.unref?.()}writeStderrLine(`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${policy.coldStart==="persistent"?"never":String(policy.idleExitMs)})`),await new Promise(()=>{})}function registerSupervisorSignals(shutdown,drain){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{shutdown(`signal:${signal}`,signal==="SIGHUP"?129:143)});process.platform!=="win32"&&process.on("SIGUSR1",drain)}async function adoptPublicSocket(bindSocket,publicSocket,expected){if(expected===void 0)throw new Error(`${publicSocket}: a generation launch must name the entry it replaces`);let current=await statSocketIdentity(publicSocket);if(current===void 0||current.dev!==expected.dev||current.ino!==expected.ino)throw new Error(`${publicSocket}: owned by another socket entry now; refusing to replace it`);await rename(bindSocket,publicSocket)}async function ensurePublicSocketSecret(publicSocket){let secretPath=socketSecretPath(publicSocket);try{return await ensureSocketSecret(secretPath)}catch(cause){throw new Error(`senpi rpc host supervisor: cannot provision public socket secret ${secretPath}`,{cause})}}async function readSettingsFile(settingsFile){try{return JSON.parse(await readFile(settingsFile,"utf8"))}catch{return}}async function stopChild(child){if(!(child.exitCode!==null||child.signalCode!==null)){try{child.kill("SIGTERM")}catch{return}if(!await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS)){try{child.kill("SIGKILL")}catch{return}await waitForChildExit(child,2e3)}}}function waitForChildExit(child,timeoutMs){return child.exitCode!==null||child.signalCode!==null?Promise.resolve(!0):new Promise(resolve2=>{let timer=setTimeout(()=>{child.off("exit",onExit2),resolve2(!1)},timeoutMs),onExit2=()=>{clearTimeout(timer),resolve2(!0)};child.once("exit",onExit2)})}async function waitForListener(socketPath,timeoutMs,secret){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await canConnect(socketPath,secret))return;await delay(50)}throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`)}function canConnect(socketPath,secret){return new Promise(resolve2=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform,secret));secret&&sendSocketHandshake(socket,secret);let settle=value=>{socket.destroy(),resolve2(value)};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1))})}function waitForConnect(socket,timeoutMs){return new Promise((resolve2,reject)=>{let timer=setTimeout(()=>{cleanup(),reject(new Error(`observer connection to internal host timed out after ${timeoutMs}ms`))},timeoutMs),onConnect=()=>{cleanup(),resolve2()},onError=cause=>{cleanup(),reject(cause)},cleanup=()=>{clearTimeout(timer),socket.off("connect",onConnect),socket.off("error",onError)};socket.once("connect",onConnect),socket.once("error",onError)})}async function prepareSocketPath(socketPath){if(process.platform!=="win32"){if(Buffer.byteLength(socketPath)>MAX_SOCKET_PATH_BYTES)throw new Error(`${socketPath}: socket path is ${Buffer.byteLength(socketPath)} bytes, over the ${MAX_SOCKET_PATH_BYTES}-byte limit.`);await mkdir(dirname(socketPath),{recursive:!0,mode:448});try{await access(socketPath)}catch(cause){if(isNodeErrorCode(cause,"ENOENT"))return;throw cause}if(await canConnect(socketPath))throw new Error(`${socketPath}: address already in use by a live server.`);await unlink(socketPath)}}function listen(server,socketPath,secret){return new Promise((resolve2,reject)=>{server.once("error",reject),server.listen({path:resolveSocketTransportAddress(socketPath,process.platform,secret),readableAll:!1,writableAll:!1},async()=>{server.off("error",reject);try{process.platform!=="win32"&&!socketPath.startsWith("\0")&&await chmod(socketPath,384),resolve2()}catch(cause){reject(cause)}})})}function closeServer(server){return new Promise(resolve2=>{server.close(()=>resolve2())})}function writeStderrLine(text){try{writeSync(2,`${text}
14
14
  `)}catch{}}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function errorMessage(cause){return cause instanceof Error?cause.message:String(cause)}function isNodeErrorCode(cause,code){return cause instanceof Error&&"code"in cause&&cause.code===code}function isEntryScript(){let entry=process.argv[1];if(!entry)return!1;try{return fileURLToPath(import.meta.url)===realpathSync(entry)}catch{return!1}}if(!isBundledNode&&isEntryScript()){let launch=parseSupervisorArgs(process.argv.slice(2));launch||(writeStderrLine("usage: host-lifecycle.ts --socket <path> [host cli args...]"),process.exit(2)),runHostSupervisor(launch)}export{rpcHostExecArgv,recordProcessLifetime,readHostCrashRecords,classifyChildExit,OBSERVE_REQUEST_FIELD,ClientOccupancy,HOST_COLD_START_ENV,HOST_IDLE_EXIT_MS_ENV,DEFAULT_HOST_IDLE_EXIT_MS,HANDOFF_GRACE_MS_ENV,DEFAULT_HANDOFF_GRACE_MS,parseColdStart,parseIdleExitMs,resolveHostPolicy,IdleExitDecider,readHostWatchdogConfigFromBrandEnv,armHostWatchdog,createInternalSocketPath,INTERNAL_SUPERVISOR_FLAG,findInternalSupervisorArgs,parseSupervisorArgs,resolveCliMainPath,resolveHostChildLaunch,spawnableChildLaunch,runHostSupervisor};
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{rateLimitModelFamily}from"./chunk-F6EQ7EV3.js";import{getShellConfig}from"./chunk-JEZWV7JW.js";import{getOverflowPatterns}from"./chunk-D2W3MXRF.js";import{normalizeProviderError}from"./chunk-TAV6QZFM.js";import{extract429RetryAfterMs}from"./chunk-PELNNWGO.js";import{PROVIDER_NOT_CONFIGURED_PREFIX,USAGE_LIMIT_EXHAUSTION}from"./chunk-XL5KIYQF.js";var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error"),status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}function rendezvousOrder(key,slots,hasher){return[...slots].map(slot=>({slot,score:hasher(`${key}\0${slot.name}`)})).sort((left,right)=>right.score>left.score?1:right.score<left.score?-1:0).map(({slot})=>slot)}var DEFAULT_SLOT_BLOCK_MS=6e4,MAX_SLOT_BLOCK_MS=2880*60*1e3;var MONTHS=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"],RESET_AT_KEYS=new Set(["resets_at"]),RESET_AFTER_SECONDS_KEYS=new Set(["reset_after_seconds"]),RELATIVE_RE=/\b(?:resets?|try again|retry)\s+in\s+~?((?:\d+(?:\.\d+)?\s*(?:days?|d|hours?|hrs?|h|minutes?|mins?|m|seconds?|secs?|s)\b(?:\s*,?\s*(?:and\s+)?)?)+)/i,RELATIVE_PART_RE=/(\d+(?:\.\d+)?)\s*(days?|d|hours?|hrs?|h|minutes?|mins?|m|seconds?|secs?|s)\b/gi,CLOCK_RE=/\b(?:resets?|try again)\s+(?:at\s+|on\s+)?(?:([a-z]{3})[a-z]*\.?\s+(\d{1,2}),?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*([ap])\.?\s?m\b\.?(?:\s*\(([A-Za-z_]+(?:\/[A-Za-z0-9_+-]+)*)\))?/i;function usageLimitResetMs(text,nowMs){return fromJsonFields(text,nowMs)??fromRelativeProse(text)??fromClockProse(text,nowMs)}function fromJsonFields(text,nowMs){let start=text.indexOf("{");if(start<0)return;let parsed;try{parsed=JSON.parse(text.slice(start))}catch{return}let found;return walk(parsed,(key,value)=>{let ms=RESET_AT_KEYS.has(key)?absoluteFieldMs(value,nowMs):RESET_AFTER_SECONDS_KEYS.has(key)?secondsFieldMs(value):void 0;ms!==void 0&&(found===void 0||ms>found)&&(found=ms)}),found}function walk(value,visit){if(Array.isArray(value)){for(let item of value)walk(item,visit);return}if(!(typeof value!="object"||value===null))for(let[key,entry]of Object.entries(value))visit(key,entry),walk(entry,visit)}function absoluteFieldMs(value,nowMs){if(typeof value=="number"&&Number.isFinite(value)&&value>0){let epochMs=value<1e12?value*1e3:value;return Math.max(0,Math.ceil(epochMs-nowMs))}if(typeof value=="string"&&/\d{4}-\d{2}-\d{2}T/.test(value)){let epochMs=Date.parse(value);return Number.isNaN(epochMs)?void 0:Math.max(0,epochMs-nowMs)}}function secondsFieldMs(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0?Math.ceil(value*1e3):void 0}function fromRelativeProse(text){let phrase=RELATIVE_RE.exec(text)?.[1];if(phrase===void 0)return;let total=0;for(let[,amount,unit]of phrase.matchAll(RELATIVE_PART_RE))total+=Number.parseFloat(amount??"0")*unitMs(unit??"");return Math.ceil(total)}function unitMs(unit){let u=unit.toLowerCase();return u.startsWith("d")?864e5:u.startsWith("h")?36e5:u==="s"||u.startsWith("sec")?1e3:6e4}function fromClockProse(text,nowMs){let match=CLOCK_RE.exec(text);if(!match)return;let[,monthName,dayText,hourText,minuteText,meridiem,zoneText]=match,hour12=Number.parseInt(hourText??"",10),minute=minuteText===void 0?0:Number.parseInt(minuteText,10);if(hour12<1||hour12>12||minute>59)return;let hour=hour12%12+(meridiem?.toLowerCase()==="p"?12:0),zone=zoneText??Intl.DateTimeFormat().resolvedOptions().timeZone;if(!isValidTimeZone(zone))return;let today=zonedParts(zone,nowMs);if(monthName!==void 0){let month=MONTHS.indexOf(monthName.toLowerCase()),day=Number.parseInt(dayText??"",10);if(month<0||day<1||day>31)return;let target2=zonedToEpoch(zone,today.year,month,day,hour,minute);return target2<=nowMs&&(target2=zonedToEpoch(zone,today.year+1,month,day,hour,minute)),target2-nowMs}let target=zonedToEpoch(zone,today.year,today.month,today.day,hour,minute);return target<=nowMs&&(target=zonedToEpoch(zone,today.year,today.month,today.day+1,hour,minute)),target-nowMs}function isValidTimeZone(zone){try{return new Intl.DateTimeFormat("en-US",{timeZone:zone}),!0}catch{return!1}}function zonedParts(zone,epochMs){let parts=new Intl.DateTimeFormat("en-US",{timeZone:zone,hourCycle:"h23",year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric"}).formatToParts(epochMs),get=type=>Number.parseInt(parts.find(part=>part.type===type)?.value??"0",10);return{year:get("year"),month:get("month")-1,day:get("day"),hour:get("hour"),minute:get("minute"),second:get("second")}}function zoneOffsetMs(zone,epochMs){let p=zonedParts(zone,epochMs);return Date.UTC(p.year,p.month,p.day,p.hour,p.minute,p.second)-Math.floor(epochMs/1e3)*1e3}function zonedToEpoch(zone,year,month,day,hour,minute){let wall=Date.UTC(year,month,day,hour,minute),first=wall-zoneOffsetMs(zone,wall);return wall-zoneOffsetMs(zone,first)}function escapeRegExp(text){return text.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ACCOUNT_USAGE_LIMIT_TEXT=new RegExp([...USAGE_LIMIT_EXHAUSTION.markers.map(escapeRegExp),String.raw`\b(?:hit|reached)\s+your\b[^.]*?\blimit\b`,String.raw`\busage\s+limit\s+reached\b`,String.raw`\b(?:Go|Free)UsageLimitError\b`,String.raw`\bblocking_limit\b`,String.raw`\brapid_refill_breaker\b`,String.raw`\bquota\s+exceeded\b`].join("|"),"i");function isAccountUsageLimitText(text){return ACCOUNT_USAGE_LIMIT_TEXT.test(text)}var COOLDOWN_BASE_MS=DEFAULT_SLOT_BLOCK_MS,COOLDOWN_CAP_MS=MAX_SLOT_BLOCK_MS,RETRY_SAME_MAX_ATTEMPTS=2;function rateLimitCooldown(failureCount,serverHintMs,policy={}){let cap=policy.capMs??COOLDOWN_CAP_MS,base=policy.baseMs??COOLDOWN_BASE_MS,backoff=Math.min(cap,base*2**Math.max(0,failureCount)),floored=serverHintMs===void 0?backoff:Math.max(backoff,serverHintMs);return{cooldownMs:Math.min(cap,floored),retryAfterWasCapped:floored>cap}}var INVALID_KEY_TEXT=/invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i,ACCOUNT_SCOPED_403_TEXT=/account|credential|token|api[ _-]?key|organization|subscription/i,RATE_LIMIT_TEXT=/rate[ _-]?limit|too many requests|resource_exhausted/i,BILLING_TEXT=/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i,OVERLOAD_TEXT=/overloaded/i,NETWORK_TEXT=/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i,WEBSOCKET_REQUEST_FAULT_TEXT=/websocket closed 100[89]\b/i,WEBSOCKET_TRANSPORT_FAULT_TEXT=/websocket (?:closed|error|connect timeout|liveness timeout)/i,FAIL_FAST_TEXT=/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i,ABORT_TEXT=/\baborted?\b/i;function isAbort(error,message){return error instanceof Error&&error.name==="AbortError"?!0:ABORT_TEXT.test(message)}function isOverflowText(text){return getOverflowPatterns().some(pattern=>pattern.test(text))}function classifyCredentialFailure(error,context={}){let normalized=normalizeProviderError(error),text=normalized.messageCarriesBody?normalized.message:`${normalized.message} ${normalized.body??""}`,status=normalized.status,failureCount=context.failureCount??0;if(isAbort(error,text))return{kind:"fail_request"};if(text.includes(PROVIDER_NOT_CONFIGURED_PREFIX))return{kind:"failover",block:{reason:"auth_error"}};if(status===401||INVALID_KEY_TEXT.test(text))return{kind:"failover",block:{reason:"auth_error"}};if(status===403)return ACCOUNT_SCOPED_403_TEXT.test(text)?{kind:"failover",block:{reason:"auth_error"}}:{kind:"fail_request"};if(status===402||BILLING_TEXT.test(text))return{kind:"failover",block:{reason:"account_disabled"}};let usageLimit=isAccountUsageLimitText(text)&&!isOverflowText(text);if(status===429||RATE_LIMIT_TEXT.test(text)||usageLimit){let nowMs=context.nowMs??Date.now(),hint=extract429RetryAfterMs({status:status??429,bodyText:text},nowMs)??(usageLimit?normalized.retryAfterMs??usageLimitResetMs(text,nowMs):void 0),modelFamily=rateLimitModelFamily(text);return{kind:"failover",block:{reason:"rate_limit",...rateLimitCooldown(failureCount,hint,{baseMs:context.cooldownBaseMs,capMs:context.cooldownCapMs}),...modelFamily===void 0?{}:{modelFamily}}}}return isOverflowText(text)||status===400||status===404||FAIL_FAST_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_REQUEST_FAULT_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_TRANSPORT_FAULT_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===529||OVERLOAD_TEXT.test(text)||status!==void 0&&status>=500&&status<600?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===408||NETWORK_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:{kind:"fail_request"}}var CredentialFailoverError=class extends Error{constructor(action,original,options={}){let detail=original instanceof Error?original.message:String(original);super(detail,{cause:original}),this.name="CredentialFailoverError",this.action=action,this.original=original,this.retryAt=options.retryAt}};function isAvailable(slot,now){return!(slot.blockReason==="auth_error"||slot.blockReason==="account_disabled"||slot.blockedUntil!==void 0&&slot.blockedUntil>now)}function soonestRetryAt(slots,now){let deadlines=slots.map(slot=>slot.blockedUntil).filter(value=>value!==void 0&&value>now);return deadlines.length===0?void 0:Math.min(...deadlines)}async function settle(stream){let iterator=stream[Symbol.asyncIterator]();try{await iterator.return?.(void 0)}catch{}}async function*runCredentialFailover(options){let now=options.now??Date.now,classify=options.classify??classifyCredentialFailure,attempted=new Set,retriesBySlot=new Map,lastError,lastOriginal,lastTerminalEvent,startAnnounced=!1;for(;;){let slots=await options.listSlots(),candidates=slots.filter(slot2=>!attempted.has(slot2.name)&&isAvailable(slot2,now()));if(candidates.length===0){if(lastTerminalEvent!==void 0){yield lastTerminalEvent;return}let retryAt=soonestRetryAt(slots,now());throw lastError!==void 0&&lastOriginal!==void 0?new CredentialFailoverError(lastError.action,lastOriginal,retryAt===void 0?{}:{retryAt}):new CredentialFailoverError({kind:"fail_request"},new Error("No credential slots available"),retryAt===void 0?{}:{retryAt})}let slot=options.select(candidates),committedOutput=!1,terminalEvent,attemptStream;try{attemptStream=await options.runAttempt(slot);for await(let event of attemptStream){let failure=options.errorFromEvent?.(event);if(failure!==void 0)throw terminalEvent=event,failure;if(options.isStreamStart?.(event)){if(startAnnounced)continue;startAnnounced=!0}committedOutput||=options.isCommittedOutput(event),yield event}await options.onSuccess?.(slot);return}catch(error){attemptStream&&await settle(attemptStream);let failureCount=(slot.failureCount??0)+(retriesBySlot.get(slot.name)??0),action=classify(error,{failureCount});if(lastOriginal=error,lastTerminalEvent=terminalEvent,action.kind==="retry_same"&&!committedOutput){let used=(retriesBySlot.get(slot.name)??0)+1;if(retriesBySlot.set(slot.name,used),used<action.maxAttempts)continue;if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}if(action.kind!=="failover"){if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}await options.persistBlock(slot,action.block),attempted.add(slot.name);let failure=new CredentialFailoverError(action,error);if(lastError=failure,await options.onRotate?.({slot,block:action.block,attempt:attempted.size,committedOutput}),committedOutput){if(terminalEvent!==void 0){yield terminalEvent;return}throw failure}}}}function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}import{spawn}from"child_process";var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{child.kill("SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(child.kill("SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){return env?.[name]||process.env[name]||void 0}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0)return;resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env){let resolvedValue=await resolveConfigValueUncached(config,env);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}export{sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent,rendezvousOrder,usageLimitResetMs,classifyCredentialFailure,CredentialFailoverError,runCredentialFailover};
2
+ import{rateLimitModelFamily}from"./chunk-F6EQ7EV3.js";import{getShellConfig}from"./chunk-JEZWV7JW.js";import{getOverflowPatterns}from"./chunk-LSE7KE2C.js";import{normalizeProviderError}from"./chunk-TAV6QZFM.js";import{extract429RetryAfterMs}from"./chunk-PELNNWGO.js";import{PROVIDER_NOT_CONFIGURED_PREFIX,USAGE_LIMIT_EXHAUSTION}from"./chunk-XL5KIYQF.js";var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error"),status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}function rendezvousOrder(key,slots,hasher){return[...slots].map(slot=>({slot,score:hasher(`${key}\0${slot.name}`)})).sort((left,right)=>right.score>left.score?1:right.score<left.score?-1:0).map(({slot})=>slot)}var DEFAULT_SLOT_BLOCK_MS=6e4,MAX_SLOT_BLOCK_MS=2880*60*1e3;var MONTHS=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"],RESET_AT_KEYS=new Set(["resets_at"]),RESET_AFTER_SECONDS_KEYS=new Set(["reset_after_seconds"]),RELATIVE_RE=/\b(?:resets?|try again|retry)\s+in\s+~?((?:\d+(?:\.\d+)?\s*(?:days?|d|hours?|hrs?|h|minutes?|mins?|m|seconds?|secs?|s)\b(?:\s*,?\s*(?:and\s+)?)?)+)/i,RELATIVE_PART_RE=/(\d+(?:\.\d+)?)\s*(days?|d|hours?|hrs?|h|minutes?|mins?|m|seconds?|secs?|s)\b/gi,CLOCK_RE=/\b(?:resets?|try again)\s+(?:at\s+|on\s+)?(?:([a-z]{3})[a-z]*\.?\s+(\d{1,2}),?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*([ap])\.?\s?m\b\.?(?:\s*\(([A-Za-z_]+(?:\/[A-Za-z0-9_+-]+)*)\))?/i;function usageLimitResetMs(text,nowMs){return fromJsonFields(text,nowMs)??fromRelativeProse(text)??fromClockProse(text,nowMs)}function fromJsonFields(text,nowMs){let start=text.indexOf("{");if(start<0)return;let parsed;try{parsed=JSON.parse(text.slice(start))}catch{return}let found;return walk(parsed,(key,value)=>{let ms=RESET_AT_KEYS.has(key)?absoluteFieldMs(value,nowMs):RESET_AFTER_SECONDS_KEYS.has(key)?secondsFieldMs(value):void 0;ms!==void 0&&(found===void 0||ms>found)&&(found=ms)}),found}function walk(value,visit){if(Array.isArray(value)){for(let item of value)walk(item,visit);return}if(!(typeof value!="object"||value===null))for(let[key,entry]of Object.entries(value))visit(key,entry),walk(entry,visit)}function absoluteFieldMs(value,nowMs){if(typeof value=="number"&&Number.isFinite(value)&&value>0){let epochMs=value<1e12?value*1e3:value;return Math.max(0,Math.ceil(epochMs-nowMs))}if(typeof value=="string"&&/\d{4}-\d{2}-\d{2}T/.test(value)){let epochMs=Date.parse(value);return Number.isNaN(epochMs)?void 0:Math.max(0,epochMs-nowMs)}}function secondsFieldMs(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0?Math.ceil(value*1e3):void 0}function fromRelativeProse(text){let phrase=RELATIVE_RE.exec(text)?.[1];if(phrase===void 0)return;let total=0;for(let[,amount,unit]of phrase.matchAll(RELATIVE_PART_RE))total+=Number.parseFloat(amount??"0")*unitMs(unit??"");return Math.ceil(total)}function unitMs(unit){let u=unit.toLowerCase();return u.startsWith("d")?864e5:u.startsWith("h")?36e5:u==="s"||u.startsWith("sec")?1e3:6e4}function fromClockProse(text,nowMs){let match=CLOCK_RE.exec(text);if(!match)return;let[,monthName,dayText,hourText,minuteText,meridiem,zoneText]=match,hour12=Number.parseInt(hourText??"",10),minute=minuteText===void 0?0:Number.parseInt(minuteText,10);if(hour12<1||hour12>12||minute>59)return;let hour=hour12%12+(meridiem?.toLowerCase()==="p"?12:0),zone=zoneText??Intl.DateTimeFormat().resolvedOptions().timeZone;if(!isValidTimeZone(zone))return;let today=zonedParts(zone,nowMs);if(monthName!==void 0){let month=MONTHS.indexOf(monthName.toLowerCase()),day=Number.parseInt(dayText??"",10);if(month<0||day<1||day>31)return;let target2=zonedToEpoch(zone,today.year,month,day,hour,minute);return target2<=nowMs&&(target2=zonedToEpoch(zone,today.year+1,month,day,hour,minute)),target2-nowMs}let target=zonedToEpoch(zone,today.year,today.month,today.day,hour,minute);return target<=nowMs&&(target=zonedToEpoch(zone,today.year,today.month,today.day+1,hour,minute)),target-nowMs}function isValidTimeZone(zone){try{return new Intl.DateTimeFormat("en-US",{timeZone:zone}),!0}catch{return!1}}function zonedParts(zone,epochMs){let parts=new Intl.DateTimeFormat("en-US",{timeZone:zone,hourCycle:"h23",year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric"}).formatToParts(epochMs),get=type=>Number.parseInt(parts.find(part=>part.type===type)?.value??"0",10);return{year:get("year"),month:get("month")-1,day:get("day"),hour:get("hour"),minute:get("minute"),second:get("second")}}function zoneOffsetMs(zone,epochMs){let p=zonedParts(zone,epochMs);return Date.UTC(p.year,p.month,p.day,p.hour,p.minute,p.second)-Math.floor(epochMs/1e3)*1e3}function zonedToEpoch(zone,year,month,day,hour,minute){let wall=Date.UTC(year,month,day,hour,minute),first=wall-zoneOffsetMs(zone,wall);return wall-zoneOffsetMs(zone,first)}function escapeRegExp(text){return text.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ACCOUNT_USAGE_LIMIT_TEXT=new RegExp([...USAGE_LIMIT_EXHAUSTION.markers.map(escapeRegExp),String.raw`\b(?:hit|reached)\s+your\b[^.]*?\blimit\b`,String.raw`\busage\s+limit\s+reached\b`,String.raw`\b(?:Go|Free)UsageLimitError\b`,String.raw`\bblocking_limit\b`,String.raw`\brapid_refill_breaker\b`,String.raw`\bquota\s+exceeded\b`].join("|"),"i");function isAccountUsageLimitText(text){return ACCOUNT_USAGE_LIMIT_TEXT.test(text)}var COOLDOWN_BASE_MS=DEFAULT_SLOT_BLOCK_MS,COOLDOWN_CAP_MS=MAX_SLOT_BLOCK_MS,RETRY_SAME_MAX_ATTEMPTS=2;function rateLimitCooldown(failureCount,serverHintMs,policy={}){let cap=policy.capMs??COOLDOWN_CAP_MS,base=policy.baseMs??COOLDOWN_BASE_MS,backoff=Math.min(cap,base*2**Math.max(0,failureCount)),floored=serverHintMs===void 0?backoff:Math.max(backoff,serverHintMs);return{cooldownMs:Math.min(cap,floored),retryAfterWasCapped:floored>cap}}var INVALID_KEY_TEXT=/invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i,ACCOUNT_SCOPED_403_TEXT=/account|credential|token|api[ _-]?key|organization|subscription/i,RATE_LIMIT_TEXT=/rate[ _-]?limit|too many requests|resource_exhausted/i,BILLING_TEXT=/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i,OVERLOAD_TEXT=/overloaded/i,NETWORK_TEXT=/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i,WEBSOCKET_REQUEST_FAULT_TEXT=/websocket closed 100[89]\b/i,WEBSOCKET_TRANSPORT_FAULT_TEXT=/websocket (?:closed|error|connect timeout|liveness timeout)/i,FAIL_FAST_TEXT=/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i,ABORT_TEXT=/\baborted?\b/i;function isAbort(error,message){return error instanceof Error&&error.name==="AbortError"?!0:ABORT_TEXT.test(message)}function isOverflowText(text){return getOverflowPatterns().some(pattern=>pattern.test(text))}function classifyCredentialFailure(error,context={}){let normalized=normalizeProviderError(error),text=normalized.messageCarriesBody?normalized.message:`${normalized.message} ${normalized.body??""}`,status=normalized.status,failureCount=context.failureCount??0;if(isAbort(error,text))return{kind:"fail_request"};if(text.includes(PROVIDER_NOT_CONFIGURED_PREFIX))return{kind:"failover",block:{reason:"auth_error"}};if(status===401||INVALID_KEY_TEXT.test(text))return{kind:"failover",block:{reason:"auth_error"}};if(status===403)return ACCOUNT_SCOPED_403_TEXT.test(text)?{kind:"failover",block:{reason:"auth_error"}}:{kind:"fail_request"};if(status===402||BILLING_TEXT.test(text))return{kind:"failover",block:{reason:"account_disabled"}};let usageLimit=isAccountUsageLimitText(text)&&!isOverflowText(text);if(status===429||RATE_LIMIT_TEXT.test(text)||usageLimit){let nowMs=context.nowMs??Date.now(),hint=extract429RetryAfterMs({status:status??429,bodyText:text},nowMs)??(usageLimit?normalized.retryAfterMs??usageLimitResetMs(text,nowMs):void 0),modelFamily=rateLimitModelFamily(text);return{kind:"failover",block:{reason:"rate_limit",...rateLimitCooldown(failureCount,hint,{baseMs:context.cooldownBaseMs,capMs:context.cooldownCapMs}),...modelFamily===void 0?{}:{modelFamily}}}}return isOverflowText(text)||status===400||status===404||FAIL_FAST_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_REQUEST_FAULT_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_TRANSPORT_FAULT_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===529||OVERLOAD_TEXT.test(text)||status!==void 0&&status>=500&&status<600?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===408||NETWORK_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:{kind:"fail_request"}}var CredentialFailoverError=class extends Error{constructor(action,original,options={}){let detail=original instanceof Error?original.message:String(original);super(detail,{cause:original}),this.name="CredentialFailoverError",this.action=action,this.original=original,this.retryAt=options.retryAt}};function isAvailable(slot,now){return!(slot.blockReason==="auth_error"||slot.blockReason==="account_disabled"||slot.blockedUntil!==void 0&&slot.blockedUntil>now)}function soonestRetryAt(slots,now){let deadlines=slots.map(slot=>slot.blockedUntil).filter(value=>value!==void 0&&value>now);return deadlines.length===0?void 0:Math.min(...deadlines)}async function settle(stream){let iterator=stream[Symbol.asyncIterator]();try{await iterator.return?.(void 0)}catch{}}async function*runCredentialFailover(options){let now=options.now??Date.now,classify=options.classify??classifyCredentialFailure,attempted=new Set,retriesBySlot=new Map,lastError,lastOriginal,lastTerminalEvent,startAnnounced=!1;for(;;){let slots=await options.listSlots(),candidates=slots.filter(slot2=>!attempted.has(slot2.name)&&isAvailable(slot2,now()));if(candidates.length===0){if(lastTerminalEvent!==void 0){yield lastTerminalEvent;return}let retryAt=soonestRetryAt(slots,now());throw lastError!==void 0&&lastOriginal!==void 0?new CredentialFailoverError(lastError.action,lastOriginal,retryAt===void 0?{}:{retryAt}):new CredentialFailoverError({kind:"fail_request"},new Error("No credential slots available"),retryAt===void 0?{}:{retryAt})}let slot=options.select(candidates),committedOutput=!1,terminalEvent,attemptStream;try{attemptStream=await options.runAttempt(slot);for await(let event of attemptStream){let failure=options.errorFromEvent?.(event);if(failure!==void 0)throw terminalEvent=event,failure;if(options.isStreamStart?.(event)){if(startAnnounced)continue;startAnnounced=!0}committedOutput||=options.isCommittedOutput(event),yield event}await options.onSuccess?.(slot);return}catch(error){attemptStream&&await settle(attemptStream);let failureCount=(slot.failureCount??0)+(retriesBySlot.get(slot.name)??0),action=classify(error,{failureCount});if(lastOriginal=error,lastTerminalEvent=terminalEvent,action.kind==="retry_same"&&!committedOutput){let used=(retriesBySlot.get(slot.name)??0)+1;if(retriesBySlot.set(slot.name,used),used<action.maxAttempts)continue;if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}if(action.kind!=="failover"){if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}await options.persistBlock(slot,action.block),attempted.add(slot.name);let failure=new CredentialFailoverError(action,error);if(lastError=failure,await options.onRotate?.({slot,block:action.block,attempt:attempted.size,committedOutput}),committedOutput){if(terminalEvent!==void 0){yield terminalEvent;return}throw failure}}}}function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}import{spawn}from"child_process";var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{child.kill("SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(child.kill("SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){return env?.[name]||process.env[name]||void 0}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0)return;resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env){let resolvedValue=await resolveConfigValueUncached(config,env);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}export{sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent,rendezvousOrder,usageLimitResetMs,classifyCredentialFailure,CredentialFailoverError,runCredentialFailover};