@code-yeongyu/senpi 2026.11.2-1 → 2026.11.2-2
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.
- package/CHANGELOG.md +19 -0
- package/dist/bundle/chunks/{chunk-AMCDEC5A.js → chunk-B2LRAXQU.js} +2 -2
- package/dist/bundle/chunks/{chunk-D22YF34L.js → chunk-CQ3G57HE.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZUVGFXCS.js → chunk-FVYWSBX3.js} +3 -3
- package/dist/bundle/chunks/{chunk-665UPAKG.js → chunk-H3BTMIH5.js} +6 -6
- package/dist/bundle/chunks/{chunk-KEJWNCLN.js → chunk-HUSQY3ID.js} +1 -1
- package/dist/bundle/chunks/{chunk-IBV4OVXQ.js → chunk-N6OHYIJR.js} +1 -1
- package/dist/bundle/chunks/{chunk-XZR4J6HM.js → chunk-PP52OWBB.js} +1 -1
- package/dist/bundle/chunks/{chunk-XVQISKHL.js → chunk-QV2IEA3B.js} +4 -4
- package/dist/bundle/chunks/{chunk-2V6BR24J.js → chunk-VEWJSPOZ.js} +1 -1
- package/dist/bundle/chunks/{cli-main-REFQSP6S.js → cli-main-6ZI4QO2Z.js} +1 -1
- package/dist/bundle/chunks/{host-command-Y3ZT6YLD.js → host-command-O3ALG2O3.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-VW73K4WA.js → host-lifecycle-SGTVODHB.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +5 -5
- package/dist/bundle/chunks/{host-session-command-YDEUZBTX.js → host-session-command-4WRR5JSB.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-UZXPNJ4V.js → interactive-mode-TF7R35GK.js} +1 -1
- package/dist/bundle/chunks/{main-O5G75MYS.js → main-XLUYSOXP.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-AZKJYA2X.js → multi-session-host-CADYC2BS.js} +4 -3
- package/dist/bundle/chunks/{package-manager-cli-2YDUGJNR.js → package-manager-cli-I62KMIWK.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-KZD5HZNI.js → rpc-mode-T5GVMUBQ.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-7LSJAINZ.js → schedule-command-YXGRN5CM.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-BG2KQ6MJ.js → session-control-endpoint-PREVS5UO.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +63 -62
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +5 -5
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/session-recovery-identity.d.ts +12 -1
- package/dist/modes/rpc/compact-call-fold.d.ts +3 -1
- package/dist/modes/rpc/compact-call-fold.js +17 -6
- package/dist/modes/rpc/compact-call-identity.d.ts +13 -0
- package/dist/modes/rpc/compact-call-identity.js +30 -0
- package/dist/modes/rpc/compact-call-model.d.ts +14 -0
- package/dist/modes/rpc/compact-call-model.js +4 -0
- package/dist/modes/rpc/compact-call-table.d.ts +9 -0
- package/dist/modes/rpc/compact-call-table.js +20 -0
- package/dist/modes/rpc/compact-catalog-settled.d.ts +5 -0
- package/dist/modes/rpc/compact-catalog-settled.js +9 -2
- package/dist/modes/rpc/compact-lane-current.d.ts +2 -0
- package/dist/modes/rpc/compact-lane-current.js +4 -0
- package/dist/modes/rpc/compact-message-identity.d.ts +74 -0
- package/dist/modes/rpc/compact-message-identity.js +101 -0
- package/dist/modes/rpc/compact-session-calls.d.ts +5 -4
- package/dist/modes/rpc/compact-session-calls.js +13 -8
- package/dist/modes/rpc/compact-session-state.d.ts +2 -0
- package/dist/modes/rpc/compact-session-state.js +4 -0
- package/dist/modes/rpc/compact-settled-messages.d.ts +12 -4
- package/dist/modes/rpc/compact-settled-messages.js +18 -10
- package/dist/modes/rpc/connection-handler.js +1 -1
- package/dist/modes/rpc/connection-question-bridge.d.ts +2 -1
- package/dist/modes/rpc/connection-question-bridge.js +3 -1
- package/dist/modes/rpc/host-lifecycle-proxy.d.ts +9 -0
- package/dist/modes/rpc/host-lifecycle-proxy.js +29 -7
- package/dist/modes/rpc/rpc-question-types.d.ts +2 -0
- package/dist/modes/rpc/session-acceptance-compact.d.ts +17 -7
- package/dist/modes/rpc/session-acceptance-compact.js +20 -8
- package/dist/modes/rpc/session-acceptance-lane.d.ts +5 -0
- package/dist/modes/rpc/session-acceptance-lane.js +12 -11
- package/dist/modes/rpc/session-event-writer-destinations.d.ts +2 -1
- package/dist/modes/rpc/session-event-writer-destinations.js +24 -9
- package/dist/utils/version-check.js +9 -3
- package/docs/engine-socket/fixtures/admission-routes/i-live-identity.json +716 -0
- package/docs/engine-socket/fixtures/admission-routes/index.json +3 -1
- package/docs/engine-socket/fixtures/admission-routes/j-live-call-identity.json +1020 -0
- package/docs/rpc.md +66 -0
- package/package.json +6 -6
|
@@ -1,3 +1,3 @@
|
|
|
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
2
|
import{hasModeCrashHandler}from"./chunk-ZFIC2DZV.js";import{isStaleExtensionContextError}from"./chunk-UKSFF47T.js";import{envValue}from"./chunk-ISZ4EWIS.js";import{format}from"node:util";var OUTPUT_DELIVERY_LIMIT_MS=3e4,nativeLog=console.log,nativeStdoutWrite=process.stdout.write;async function captureStdout(print){if(console.log!==nativeLog||process.stdout.write!==nativeStdoutWrite)return{result:await print(),output:""};let chunks=[];console.log=(...args)=>{chunks.push(`${format(...args)}
|
|
3
|
-
`)},process.stdout.write=((chunk,encodingOrCallback,callback)=>(chunks.push(typeof chunk=="string"?chunk:Buffer.from(chunk).toString()),(typeof encodingOrCallback=="function"?encodingOrCallback:callback)?.(),!0));let printed=!1;try{let result=await print();return printed=!0,{result,output:chunks.join("")}}finally{console.log=nativeLog,process.stdout.write=nativeStdoutWrite,!printed&&chunks.length>0&&process.stdout.write(chunks.join(""))}}function delivered(stream,text){return stream.destroyed||stream.writableEnded?Promise.resolve():new Promise(resolve=>{let timer=setTimeout(resolve,OUTPUT_DELIVERY_LIMIT_MS);timer.unref();let done=()=>{clearTimeout(timer),resolve()};stream.once("error",done);try{stream.write(text,done)}catch{done()}})}async function exitAfterOutput(output="",code){await Promise.all([delivered(process.stdout,output),delivered(process.stderr,"")]),process.exit(code)}async function printThenExit(print,code){let{output}=await captureStdout(print);return exitAfterOutput(output,code)}import{close as closeInspector,url as inspectorUrl}from"node:inspector";var VM_DYNAMIC_IMPORT_CALLBACK_MISSING="ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING",INSPECTOR_IMPORT_FRAME="at importModuleDynamicallyCallback (node:internal/modules/esm/",INSPECTOR_TIMEOUT_FRAME=/\bat Timeout\._onTimeout \(<anonymous>:\d+:\d+\)/,RECOVER_INSPECTOR_VM_IMPORT=envValue("RECOVER_INSPECTOR_VM_IMPORT")==="1",INSPECTOR_VM_IMPORT_WARNING="Node Inspector dynamic import is unsupported; use require() or a target-side loader. Senpi kept running.";function hasInheritedInspectorOption(){return process.execArgv.some(argument=>argument.startsWith("--inspect"))||process.env.NODE_OPTIONS?.includes("--inspect")===!0}function releaseInheritedInspectorForChild(){inspectorUrl()!==void 0&&hasInheritedInspectorOption()&&closeInspector()}function isRecoverableInspectorVmImportError(error,origin){if(!RECOVER_INSPECTOR_VM_IMPORT||origin!=="unhandledRejection")return!1;try{return inspectorUrl()===void 0||typeof error!="object"||error===null||!("code"in error)||!("stack"in error)?!1:error.code===VM_DYNAMIC_IMPORT_CALLBACK_MISSING&&typeof error.stack=="string"&&error.stack.includes(INSPECTOR_IMPORT_FRAME)&&INSPECTOR_TIMEOUT_FRAME.test(error.stack)}catch{return!1}}var earlyRecoveryCount=0,earlyRecoveryInstalled=!1;function installEarlyInspectorVmImportRecovery(){if(!RECOVER_INSPECTOR_VM_IMPORT||earlyRecoveryInstalled)return;earlyRecoveryInstalled=!0;let listener=(error,origin)=>{let otherHandlerActive=hasModeCrashHandler("uncaughtException");if(isRecoverableInspectorVmImportError(error,origin)){otherHandlerActive||earlyRecoveryCount++;return}otherHandlerActive||isStaleExtensionContextError(error)||(console.error(error),process.exit(1))};process.on("uncaughtException",listener)}function consumeEarlyInspectorVmImportRecoveries(){let count=earlyRecoveryCount;return earlyRecoveryCount=0,count}var PACKAGE_COMMAND_ARGV={install:!0,remove:!0,update:!0,list:!0},PACKAGE_COMMAND_ALIAS="uninstall",CONFIG_COMMAND_ARGV="config",HOST_COMMAND_ARGV="host",SCHEDULE_COMMAND_ARGV="schedule";function isPackageCommandArgv(args){let command=args[0]??"";return Object.hasOwn(PACKAGE_COMMAND_ARGV,command)||command===PACKAGE_COMMAND_ALIAS}async function dispatchPackageCommand(args,runtimeOptions={}){if(!isPackageCommandArgv(args))return!1;let{handlePackageCommand}=await import("./package-manager-cli-
|
|
3
|
+
`)},process.stdout.write=((chunk,encodingOrCallback,callback)=>(chunks.push(typeof chunk=="string"?chunk:Buffer.from(chunk).toString()),(typeof encodingOrCallback=="function"?encodingOrCallback:callback)?.(),!0));let printed=!1;try{let result=await print();return printed=!0,{result,output:chunks.join("")}}finally{console.log=nativeLog,process.stdout.write=nativeStdoutWrite,!printed&&chunks.length>0&&process.stdout.write(chunks.join(""))}}function delivered(stream,text){return stream.destroyed||stream.writableEnded?Promise.resolve():new Promise(resolve=>{let timer=setTimeout(resolve,OUTPUT_DELIVERY_LIMIT_MS);timer.unref();let done=()=>{clearTimeout(timer),resolve()};stream.once("error",done);try{stream.write(text,done)}catch{done()}})}async function exitAfterOutput(output="",code){await Promise.all([delivered(process.stdout,output),delivered(process.stderr,"")]),process.exit(code)}async function printThenExit(print,code){let{output}=await captureStdout(print);return exitAfterOutput(output,code)}import{close as closeInspector,url as inspectorUrl}from"node:inspector";var VM_DYNAMIC_IMPORT_CALLBACK_MISSING="ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING",INSPECTOR_IMPORT_FRAME="at importModuleDynamicallyCallback (node:internal/modules/esm/",INSPECTOR_TIMEOUT_FRAME=/\bat Timeout\._onTimeout \(<anonymous>:\d+:\d+\)/,RECOVER_INSPECTOR_VM_IMPORT=envValue("RECOVER_INSPECTOR_VM_IMPORT")==="1",INSPECTOR_VM_IMPORT_WARNING="Node Inspector dynamic import is unsupported; use require() or a target-side loader. Senpi kept running.";function hasInheritedInspectorOption(){return process.execArgv.some(argument=>argument.startsWith("--inspect"))||process.env.NODE_OPTIONS?.includes("--inspect")===!0}function releaseInheritedInspectorForChild(){inspectorUrl()!==void 0&&hasInheritedInspectorOption()&&closeInspector()}function isRecoverableInspectorVmImportError(error,origin){if(!RECOVER_INSPECTOR_VM_IMPORT||origin!=="unhandledRejection")return!1;try{return inspectorUrl()===void 0||typeof error!="object"||error===null||!("code"in error)||!("stack"in error)?!1:error.code===VM_DYNAMIC_IMPORT_CALLBACK_MISSING&&typeof error.stack=="string"&&error.stack.includes(INSPECTOR_IMPORT_FRAME)&&INSPECTOR_TIMEOUT_FRAME.test(error.stack)}catch{return!1}}var earlyRecoveryCount=0,earlyRecoveryInstalled=!1;function installEarlyInspectorVmImportRecovery(){if(!RECOVER_INSPECTOR_VM_IMPORT||earlyRecoveryInstalled)return;earlyRecoveryInstalled=!0;let listener=(error,origin)=>{let otherHandlerActive=hasModeCrashHandler("uncaughtException");if(isRecoverableInspectorVmImportError(error,origin)){otherHandlerActive||earlyRecoveryCount++;return}otherHandlerActive||isStaleExtensionContextError(error)||(console.error(error),process.exit(1))};process.on("uncaughtException",listener)}function consumeEarlyInspectorVmImportRecoveries(){let count=earlyRecoveryCount;return earlyRecoveryCount=0,count}var PACKAGE_COMMAND_ARGV={install:!0,remove:!0,update:!0,list:!0},PACKAGE_COMMAND_ALIAS="uninstall",CONFIG_COMMAND_ARGV="config",HOST_COMMAND_ARGV="host",SCHEDULE_COMMAND_ARGV="schedule";function isPackageCommandArgv(args){let command=args[0]??"";return Object.hasOwn(PACKAGE_COMMAND_ARGV,command)||command===PACKAGE_COMMAND_ALIAS}async function dispatchPackageCommand(args,runtimeOptions={}){if(!isPackageCommandArgv(args))return!1;let{handlePackageCommand}=await import("./package-manager-cli-I62KMIWK.js");return await handlePackageCommand(args,runtimeOptions)}async function dispatchConfigCommand(args,runtimeOptions={}){if(args[0]!==CONFIG_COMMAND_ARGV)return!1;let{handleConfigCommand}=await import("./package-manager-cli-I62KMIWK.js");return await handleConfigCommand(args,runtimeOptions)}async function dispatchHostCommand(args){if(args[0]!==HOST_COMMAND_ARGV)return;if(args[1]==="session"){let{runHostSessionCommand}=await import("./host-session-command-4WRR5JSB.js");return await runHostSessionCommand(args.slice(2))}let{runHostCommand}=await import("./host-command-O3ALG2O3.js");return await runHostCommand(args.slice(1))}async function dispatchScheduleCommand(args){if(args[0]!==SCHEDULE_COMMAND_ARGV)return;let{runScheduleCommand}=await import("./schedule-command-YXGRN5CM.js");return await runScheduleCommand(args.slice(1))}export{captureStdout,exitAfterOutput,printThenExit,INSPECTOR_VM_IMPORT_WARNING,hasInheritedInspectorOption,releaseInheritedInspectorForChild,isRecoverableInspectorVmImportError,installEarlyInspectorVmImportRecovery,consumeEarlyInspectorVmImportRecoveries,CONFIG_COMMAND_ARGV,HOST_COMMAND_ARGV,SCHEDULE_COMMAND_ARGV,isPackageCommandArgv,dispatchPackageCommand,dispatchConfigCommand,dispatchHostCommand,dispatchScheduleCommand};
|
|
@@ -10,9 +10,9 @@ import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STALLED_STOP_MAX_MS_ENV,CHILD_STOP_TIMEO
|
|
|
10
10
|
`)}
|
|
11
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}}async function noteChildExit(context){let now=context.now??Date.now(),intent=await consumeStopIntent(context.generation,now).catch(()=>{}),outcome=describeExit(context,intent);if(outcome===void 0)return;let stall=await recentStall(context.generation,now,STOP_STALL_EVIDENCE_MAX_AGE_MS).catch(()=>{});await recordTerminalHostRecord(context.daemonDir,{at:new Date(now).toISOString(),...context.signal===null?{code:context.code??void 0}:{signal:context.signal},uptimeMs:Math.max(0,now-context.childStartedAt),kind:"rpc-host",generation:context.instanceId,...outcome,...stall?{stall:{driftMs:stall.driftMs,at:stall.at,attributedSessionId:stall.sessionId}}:{},...crashingRuntimeVersions()}).catch(()=>{})}function describeExit(context,intent){return intent!==void 0?{detection:"engine_stop",sender:intent.sender,...intent.chain?{chain:intent.chain}:{},reason:intent.reason,stopIntent:!0}:context.shutdown!==void 0?{detection:"engine_stop",sender:context.shutdown.supervisor,reason:context.shutdown.reason,stopIntent:!1}:classifyChildExit(context.code,context.signal).exitCode===0?void 0:{detection:context.signal===null||SELF_INFLICTED_SIGNALS.has(context.signal)?"supervisor":"external",stopIntent:!1}}var SELF_INFLICTED_SIGNALS=new Set(["SIGSEGV","SIGBUS","SIGABRT","SIGILL","SIGFPE","SIGTRAP","SIGSYS"]);async function noteEscalatedStop(daemonDir,instanceId,intent,now=Date.now()){await recordTerminalHostRecord(daemonDir,{at:new Date(now).toISOString(),signal:"SIGKILL",kind:"rpc-host",generation:instanceId,detection:"engine_stop",sender:intent.sender,...intent.chain?{chain:intent.chain}:{},reason:`${intent.reason}; supervisor_escalated`,stopIntent:!0}).catch(()=>{})}function hostCrashCleanupPaths(targets){let publicEntry=targets.platform==="win32"?[targets.publicSocket]:[];return targets.successor?publicEntry:[targets.generationPidFile,targets.settingsFile,...publicEntry,targets.pointerFile]}import{existsSync,readFileSync as readFileSync3,realpathSync}from"node:fs";import{access,readFile}from"node:fs/promises";import{dirname,resolve}from"node:path";import{fileURLToPath}from"node:url";function isCliModuleEntry(moduleUrl){let entry=process.argv[1];if(!entry)return!1;try{return fileURLToPath(moduleUrl)===realpathSync(entry)}catch{return!1}}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}}var existsAsync=path=>access(path).then(()=>!0,()=>!1);async function resolveCliMainPathAsync(modulePath=fileURLToPath(import.meta.url),bundled=isBundledNode){let declared=bundled?await resolveDeclaredCliEntryAsync(modulePath):void 0;if(declared!==void 0)return declared;let extension=modulePath.endsWith(".ts")?".ts":".js",unbundled=resolve(dirname(modulePath),"..","..",`cli-main${extension}`);return await existsAsync(unbundled)?unbundled:await resolveDeclaredCliEntryAsync(modulePath)??unbundled}async function resolveDeclaredCliEntryAsync(modulePath){let dir=dirname(modulePath);for(let depth=0;depth<8;depth+=1){let manifestPath=resolve(dir,"package.json");if(await existsAsync(manifestPath)){try{let declaredBin=JSON.parse(await readFile(manifestPath,"utf8")).bin,candidates=typeof declaredBin=="string"?[declaredBin]:Object.values(declaredBin??{});for(let candidate of candidates){let entry=resolve(dir,candidate);if(await existsAsync(entry))return entry}}catch{}return}let parent=dirname(dir);if(parent===dir)return;dir=parent}}import{watch}from"node:fs";import{createConnection,Socket}from"node:net";var MAX_CLASSIFIED_LINE_BYTES=64*1024,NEWLINE=10,ClientOccupancy=class{constructor(onAttach,ownInstance){this.clients=new Set,this.observers=new Set,this.attached=new Set,this.dependents=new Set,this.closed=!1,this.onAttach=onAttach,this.ownInstance=ownInstance}get attachedCount(){return this.attached.size}get unclassifiedCount(){return this.clients.size-this.observers.size-this.attached.size-this.dependents.size}admit(client){if(this.closed)return client.destroy(),!1;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()},depend=()=>{client.off("data",classify),pending=Buffer.alloc(0),this.observers.delete(client),this.dependents.add(client)},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)){this.ownInstance!==void 0&&requestOriginHostInstance(line)===this.ownInstance?depend():attach();return}this.observers.add(client)}pending.length>MAX_CLASSIFIED_LINE_BYTES&&attach()};return client.on("data",classify),!0}release(client){let unclassified=this.clients.has(client)&&!this.observers.has(client)&&!this.attached.has(client)&&!this.dependents.has(client);return this.clients.delete(client),this.observers.delete(client),this.attached.delete(client),this.dependents.delete(client),unclassified}destroyAll(){this.closed=!0;for(let client of this.clients)client.destroy()}};var SessionRunActivity=class{#running=new Set;#settling=new Map;#settleHoldMs;#now;#onSettleHoldExpired;constructor(options={}){this.#settleHoldMs=options.settleHoldMs??Number.POSITIVE_INFINITY,this.#now=options.now??Date.now,this.#onSettleHoldExpired=options.onSettleHoldExpired}observe(line){let event=parseHostEvent(line);if(event===void 0)return!1;if(event.type==="agent_start")this.#running.add(event.sessionId),this.#settling.delete(event.sessionId);else if(event.type==="agent_settled"&&event.reason!=="session_closed")this.#running.delete(event.sessionId),this.#settling.set(event.sessionId,this.#now());else if(event.type==="agent_settled"||event.type==="agent_idle"||event.type==="session_closed")this.#running.delete(event.sessionId),this.#settling.delete(event.sessionId);else return!1;return!0}get busySessions(){return this.#running.size}get settlingSessions(){let now=this.#now();for(let[sessionId,settledAt]of this.#settling){let heldMs=now-settledAt;heldMs<this.#settleHoldMs||(this.#settling.delete(sessionId),this.#onSettleHoldExpired?.(sessionId,heldMs))}return this.#settling.size}};function holdIdleExitForSettling(decision,runs){return decision==="exit"&&runs.settlingSessions>0?"idle":decision}function parseHostEvent(line){let event;try{event=JSON.parse(line)}catch{return}if(typeof event!="object"||event===null)return;let{type,sessionId,reason}=event;return typeof sessionId=="string"?{type,sessionId,reason}:void 0}import{randomBytes}from"node:crypto";import{hkdfSync}from"node:crypto";import{Duplex}from"node:stream";import{createCipheriv,createDecipheriv}from"node:crypto";var INTERNAL_RECORD_MAX=64*1024,RECORD_LIMIT=1n<<32n,InternalRecordCipher=class{constructor(key,direction,counter=0n){this.key=key,this.direction=direction,this.counter=counter}parameters(){if(this.counter<0n||this.counter>=RECORD_LIMIT)throw new Error("internal_record_counter_exhausted");let count=Buffer.alloc(8);return count.writeBigUInt64BE(this.counter),{nonce:Buffer.concat([Buffer.alloc(4),count]),aad:Buffer.concat([Buffer.from(this.direction),count])}}seal(plaintext){if(plaintext.length<1||plaintext.length>INTERNAL_RECORD_MAX)throw new Error("internal_record_length");let{nonce:nonce2,aad}=this.parameters(),cipher=createCipheriv("aes-256-gcm",this.key,nonce2);cipher.setAAD(aad);let body=Buffer.concat([cipher.update(plaintext),cipher.final(),cipher.getAuthTag()]),length=Buffer.alloc(4);return length.writeUInt32BE(body.length),this.counter++,Buffer.concat([length,body])}open(body){if(body.length<17||body.length>INTERNAL_RECORD_MAX+16)throw new Error("internal_record_length");let{nonce:nonce2,aad}=this.parameters(),decipher=createDecipheriv("aes-256-gcm",this.key,nonce2);decipher.setAAD(aad),decipher.setAuthTag(body.subarray(-16));let plaintext=decipher.update(body.subarray(0,-16)),final=decipher.final();return this.counter++,Buffer.concat([plaintext,final])}};function createInternalRecordStream(wire,key,clientNonce,serverNonce,role){let salt=Buffer.concat([clientNonce,serverNonce]),cipher=direction=>new InternalRecordCipher(Buffer.from(hkdfSync("sha256",key,salt,`senpi-rpc-internal ${direction}`,32)),direction);return new InternalRecordStream(wire,cipher(role==="client"?"c2s":"s2c"),cipher(role==="client"?"s2c":"c2s"))}var InternalRecordStream=class extends Duplex{constructor(wire,sender,receiver){super(),this.header=Buffer.alloc(4),this.headerUsed=0,this.bodyUsed=0,this.offset=0,this.wireDone=!1,this.wireClosed=!1,this.ended=!1,this.wire=wire,this.sender=sender,this.receiver=receiver,this.once("error",error=>{error.message.startsWith("internal_record")&&process.stderr.write(`senpi rpc: internal hop closed: ${error.message}
|
|
12
12
|
`)}),this.on("error",()=>{}),wire.on("data",chunk=>{wire.pause(),this.pending=chunk,this.offset=0,this.consume()}),wire.once("end",()=>{this.wireDone=!0,this.pending===void 0&&this.finish()}),wire.once("error",error=>this.destroy(error)),wire.once("close",()=>{this.wireDone=!0,this.wireClosed=!0,this.ended&&this.readableEnded?this.destroy():this.pending===void 0&&this.finish()}),this.once("end",()=>{this.wireClosed&&this.destroy()})}finish(){this.ended||(this.ended=!0,this.headerUsed!==0||this.body!==void 0?this.destroy(new Error("internal_record_truncated")):this.push(null))}consume(){try{let chunk=this.pending;if(!chunk)return;for(;this.offset<chunk.length;){if(!this.body){let n2=Math.min(4-this.headerUsed,chunk.length-this.offset);if(chunk.copy(this.header,this.headerUsed,this.offset,this.offset+n2),this.headerUsed+=n2,this.offset+=n2,this.headerUsed!==4)break;let length=this.header.readUInt32BE();if(length<17||length>INTERNAL_RECORD_MAX+16)throw new Error("internal_record_length");this.headerUsed=0,this.body=Buffer.alloc(length)}let n=Math.min(this.body.length-this.bodyUsed,chunk.length-this.offset);if(chunk.copy(this.body,this.bodyUsed,this.offset,this.offset+n),this.bodyUsed+=n,this.offset+=n,this.bodyUsed===this.body.length){let plaintext=this.receiver.open(this.body);if(this.body=void 0,this.bodyUsed=0,!this.push(plaintext)){this.offset===chunk.length&&(this.pending=void 0,this.wireDone&&this.finish());return}}}this.pending=void 0,this.wireDone?this.finish():this.wire.resume()}catch(cause){this.destroy(cause instanceof Error&&cause.message.startsWith("internal_record")?cause:new Error("internal_record_unverified",{cause}))}}_read(){this.pending?this.consume():this.wire.resume()}_write(chunk,_encoding,callback){let offset=0,next=error=>{if(error){callback(error);return}if(this.destroyed){callback(new Error("internal_hop_lost"));return}if(offset===chunk.length){callback();return}try{let end=Math.min(chunk.length,offset+INTERNAL_RECORD_MAX),record2=this.sender.seal(chunk.subarray(offset,end));offset=end,this.wire.write(record2,next)}catch(cause){callback(cause instanceof Error?cause:new Error("internal_record_invalid"))}};next()}_final(callback){this.wire.end(callback)}_destroy(error,callback){this.wire.destroy(),callback(error)}};var INTERNAL_LAUNCH_ID="internal";function proof(key,label,first,second){return rpcAuthProof(key,label,INTERNAL_LAUNCH_ID,first,second)}function matches(actual,expected){return rpcProofMatches(expected,actual)}function object(value){if(!isObject(value))throw new Error("auth_failed");return value}function isObject(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function nonce(value){if(typeof value!="string"||!RPC_AUTH_HEX.test(value))throw new Error("auth_failed");return value}var HOST_PRE_AUTH_BUDGET={maxBytes:8192,timeoutMs:2e3};async function handshake(socket,budget,run){let readBytes=0,ended=!1,rejectPending,fail=error=>{ended=!0,rejectPending?.(error),socket.destroy()},timer=budget.timeoutMs===void 0?void 0:setTimeout(()=>fail(new Error("internal_auth_timeout")),budget.timeoutMs);timer?.unref();let onError=error=>fail(error),onClose=()=>fail(new Error("internal_hop_lost"));socket.on("error",onError),socket.once("close",onClose);let read=()=>new Promise((resolve2,reject)=>{if(ended)return reject(new Error("internal_hop_lost"));let buffer=Buffer.alloc(0);rejectPending=cause=>{socket.off("data",data),reject(cause)};let data=chunk=>{let newline=chunk.indexOf(10),used=newline===-1?chunk.length:newline+1;if(readBytes+=used,readBytes>budget.maxBytes)return fail(new Error("internal_auth_oversized"));if(buffer=Buffer.concat([buffer,chunk.subarray(0,used)]),newline!==-1){socket.pause(),socket.off("data",data),rejectPending=void 0,used<chunk.length&&socket.unshift(chunk.subarray(used));try{resolve2(object(JSON.parse(buffer.toString("utf8"))))}catch{reject(new Error("auth_failed"))}}};socket.on("data",data),socket.resume()});try{return await run(read,frame=>new Promise((resolve2,reject)=>{socket.write(`${JSON.stringify(frame)}
|
|
13
|
-
`,error=>error?reject(error):resolve2())}))}catch(cause){throw socket.destroy(),cause}finally{timer&&clearTimeout(timer),socket.off("error",onError),socket.off("close",onClose)}}function connectInternalConnection(socket,key,options={}){return handshake(socket,{maxBytes:MAX_RPC_LINE_CHARACTERS,timeoutMs:options.timeoutMs},async(read,send)=>{let clientNonce=randomBytes(32).toString("hex"),[response]=await Promise.all([read(),send({id:"internal-protocol",type:"get_protocol_info",observe:!0,auth:{client_nonce:clientNonce}})]),data=response.data;if(!isObject(data)||!isObject(data.auth))throw new Error("host_identity_unproven");let auth=data.auth,serverNonce=nonce(auth.server_nonce);if(response.id!=="internal-protocol"||response.success!==!0||auth.launch_id!==INTERNAL_LAUNCH_ID||!matches(auth.server_proof,proof(key,"server",clientNonce,serverNonce)))throw new Error("host_identity_unproven");let[result]=await Promise.all([read(),send({id:"internal-auth",type:"authenticate",client_proof:proof(key,"client",serverNonce,clientNonce)})]);if(result.id!=="internal-auth"||result.command!=="authenticate"||result.success!==!0)throw new Error("auth_failed");return createInternalRecordStream(socket,key,Buffer.from(clientNonce,"hex"),Buffer.from(serverNonce,"hex"),"client")})}function acceptInternalConnection(socket,key,protocol={}){return handshake(socket,HOST_PRE_AUTH_BUDGET,async(read,send)=>{let refuse=async frame2=>{throw await send({id:frame2.id,type:"response",command:frame2.type,success:!1,error:"auth_required",errorCode:"auth_required"}),new Error("auth_required")},first=await read(),offered=isObject(first.auth)?first.auth.client_nonce:void 0;if(first.type!=="get_protocol_info"||typeof offered!="string"||!RPC_AUTH_HEX.test(offered))return refuse(first);let clientNonce=offered,serverNonce=randomBytes(32).toString("hex"),[frame]=await Promise.all([read(),send({id:first.id,type:"response",command:first.type,success:!0,data:{...protocol,capabilities:[...Array.isArray(protocol.capabilities)?protocol.capabilities:[],"socket_auth"],auth:{launch_id:INTERNAL_LAUNCH_ID,server_nonce:serverNonce,server_proof:proof(key,"server",clientNonce,serverNonce)}}})]);if(frame.type!=="authenticate")return refuse(frame);let valid=matches(frame.client_proof,proof(key,"client",serverNonce,clientNonce));if(await send({id:frame.id,type:"response",command:"authenticate",success:valid,...valid?{}:{error:"auth_failed",errorCode:"auth_failed"}}),!valid)throw new Error("auth_failed");return createInternalRecordStream(socket,key,Buffer.from(clientNonce,"hex"),Buffer.from(serverNonce,"hex"),"server")})}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 INTERNAL_OBSERVER_HANDSHAKE_MS=5e3,SupervisorActivity=class{constructor(options){this.options=options,this.decider=new IdleExitDecider(options.idleExitMs),this.runs=new SessionRunActivity({settleHoldMs:options.idleExitMs,onSettleHoldExpired:(sessionId,heldMs)=>supervisorLog(`session ${sessionId} settled ${heldMs} ms ago and its agent_settled extension handlers have not finished; idle exit no longer waits for them`)}),this.clients=new ClientOccupancy(()=>this.refresh(),options.instanceId),this.observerLink=createObserverLink({open:()=>this.connectObserver(),settled:options.settled,retryDelayMs:250,now:Date.now,setTimer:(run,ms)=>{let timer=setTimeout(run,ms);return timer.unref?.(),{cancel:()=>clearTimeout(timer)}}})}current(){return{connections:this.clients.attachedCount,activeTurns:activeTurnsForIdleDecision({healthy:this.observerLink.healthy(),unhealthySince:this.observerLink.unhealthySince(),now:Date.now(),unknownGraceMs:this.decider.idleExitMs,observedBusy:this.runs.busySessions})}}refresh(){let current=this.current();return(current.connections>0||current.activeTurns>0||this.clients.unclassifiedCount>0)&&this.options.onActivity?.(),holdIdleExitForSettling(this.decider.update(current),this.runs)}quiescent(){return this.observerLink.healthy()&&this.runs.busySessions===0&&this.runs.settlingSessions===0&&this.clients.attachedCount===0&&this.clients.unclassifiedCount===0}openObserver(){return this.observerLink.open()}stopObserver(){this.observerLink.stop(),this.observerSocket?.destroy()}async connectObserver(){let secret=this.options.internalSecret,next=createConnection(resolveSocketTransportAddress(this.options.internalSocket,process.platform,secret));secret&&sendSocketHandshake(next,secret);let stream;try{this.options.internalKey?stream=await connectInternalConnection(next,this.options.internalKey,{timeoutMs:INTERNAL_OBSERVER_HANDSHAKE_MS}):(await waitForConnect(next,5e3),stream=next)}catch(cause){throw next.destroy(),cause}return this.observerSocket=stream,attachJsonlLineReader(stream,line=>this.observeHostEvent(line),{maxLineLength:MAX_RPC_LINE_CHARACTERS}),{onLost:handler=>{let lost=()=>{handler(),this.options.onActivity?.()};stream.once("close",lost),stream.once("error",lost)}}}observeHostEvent(line){this.runs.observe(line)&&this.refresh()}},OWNER_EXIT_GRACE_MS=2e3,OWNER_PROBE_MAX_INTERVAL_MS=5e3,SupervisorOwner=class{constructor(generationDir){this.watchFailed=!1,this.nextProbeAt=0,this.probeIntervalMs=1e3,this.gone=!1,this.revision=0,this.stopped=!1,this.idle=new IdleExitDecider(OWNER_EXIT_GRACE_MS,()=>performance.now()),this.generationDir=generationDir}async start(fd){if(await this.reload(),!(fd===void 0||this.owner==null))try{let pipe=new Socket({fd,readable:!0,writable:!1});this.pipe=pipe;let bound=this.owner,failed=!1,eof=()=>{!failed&&!this.stopped&&sameHostOwner(this.owner,bound)&&(this.gone=!0)};pipe.once("end",eof),process.platform==="win32"&&pipe.once("close",eof),pipe.once("error",()=>{failed=!0,this.pipe===pipe&&(this.pipe=void 0),pipe.destroy()}),pipe.resume()}catch{this.pipe=void 0}}async reload(){let revision=++this.revision,next=await readHostOwner(this.generationDir);if(!(this.stopped||revision!==this.revision)){if(sameHostOwner(this.owner,next)||(this.pipe?.destroy(),this.pipe=void 0,this.gone=!1,this.nextProbeAt=0,this.probeIntervalMs=1e3,this.activity()),this.owner=next,next==null)this.watcher?.close(),this.watcher=void 0;else if(!this.watcher&&!this.watchFailed)try{this.watcher=watch(this.generationDir,(_event,filename)=>{filename?.toString()==="owner.json"&&this.reload()}),this.watcher.once("error",()=>{this.watchFailed=!0,this.watcher?.close(),this.watcher=void 0})}catch{this.watchFailed=!0}}}activity(){this.idle.update({connections:1,activeTurns:0})}async shouldExit(activity){this.watcher||await this.reload();let owner=this.owner,revision=this.revision;if(owner!=null&&(!this.pipe||process.ppid!==owner.pid)&&!this.gone&&performance.now()>=this.nextProbeAt){let gone=await hostOwnerGone(owner);if(this.stopped||revision!==this.revision)return!1;this.gone=gone,this.nextProbeAt=performance.now()+this.probeIntervalMs,this.probeIntervalMs=Math.min(OWNER_PROBE_MAX_INTERVAL_MS,this.probeIntervalMs*2)}let quiet=this.gone&&owner!=null&&activity.quiescent();if(this.idle.update({connections:quiet?0:1,activeTurns:0})!=="exit")return!1;let current=await readHostOwner(this.generationDir);return!this.stopped&&revision===this.revision&&sameHostOwner(owner,current)&&activity.quiescent()}stop(){this.stopped=!0,this.watcher?.close(),this.pipe?.destroy()}};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)})}import{readFile as readFile2}from"node:fs/promises";var SUPERSESSION_POLL_MS=1e3,ABSENT_CONFIRMATIONS=3,REPLACED_CONFIRMATIONS=3,IDENTITY_PROBE_TIMEOUT_MS=2e3;function watchForSupersession(endpoint,onLost){if(endpoint.identity===void 0)return endpoint.pointer===void 0?()=>{}:watchPointerSupersession(endpoint,endpoint.pointer,onLost);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 watchPointerSupersession(endpoint,pointer,onLost){let probe=endpoint.probeInstanceId??probeAnsweringInstance,readPointer=endpoint.readPointerInstanceId??pointerInstanceId,agreeingPolls=0,observing=!1,lost=!1,observe=async()=>{let named=await readPointer(pointer.file);return named===void 0||named===pointer.instanceId?!1:await probe(endpoint.path)===named},timer=setInterval(()=>{lost||observing||endpoint.settled?.()===!0||(observing=!0,observe().then(replaced=>{lost||endpoint.settled?.()===!0||(agreeingPolls=replaced?agreeingPolls+1:0,!(agreeingPolls<REPLACED_CONFIRMATIONS)&&(lost=!0,clearInterval(timer),onLost("replaced")))},()=>{agreeingPolls=0}).finally(()=>{observing=!1}))},SUPERSESSION_POLL_MS);return timer.unref?.(),()=>clearInterval(timer)}async function pointerInstanceId(file){try{let parsed=JSON.parse(await readFile2(file,"utf8")),instanceId=typeof parsed=="object"&&parsed!==null?Reflect.get(parsed,"instance_id"):void 0;return typeof instanceId=="string"&&instanceId!==""?instanceId:void 0}catch{return}}async function probeAnsweringInstance(path){let{isRecord:isRecord2,requestOnSocket}=await import("./host-socket-request-F2R5P34M.js"),answer=await requestOnSocket(path,{type:"get_protocol_info",[OBSERVE_REQUEST_FIELD]:!0},IDENTITY_PROBE_TIMEOUT_MS).catch(()=>{});return isRecord2(answer)&&typeof answer.instanceId=="string"?answer.instanceId:void 0}function ignore(){}var SupervisorDrain=class{constructor(child,shuttingDown,beginStopping=()=>{},relay){this.draining=!1,this.child=child,this.shuttingDown=shuttingDown,this.beginStopping=beginStopping,this.relay=relay}get active(){return this.draining}drain(){if(this.draining||this.shuttingDown())return;this.draining=!0,this.beginStopping(),supervisorLog("draining into the next generation");let graceMs=parseIdleExitMs(process.env[HANDOFF_GRACE_MS_ENV])??6e5;this.graceTimer=setTimeout(()=>{supervisorLog(JSON.stringify({event:"handoff_grace_expired",graceMs})),this.requestChildDrain()},graceMs),this.graceTimer.unref(),this.requestChildDrain()}stop(){this.graceTimer&&clearTimeout(this.graceTimer)}async acceptRequests(generation){let stop=watchDrainRequest(generation.drainRequestFile,request=>{supervisorLog(`drain requested (${request.reason})`),this.drain()});return await writeDrainWatch(generation.drainWatchFile,{pid:process.pid}).catch(cause=>{supervisorLog(`cannot advertise the drain request: ${errorMessage(cause)}`)}),stop}requestChildDrain(){let{child,relay}=this;if(!(child.pid===void 0||child.exitCode!==null||child.signalCode!==null)&&(relay&&writeDrainRequest(relay.file,{sender:relay.sender,reason:"supervisor_drain"}).catch(cause=>{supervisorLog(`could not relay the drain to the host: ${errorMessage(cause)}`)}),process.platform!=="win32"))try{process.kill(child.pid,"SIGUSR1")}catch(cause){supervisorLog(`could not ask the host to drain: ${errorMessage(cause)}`)}}};function drainOnPublicSocketLoss(path,identity,settled,drain,onReplaced,pointer){return watchForSupersession({path,identity,settled,...pointer&&{pointer}},loss=>{loss==="replaced"&&onReplaced(),supervisorLog(loss==="absent"?"the public socket entry is gone; nothing can reach this generation; draining":"another generation owns the public socket; draining this one"),drain.drain()})}var CHILD_IDENTITY_TICK_MS=500,CHILD_IDENTITY_READ_GAP_TICKS=10,CHILD_IDENTITY_READ_GAP_MAX_TICKS=120;function childLiveness(pid){try{return process.kill(pid,0),"alive"}catch(cause){return cause instanceof Error&&"code"in cause&&cause.code==="ESRCH"?"dead":"unknown"}}async function watchWin32ChildIdentity(child,shuttingDown,onGone){let pid=child.pid;if(pid===void 0)return()=>{};let readStartTime=()=>readProcessStartTime(pid,process.platform,1e3),baseline=await readStartTime().catch(()=>{}),adoptable=!0,suspect=!1,deadTicks=0,reading=!1,ended=!1,ticksUntilRead=0,readGapTicks=CHILD_IDENTITY_READ_GAP_TICKS,backOff=()=>{ticksUntilRead=readGapTicks,readGapTicks=Math.min(readGapTicks*2,CHILD_IDENTITY_READ_GAP_MAX_TICKS)},end=()=>{ended=!0,onGone()},settle=current=>{if(!ended){if(baseline===void 0){current!==void 0&&adoptable&&childLiveness(pid)==="alive"?baseline=current:backOff();return}if(current!==void 0&¤t!==baseline)return end();current===baseline&&(suspect=!1),backOff()}},timer=setInterval(()=>{if(ended||shuttingDown()||child.exitCode!==null||child.signalCode!==null)return;ticksUntilRead>0&&ticksUntilRead--;let liveness=childLiveness(pid);if(liveness==="dead"){if(deadTicks++,deadTicks>=2)return end();suspect=!0,adoptable=!1;return}(deadTicks>0||liveness==="unknown")&&(suspect=!0,adoptable=!1),deadTicks=0,!(!(baseline===void 0?adoptable:suspect)||reading||ticksUntilRead>0)&&(reading=!0,readStartTime().then(settle,()=>{ended||backOff()}).finally(()=>{reading=!1}))},CHILD_IDENTITY_TICK_MS);return timer.unref?.(),()=>{ended=!0,clearInterval(timer)}}import{randomBytes as randomBytes2}from"node:crypto";import{readFile as readFile4}from"node:fs/promises";import{join as join5}from"node:path";import{readFileSync as readFileSync4}from"node:fs";function readProcessStartTicks(pid,platform=process.platform){if(platform==="linux")try{let stat2=readFileSync4(`/proc/${pid}/stat`,"utf8"),ticks=stat2.slice(stat2.lastIndexOf(")")+2).split(" ")[19];return ticks!==void 0&&/^\d+$/.test(ticks)?ticks:void 0}catch{return}}async function compareRecordedStart(pid,recorded,platform,probe){if(platform==="linux"){if(recorded.ticks===void 0)return"unknown";let observed2=probe.ticks(pid);return observed2===void 0?"unknown":observed2===recorded.ticks?"same":"changed"}if(recorded.time===void 0)return"unknown";let observed=await probe.time(pid),recordedMs=processStartTimeMs(recorded.time),observedMs=observed===void 0?void 0:processStartTimeMs(observed);return recordedMs===void 0||observedMs===void 0?"unknown":sameProcessStartMs(recordedMs,observedMs)?"same":"changed"}import{randomUUID}from"node:crypto";import{realpathSync as realpathSync2}from"node:fs";import{mkdir,readFile as readFile3,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{join as join3}from"node:path";var INTERNAL_HOST_DIR_PREFIX="senpi-rpc-host-internal-",SHORT_TEMP_ROOT="/tmp";function internalHostDirRoots(){let primary=tmpdir();return canonicalPath(primary)!==canonicalPath(SHORT_TEMP_ROOT)?[primary,SHORT_TEMP_ROOT]:[Buffer.byteLength(primary)<Buffer.byteLength(SHORT_TEMP_ROOT)?primary:SHORT_TEMP_ROOT]}function canonicalPath(path){try{return realpathSync2(path)}catch{return path}}function internalHostDirRoot(name){for(let root of internalHostDirRoots())if(Buffer.byteLength(join3(root,name,"host.sock"))<=MAX_SOCKET_PATH_BYTES)return root;let tried=internalHostDirRoots().map(root=>join3(root,name,"host.sock"));throw new Error(`internal_socket_path_too_long: every candidate exceeds ${MAX_SOCKET_PATH_BYTES} bytes (${tried.join(", ")}); set TMPDIR to a shorter directory`)}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 name=`${INTERNAL_HOST_DIR_PREFIX}${randomUUID().slice(0,8)}`,dir=join3(internalHostDirRoot(name),name);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 CHILD_START_TIME_WAIT_MS=1e4,CHILD_START_TIME_UNHURRIED_MS=15e3;async function readChildStartTime(pid,timeoutMs){let identity=await readProcessIdentity(pid,process.platform,timeoutMs,void 0,"UTC");if(identity.kind==="error")throw identity.error;return identity.kind==="present"?identity.identity:void 0}async function recordChildPid(file,pid,running){try{await writeJsonAtomic(file,{pid,processStartTime:null});let processStartTime=await waitForStartTime(pid,CHILD_START_TIME_WAIT_MS,p=>readChildStartTime(p,1e3)).catch(()=>{})??await readChildStartTime(pid,CHILD_START_TIME_UNHURRIED_MS).catch(()=>{});if(processStartTime===void 0){supervisorLog(`host child pid ${pid} start time unreadable at recording`);return}if(!running())return;await writeJsonAtomic(file,{pid,processStartTime})}catch(cause){supervisorLog(`could not record the host child pid: ${errorMessage(cause)}`)}}async function readSettingsFile(settingsFile){try{return JSON.parse(await readFile3(settingsFile,"utf8"))}catch{return}}import{execFileSync}from"node:child_process";import{closeSync as closeSync2,constants,fstatSync,openSync,rmSync as rmSync2}from"node:fs";import{join as join4}from"node:path";import{closeSync}from"node:fs";import{Socket as Socket2}from"node:net";function watchHostLifetime(fd,gone,unavailable){let stopped=!1,bun=Reflect.get(globalThis,"Bun");if(typeof bun=="object"&&bun!==null&&typeof Reflect.get(bun,"file")=="function"){let reader=Reflect.get(bun,"file")(fd).stream().getReader();return(async()=>{try{for(;!stopped;){let{done}=await reader.read();if(done){stopped||gone();return}}}catch{stopped||unavailable()}})(),()=>{stopped||(stopped=!0,reader.cancel().catch(()=>{}).finally(()=>closeSync(fd)))}}let socket=new Socket2({fd,readable:!0,writable:!1});return socket.once("end",()=>{stopped||gone()}),socket.once("error",()=>{stopped||unavailable()}),socket.unref(),socket.resume(),()=>{stopped=!0,socket.destroy()}}var HOST_WATCH_LIFETIME_FIFO_ENV="SENPI_RPC_HOST_LIFETIME_FIFO";function prepareLifetimeBinding(hopDir,platform=process.platform){if(platform!=="linux")return{};let path=join4(hopDir,"lifetime.fifo");try{return rmSync2(path,{force:!0}),execFileSync("mkfifo",["-m","600",path],{stdio:"ignore"}),openSync(path,constants.O_RDWR),{lifetimeFifo:path}}catch{return{}}}function armLifetimeBinding(binding,gone,unavailable,platform=process.platform){if(platform==="win32")return;let fifo=platform==="linux"?openFifoReadEnd(binding.lifetimeFifo):void 0;if(fifo!==void 0)return binding.lifetimeFd!==void 0&&closeSync2(binding.lifetimeFd),watchHostLifetime(fifo,()=>gone("supervisor lifetime FIFO closed"),unavailable);if(binding.lifetimeFd!==void 0)return watchHostLifetime(binding.lifetimeFd,()=>gone("supervisor stdin lifetime closed"),unavailable)}function openFifoReadEnd(path){if(path===void 0)return;let fd;try{fd=openSync(path,constants.O_RDONLY|constants.O_NONBLOCK|constants.O_NOFOLLOW)}catch{return}let stat2=fstatSync(fd),owned=typeof process.getuid!="function"||stat2.uid===process.getuid();if(stat2.isFIFO()&&owned&&(stat2.mode&511)===384)return fd;closeSync2(fd)}async function recordedOwnerStartTime(dir){if(dir!==void 0)try{let owner=JSON.parse(await readFile4(join5(dir,".owner"),"utf8")),start=owner!==null&&typeof owner=="object"?Reflect.get(owner,"processStartTime"):void 0;return typeof start=="string"?start:void 0}catch{return}}async function prepareInternalHop(daemonDir){let created=await createInternalSocketPath(daemonDir),internal={...created,secretPath:created.secretPath??socketSecretPath(created.socket)},internalSecret=process.platform==="win32"?await createSocketSecret(internal.secretPath):void 0,internalKey=process.platform==="win32"?void 0:randomBytes2(32);return{internal,internalSocket:internal.socket,internalSecret,internalKey,...internalKey&&internal.dir!==void 0?prepareLifetimeBinding(internal.dir):{},supervisorStart:internalKey?{time:await recordedOwnerStartTime(internal.dir),ticks:readProcessStartTicks(process.pid)}:void 0,transport:{...internalSecret?{internalSecret}:{},...internalKey?{internalKey}:{}}}}import childProcess from"node:child_process";import{Socket as Socket4}from"node:net";import{extname}from"node:path";function runtimeExecArgv(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}import{rmSync as rmSync3}from"node:fs";import{rm}from"node:fs/promises";import{Socket as Socket3}from"node:net";var HOST_WATCH_BACKSTOP_INTERVAL_MS=3e4,HOST_WATCH_PPID_INTERVAL_MS=250,HOST_WATCH_PPID_BACKUP_INTERVAL_MS=5e3,HOST_WATCH_IDENTITY_INTERVAL_MS=5e3,HOST_WATCH_IDENTITY_ONLY_INTERVAL_MS=1e3,HOST_WATCH_SPAWNING_IDENTITY_INTERVAL_MS=6e4;function supervisorPoll(ppid,recorded,fire,stopped){let stopPpid,ppidIntervalMs;return{arm(intervalMs){stopped()||ppid===void 0||ppidIntervalMs===intervalMs||(stopPpid?.(),ppidIntervalMs=intervalMs,stopPpid=watchPpid(ppid,recorded,fire,intervalMs))},soleInterval:recorded.ticks!==void 0||recorded.time!==void 0?HOST_WATCH_IDENTITY_ONLY_INTERVAL_MS:HOST_WATCH_PPID_INTERVAL_MS,stop:()=>stopPpid?.()}}function watchPpid(supervisorPid,recorded,fire,intervalMs){if(supervisorPid===process.pid)return()=>{};let linux=process.platform==="linux",comparable=linux?recorded.ticks!==void 0:recorded.time!==void 0,identityEveryTicks=Math.max(1,Math.round((linux?HOST_WATCH_IDENTITY_INTERVAL_MS:HOST_WATCH_SPAWNING_IDENTITY_INTERVAL_MS)/intervalMs)),probe={ticks:pid=>readProcessStartTicks(pid),time:pid=>readProcessStartTime(pid,process.platform,1e3)},ticks=0,stopped=!1,probing=!1,timer=setInterval(()=>{if(!stopped){if(!processAlive(supervisorPid)){fire(`supervisor pid ${supervisorPid} is gone`);return}ticks+=1,!(!comparable||probing||ticks%identityEveryTicks!==0)&&(probing=!0,compareRecordedStart(supervisorPid,recorded,process.platform,probe).then(result=>{!stopped&&result==="changed"&&fire(`supervisor pid ${supervisorPid} start time changed`)},()=>{}).finally(()=>{probing=!1}))}},intervalMs);return timer.unref?.(),()=>{stopped=!0,clearInterval(timer)}}function processAlive(pid){try{return process.kill(pid,0),!0}catch(cause){return!(cause instanceof Error&&"code"in cause&&cause.code==="ESRCH")}}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_PSTART_ENV="SENPI_RPC_HOST_WATCH_PSTART",HOST_WATCH_PSTART_TICKS_ENV="SENPI_RPC_HOST_WATCH_PSTART_TICKS",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 ppid=parsePositiveInteger(env[HOST_WATCH_PPID_ENV]),fd=process.platform!=="win32"&&ppid!==void 0?void 0:parsePositiveInteger(env[HOST_WATCH_FD_ENV]);if(fd===void 0&&ppid===void 0)return;let scratchDir=env[HOST_SCRATCH_DIR_ENV],cleanupPaths=env[HOST_CLEANUP_PATHS_ENV]?.split(`
|
|
13
|
+
`,error=>error?reject(error):resolve2())}))}catch(cause){throw socket.destroy(),cause}finally{timer&&clearTimeout(timer),socket.off("error",onError),socket.off("close",onClose)}}function connectInternalConnection(socket,key,options={}){return handshake(socket,{maxBytes:MAX_RPC_LINE_CHARACTERS,timeoutMs:options.timeoutMs},async(read,send)=>{let clientNonce=randomBytes(32).toString("hex"),[response]=await Promise.all([read(),send({id:"internal-protocol",type:"get_protocol_info",observe:!0,auth:{client_nonce:clientNonce}})]),data=response.data;if(!isObject(data)||!isObject(data.auth))throw new Error("host_identity_unproven");let auth=data.auth,serverNonce=nonce(auth.server_nonce);if(response.id!=="internal-protocol"||response.success!==!0||auth.launch_id!==INTERNAL_LAUNCH_ID||!matches(auth.server_proof,proof(key,"server",clientNonce,serverNonce)))throw new Error("host_identity_unproven");let[result]=await Promise.all([read(),send({id:"internal-auth",type:"authenticate",client_proof:proof(key,"client",serverNonce,clientNonce)})]);if(result.id!=="internal-auth"||result.command!=="authenticate"||result.success!==!0)throw new Error("auth_failed");return createInternalRecordStream(socket,key,Buffer.from(clientNonce,"hex"),Buffer.from(serverNonce,"hex"),"client")})}function acceptInternalConnection(socket,key,protocol={}){return handshake(socket,HOST_PRE_AUTH_BUDGET,async(read,send)=>{let refuse=async frame2=>{throw await send({id:frame2.id,type:"response",command:frame2.type,success:!1,error:"auth_required",errorCode:"auth_required"}),new Error("auth_required")},first=await read(),offered=isObject(first.auth)?first.auth.client_nonce:void 0;if(first.type!=="get_protocol_info"||typeof offered!="string"||!RPC_AUTH_HEX.test(offered))return refuse(first);let clientNonce=offered,serverNonce=randomBytes(32).toString("hex"),[frame]=await Promise.all([read(),send({id:first.id,type:"response",command:first.type,success:!0,data:{...protocol,capabilities:[...Array.isArray(protocol.capabilities)?protocol.capabilities:[],"socket_auth"],auth:{launch_id:INTERNAL_LAUNCH_ID,server_nonce:serverNonce,server_proof:proof(key,"server",clientNonce,serverNonce)}}})]);if(frame.type!=="authenticate")return refuse(frame);let valid=matches(frame.client_proof,proof(key,"client",serverNonce,clientNonce));if(await send({id:frame.id,type:"response",command:"authenticate",success:valid,...valid?{}:{error:"auth_failed",errorCode:"auth_failed"}}),!valid)throw new Error("auth_failed");return createInternalRecordStream(socket,key,Buffer.from(clientNonce,"hex"),Buffer.from(serverNonce,"hex"),"server")})}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 INTERNAL_OBSERVER_HANDSHAKE_MS=5e3,SupervisorActivity=class{constructor(options){this.options=options,this.decider=new IdleExitDecider(options.idleExitMs),this.runs=new SessionRunActivity({settleHoldMs:options.idleExitMs,onSettleHoldExpired:(sessionId,heldMs)=>supervisorLog(`session ${sessionId} settled ${heldMs} ms ago and its agent_settled extension handlers have not finished; idle exit no longer waits for them`)}),this.clients=new ClientOccupancy(()=>this.refresh(),options.instanceId),this.observerLink=createObserverLink({open:()=>this.connectObserver(),settled:options.settled,retryDelayMs:250,now:Date.now,setTimer:(run,ms)=>{let timer=setTimeout(run,ms);return timer.unref?.(),{cancel:()=>clearTimeout(timer)}}})}current(){return{connections:this.clients.attachedCount,activeTurns:activeTurnsForIdleDecision({healthy:this.observerLink.healthy(),unhealthySince:this.observerLink.unhealthySince(),now:Date.now(),unknownGraceMs:this.decider.idleExitMs,observedBusy:this.runs.busySessions})}}refresh(){let current=this.current();return(current.connections>0||current.activeTurns>0||this.clients.unclassifiedCount>0)&&this.options.onActivity?.(),holdIdleExitForSettling(this.decider.update(current),this.runs)}quiescent(){return this.observerLink.healthy()&&this.runs.busySessions===0&&this.runs.settlingSessions===0&&this.clients.attachedCount===0&&this.clients.unclassifiedCount===0}openObserver(){return this.observerLink.open()}stopObserver(){this.observerLink.stop(),this.observerSocket?.destroy()}async connectObserver(){let secret=this.options.internalSecret,next=createConnection(resolveSocketTransportAddress(this.options.internalSocket,process.platform,secret));secret&&sendSocketHandshake(next,secret);let stream;try{this.options.internalKey?stream=await connectInternalConnection(next,this.options.internalKey,{timeoutMs:INTERNAL_OBSERVER_HANDSHAKE_MS}):(await waitForConnect(next,5e3),stream=next)}catch(cause){throw next.destroy(),cause}return this.observerSocket=stream,attachJsonlLineReader(stream,line=>this.observeHostEvent(line),{maxLineLength:MAX_RPC_LINE_CHARACTERS}),{onLost:handler=>{let lost=()=>{handler(),this.options.onActivity?.()};stream.once("close",lost),stream.once("error",lost)}}}observeHostEvent(line){this.runs.observe(line)&&this.refresh()}},OWNER_EXIT_GRACE_MS=2e3,OWNER_PROBE_MAX_INTERVAL_MS=5e3,SupervisorOwner=class{constructor(generationDir){this.watchFailed=!1,this.nextProbeAt=0,this.probeIntervalMs=1e3,this.gone=!1,this.revision=0,this.stopped=!1,this.idle=new IdleExitDecider(OWNER_EXIT_GRACE_MS,()=>performance.now()),this.generationDir=generationDir}async start(fd){if(await this.reload(),!(fd===void 0||this.owner==null))try{let pipe=new Socket({fd,readable:!0,writable:!1});this.pipe=pipe;let bound=this.owner,failed=!1,eof=()=>{!failed&&!this.stopped&&sameHostOwner(this.owner,bound)&&(this.gone=!0)};pipe.once("end",eof),process.platform==="win32"&&pipe.once("close",eof),pipe.once("error",()=>{failed=!0,this.pipe===pipe&&(this.pipe=void 0),pipe.destroy()}),pipe.resume()}catch{this.pipe=void 0}}async reload(){let revision=++this.revision,next=await readHostOwner(this.generationDir);if(!(this.stopped||revision!==this.revision)){if(sameHostOwner(this.owner,next)||(this.pipe?.destroy(),this.pipe=void 0,this.gone=!1,this.nextProbeAt=0,this.probeIntervalMs=1e3,this.activity()),this.owner=next,next==null)this.watcher?.close(),this.watcher=void 0;else if(!this.watcher&&!this.watchFailed)try{this.watcher=watch(this.generationDir,(_event,filename)=>{filename?.toString()==="owner.json"&&this.reload()}),this.watcher.once("error",()=>{this.watchFailed=!0,this.watcher?.close(),this.watcher=void 0})}catch{this.watchFailed=!0}}}activity(){this.idle.update({connections:1,activeTurns:0})}async shouldExit(activity){this.watcher||await this.reload();let owner=this.owner,revision=this.revision;if(owner!=null&&(!this.pipe||process.ppid!==owner.pid)&&!this.gone&&performance.now()>=this.nextProbeAt){let gone=await hostOwnerGone(owner);if(this.stopped||revision!==this.revision)return!1;this.gone=gone,this.nextProbeAt=performance.now()+this.probeIntervalMs,this.probeIntervalMs=Math.min(OWNER_PROBE_MAX_INTERVAL_MS,this.probeIntervalMs*2)}let quiet=this.gone&&owner!=null&&activity.quiescent();if(this.idle.update({connections:quiet?0:1,activeTurns:0})!=="exit")return!1;let current=await readHostOwner(this.generationDir);return!this.stopped&&revision===this.revision&&sameHostOwner(owner,current)&&activity.quiescent()}stop(){this.stopped=!0,this.watcher?.close(),this.pipe?.destroy()}};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)})}import{readFile as readFile2}from"node:fs/promises";var SUPERSESSION_POLL_MS=1e3,ABSENT_CONFIRMATIONS=3,REPLACED_CONFIRMATIONS=3,IDENTITY_PROBE_TIMEOUT_MS=2e3;function watchForSupersession(endpoint,onLost){if(endpoint.identity===void 0)return endpoint.pointer===void 0?()=>{}:watchPointerSupersession(endpoint,endpoint.pointer,onLost);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 watchPointerSupersession(endpoint,pointer,onLost){let probe=endpoint.probeInstanceId??probeAnsweringInstance,readPointer=endpoint.readPointerInstanceId??pointerInstanceId,agreeingPolls=0,observing=!1,lost=!1,observe=async()=>{let named=await readPointer(pointer.file);return named===void 0||named===pointer.instanceId?!1:await probe(endpoint.path)===named},timer=setInterval(()=>{lost||observing||endpoint.settled?.()===!0||(observing=!0,observe().then(replaced=>{lost||endpoint.settled?.()===!0||(agreeingPolls=replaced?agreeingPolls+1:0,!(agreeingPolls<REPLACED_CONFIRMATIONS)&&(lost=!0,clearInterval(timer),onLost("replaced")))},()=>{agreeingPolls=0}).finally(()=>{observing=!1}))},SUPERSESSION_POLL_MS);return timer.unref?.(),()=>clearInterval(timer)}async function pointerInstanceId(file){try{let parsed=JSON.parse(await readFile2(file,"utf8")),instanceId=typeof parsed=="object"&&parsed!==null?Reflect.get(parsed,"instance_id"):void 0;return typeof instanceId=="string"&&instanceId!==""?instanceId:void 0}catch{return}}async function probeAnsweringInstance(path){let{isRecord:isRecord2,requestOnSocket}=await import("./host-socket-request-F2R5P34M.js"),answer=await requestOnSocket(path,{type:"get_protocol_info",[OBSERVE_REQUEST_FIELD]:!0},IDENTITY_PROBE_TIMEOUT_MS).catch(()=>{});return isRecord2(answer)&&typeof answer.instanceId=="string"?answer.instanceId:void 0}function ignore(){}var SupervisorDrain=class{constructor(child,shuttingDown,beginStopping=()=>{},relay){this.draining=!1,this.child=child,this.shuttingDown=shuttingDown,this.beginStopping=beginStopping,this.relay=relay}get active(){return this.draining}drain(){if(this.draining||this.shuttingDown())return;this.draining=!0,this.beginStopping(),supervisorLog("draining into the next generation");let graceMs=parseIdleExitMs(process.env[HANDOFF_GRACE_MS_ENV])??6e5;this.graceTimer=setTimeout(()=>{supervisorLog(JSON.stringify({event:"handoff_grace_expired",graceMs})),this.requestChildDrain()},graceMs),this.graceTimer.unref(),this.requestChildDrain()}stop(){this.graceTimer&&clearTimeout(this.graceTimer)}async acceptRequests(generation){let stop=watchDrainRequest(generation.drainRequestFile,request=>{supervisorLog(`drain requested (${request.reason})`),this.drain()});return await writeDrainWatch(generation.drainWatchFile,{pid:process.pid}).catch(cause=>{supervisorLog(`cannot advertise the drain request: ${errorMessage(cause)}`)}),stop}requestChildDrain(){let{child,relay}=this;if(!(child.pid===void 0||child.exitCode!==null||child.signalCode!==null)&&(relay&&writeDrainRequest(relay.file,{sender:relay.sender,reason:"supervisor_drain"}).catch(cause=>{supervisorLog(`could not relay the drain to the host: ${errorMessage(cause)}`)}),process.platform!=="win32"))try{process.kill(child.pid,"SIGUSR1")}catch(cause){supervisorLog(`could not ask the host to drain: ${errorMessage(cause)}`)}}};function drainOnPublicSocketLoss(path,identity,settled,drain,onReplaced,pointer){return watchForSupersession({path,identity,settled,...pointer&&{pointer}},loss=>{loss==="replaced"&&onReplaced(),supervisorLog(loss==="absent"?"the public socket entry is gone; nothing can reach this generation; draining":"another generation owns the public socket; draining this one"),drain.drain()})}var CHILD_IDENTITY_TICK_MS=500,CHILD_IDENTITY_READ_GAP_TICKS=10,CHILD_IDENTITY_READ_GAP_MAX_TICKS=120;function childLiveness(pid){try{return process.kill(pid,0),"alive"}catch(cause){return cause instanceof Error&&"code"in cause&&cause.code==="ESRCH"?"dead":"unknown"}}async function watchWin32ChildIdentity(child,shuttingDown,onGone){let pid=child.pid;if(pid===void 0)return()=>{};let readStartTime=()=>readProcessStartTime(pid,process.platform,1e3),baseline=await readStartTime().catch(()=>{}),adoptable=!0,suspect=!1,deadTicks=0,reading=!1,ended=!1,ticksUntilRead=0,readGapTicks=CHILD_IDENTITY_READ_GAP_TICKS,backOff=()=>{ticksUntilRead=readGapTicks,readGapTicks=Math.min(readGapTicks*2,CHILD_IDENTITY_READ_GAP_MAX_TICKS)},end=()=>{ended=!0,onGone()},settle=current=>{if(!ended){if(baseline===void 0){current!==void 0&&adoptable&&childLiveness(pid)==="alive"?baseline=current:backOff();return}if(current!==void 0&¤t!==baseline)return end();current===baseline&&(suspect=!1),backOff()}},timer=setInterval(()=>{if(ended||shuttingDown()||child.exitCode!==null||child.signalCode!==null)return;ticksUntilRead>0&&ticksUntilRead--;let liveness=childLiveness(pid);if(liveness==="dead"){if(deadTicks++,deadTicks>=2)return end();suspect=!0,adoptable=!1;return}(deadTicks>0||liveness==="unknown")&&(suspect=!0,adoptable=!1),deadTicks=0,!(!(baseline===void 0?adoptable:suspect)||reading||ticksUntilRead>0)&&(reading=!0,readStartTime().then(settle,()=>{ended||backOff()}).finally(()=>{reading=!1}))},CHILD_IDENTITY_TICK_MS);return timer.unref?.(),()=>{ended=!0,clearInterval(timer)}}import{randomBytes as randomBytes2}from"node:crypto";import{readFile as readFile4}from"node:fs/promises";import{join as join5}from"node:path";import{readFileSync as readFileSync4}from"node:fs";function readProcessStartTicks(pid,platform=process.platform){if(platform==="linux")try{let stat=readFileSync4(`/proc/${pid}/stat`,"utf8"),ticks=stat.slice(stat.lastIndexOf(")")+2).split(" ")[19];return ticks!==void 0&&/^\d+$/.test(ticks)?ticks:void 0}catch{return}}async function compareRecordedStart(pid,recorded,platform,probe){if(platform==="linux"){if(recorded.ticks===void 0)return"unknown";let observed2=probe.ticks(pid);return observed2===void 0?"unknown":observed2===recorded.ticks?"same":"changed"}if(recorded.time===void 0)return"unknown";let observed=await probe.time(pid),recordedMs=processStartTimeMs(recorded.time),observedMs=observed===void 0?void 0:processStartTimeMs(observed);return recordedMs===void 0||observedMs===void 0?"unknown":sameProcessStartMs(recordedMs,observedMs)?"same":"changed"}import{randomUUID}from"node:crypto";import{realpathSync as realpathSync2}from"node:fs";import{mkdir,readFile as readFile3,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{join as join3}from"node:path";var INTERNAL_HOST_DIR_PREFIX="senpi-rpc-host-internal-",SHORT_TEMP_ROOT="/tmp";function internalHostDirRoots(){let primary=tmpdir();return canonicalPath(primary)!==canonicalPath(SHORT_TEMP_ROOT)?[primary,SHORT_TEMP_ROOT]:[Buffer.byteLength(primary)<Buffer.byteLength(SHORT_TEMP_ROOT)?primary:SHORT_TEMP_ROOT]}function canonicalPath(path){try{return realpathSync2(path)}catch{return path}}function internalHostDirRoot(name){for(let root of internalHostDirRoots())if(Buffer.byteLength(join3(root,name,"host.sock"))<=MAX_SOCKET_PATH_BYTES)return root;let tried=internalHostDirRoots().map(root=>join3(root,name,"host.sock"));throw new Error(`internal_socket_path_too_long: every candidate exceeds ${MAX_SOCKET_PATH_BYTES} bytes (${tried.join(", ")}); set TMPDIR to a shorter directory`)}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 name=`${INTERNAL_HOST_DIR_PREFIX}${randomUUID().slice(0,8)}`,dir=join3(internalHostDirRoot(name),name);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 CHILD_START_TIME_WAIT_MS=1e4,CHILD_START_TIME_UNHURRIED_MS=15e3;async function readChildStartTime(pid,timeoutMs){let identity=await readProcessIdentity(pid,process.platform,timeoutMs,void 0,"UTC");if(identity.kind==="error")throw identity.error;return identity.kind==="present"?identity.identity:void 0}async function recordChildPid(file,pid,running){try{await writeJsonAtomic(file,{pid,processStartTime:null});let processStartTime=await waitForStartTime(pid,CHILD_START_TIME_WAIT_MS,p=>readChildStartTime(p,1e3)).catch(()=>{})??await readChildStartTime(pid,CHILD_START_TIME_UNHURRIED_MS).catch(()=>{});if(processStartTime===void 0){supervisorLog(`host child pid ${pid} start time unreadable at recording`);return}if(!running())return;await writeJsonAtomic(file,{pid,processStartTime})}catch(cause){supervisorLog(`could not record the host child pid: ${errorMessage(cause)}`)}}async function readSettingsFile(settingsFile){try{return JSON.parse(await readFile3(settingsFile,"utf8"))}catch{return}}import{execFileSync}from"node:child_process";import{closeSync as closeSync2,constants,fstatSync,openSync,rmSync as rmSync2}from"node:fs";import{join as join4}from"node:path";import{closeSync}from"node:fs";import{Socket as Socket2}from"node:net";function watchHostLifetime(fd,gone,unavailable){let stopped=!1,bun=Reflect.get(globalThis,"Bun");if(typeof bun=="object"&&bun!==null&&typeof Reflect.get(bun,"file")=="function"){let reader=Reflect.get(bun,"file")(fd).stream().getReader();return(async()=>{try{for(;!stopped;){let{done}=await reader.read();if(done){stopped||gone();return}}}catch{stopped||unavailable()}})(),()=>{stopped||(stopped=!0,reader.cancel().catch(()=>{}).finally(()=>closeSync(fd)))}}let socket=new Socket2({fd,readable:!0,writable:!1});return socket.once("end",()=>{stopped||gone()}),socket.once("error",()=>{stopped||unavailable()}),socket.unref(),socket.resume(),()=>{stopped=!0,socket.destroy()}}var HOST_WATCH_LIFETIME_FIFO_ENV="SENPI_RPC_HOST_LIFETIME_FIFO";function prepareLifetimeBinding(hopDir,platform=process.platform){if(platform!=="linux")return{};let path=join4(hopDir,"lifetime.fifo");try{return rmSync2(path,{force:!0}),execFileSync("mkfifo",["-m","600",path],{stdio:"ignore"}),openSync(path,constants.O_RDWR),{lifetimeFifo:path}}catch{return{}}}function armLifetimeBinding(binding,gone,unavailable,platform=process.platform){if(platform==="win32")return;let fifo=platform==="linux"?openFifoReadEnd(binding.lifetimeFifo):void 0;if(fifo!==void 0)return binding.lifetimeFd!==void 0&&closeSync2(binding.lifetimeFd),watchHostLifetime(fifo,()=>gone("supervisor lifetime FIFO closed"),unavailable);if(binding.lifetimeFd!==void 0)return watchHostLifetime(binding.lifetimeFd,()=>gone("supervisor stdin lifetime closed"),unavailable)}function openFifoReadEnd(path){if(path===void 0)return;let fd;try{fd=openSync(path,constants.O_RDONLY|constants.O_NONBLOCK|constants.O_NOFOLLOW)}catch{return}let stat=fstatSync(fd),owned=typeof process.getuid!="function"||stat.uid===process.getuid();if(stat.isFIFO()&&owned&&(stat.mode&511)===384)return fd;closeSync2(fd)}async function recordedOwnerStartTime(dir){if(dir!==void 0)try{let owner=JSON.parse(await readFile4(join5(dir,".owner"),"utf8")),start=owner!==null&&typeof owner=="object"?Reflect.get(owner,"processStartTime"):void 0;return typeof start=="string"?start:void 0}catch{return}}async function prepareInternalHop(daemonDir){let created=await createInternalSocketPath(daemonDir),internal={...created,secretPath:created.secretPath??socketSecretPath(created.socket)},internalSecret=process.platform==="win32"?await createSocketSecret(internal.secretPath):void 0,internalKey=process.platform==="win32"?void 0:randomBytes2(32);return{internal,internalSocket:internal.socket,internalSecret,internalKey,...internalKey&&internal.dir!==void 0?prepareLifetimeBinding(internal.dir):{},supervisorStart:internalKey?{time:await recordedOwnerStartTime(internal.dir),ticks:readProcessStartTicks(process.pid)}:void 0,transport:{...internalSecret?{internalSecret}:{},...internalKey?{internalKey}:{}}}}import childProcess from"node:child_process";import{Socket as Socket4}from"node:net";import{extname}from"node:path";function runtimeExecArgv(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}import{rmSync as rmSync3}from"node:fs";import{rm}from"node:fs/promises";import{Socket as Socket3}from"node:net";var HOST_WATCH_BACKSTOP_INTERVAL_MS=3e4,HOST_WATCH_PPID_INTERVAL_MS=250,HOST_WATCH_PPID_BACKUP_INTERVAL_MS=5e3,HOST_WATCH_IDENTITY_INTERVAL_MS=5e3,HOST_WATCH_IDENTITY_ONLY_INTERVAL_MS=1e3,HOST_WATCH_SPAWNING_IDENTITY_INTERVAL_MS=6e4;function supervisorPoll(ppid,recorded,fire,stopped){let stopPpid,ppidIntervalMs;return{arm(intervalMs){stopped()||ppid===void 0||ppidIntervalMs===intervalMs||(stopPpid?.(),ppidIntervalMs=intervalMs,stopPpid=watchPpid(ppid,recorded,fire,intervalMs))},soleInterval:recorded.ticks!==void 0||recorded.time!==void 0?HOST_WATCH_IDENTITY_ONLY_INTERVAL_MS:HOST_WATCH_PPID_INTERVAL_MS,stop:()=>stopPpid?.()}}function watchPpid(supervisorPid,recorded,fire,intervalMs){if(supervisorPid===process.pid)return()=>{};let linux=process.platform==="linux",comparable=linux?recorded.ticks!==void 0:recorded.time!==void 0,identityEveryTicks=Math.max(1,Math.round((linux?HOST_WATCH_IDENTITY_INTERVAL_MS:HOST_WATCH_SPAWNING_IDENTITY_INTERVAL_MS)/intervalMs)),probe={ticks:pid=>readProcessStartTicks(pid),time:pid=>readProcessStartTime(pid,process.platform,1e3)},ticks=0,stopped=!1,probing=!1,timer=setInterval(()=>{if(!stopped){if(!processAlive(supervisorPid)){fire(`supervisor pid ${supervisorPid} is gone`);return}ticks+=1,!(!comparable||probing||ticks%identityEveryTicks!==0)&&(probing=!0,compareRecordedStart(supervisorPid,recorded,process.platform,probe).then(result=>{!stopped&&result==="changed"&&fire(`supervisor pid ${supervisorPid} start time changed`)},()=>{}).finally(()=>{probing=!1}))}},intervalMs);return timer.unref?.(),()=>{stopped=!0,clearInterval(timer)}}function processAlive(pid){try{return process.kill(pid,0),!0}catch(cause){return!(cause instanceof Error&&"code"in cause&&cause.code==="ESRCH")}}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_PSTART_ENV="SENPI_RPC_HOST_WATCH_PSTART",HOST_WATCH_PSTART_TICKS_ENV="SENPI_RPC_HOST_WATCH_PSTART_TICKS",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 ppid=parsePositiveInteger(env[HOST_WATCH_PPID_ENV]),fd=process.platform!=="win32"&&ppid!==void 0?void 0:parsePositiveInteger(env[HOST_WATCH_FD_ENV]);if(fd===void 0&&ppid===void 0)return;let scratchDir=env[HOST_SCRATCH_DIR_ENV],cleanupPaths=env[HOST_CLEANUP_PATHS_ENV]?.split(`
|
|
14
14
|
`).filter(Boolean),publicSocket=env[HOST_PUBLIC_SOCKET_ENV],daemonDir=env[HOST_DAEMON_DIR_ENV],instanceId=env[HOST_INSTANCE_ID_ENV];return{fd,ppid,...env[HOST_WATCH_PSTART_ENV]?{processStartTime:env[HOST_WATCH_PSTART_ENV]}:{},...env[HOST_WATCH_PSTART_TICKS_ENV]?{processStartTicks:env[HOST_WATCH_PSTART_TICKS_ENV]}:{},...env[HOST_WATCH_LIFETIME_FIFO_ENV]?{lifetimeFifo:env[HOST_WATCH_LIFETIME_FIFO_ENV]}:{},scratchDir:scratchDir===void 0||scratchDir===""?void 0:scratchDir,cleanupPaths,publicSocket:publicSocket===""?void 0:publicSocket,...daemonDir&&instanceId?{daemonDir,instanceId}:{}}}function readHostWatchdogConfigFromBrandEnv(env=process.env){return readHostWatchdogConfig({[HOST_WATCH_FD_ENV]:env[HOST_WATCH_FD_ENV]??envValue("RPC_HOST_WATCH_FD",env),[HOST_WATCH_PPID_ENV]:env[HOST_WATCH_PPID_ENV]??envValue("RPC_HOST_WATCH_PPID",env),[HOST_WATCH_PSTART_ENV]:env[HOST_WATCH_PSTART_ENV]??envValue("RPC_HOST_WATCH_PSTART",env),[HOST_WATCH_PSTART_TICKS_ENV]:env[HOST_WATCH_PSTART_TICKS_ENV]??envValue("RPC_HOST_WATCH_PSTART_TICKS",env),[HOST_WATCH_LIFETIME_FIFO_ENV]:env[HOST_WATCH_LIFETIME_FIFO_ENV]??envValue("RPC_HOST_LIFETIME_FIFO",env),[HOST_SCRATCH_DIR_ENV]:env[HOST_SCRATCH_DIR_ENV]??envValue("RPC_HOST_SCRATCH_DIR",env),[HOST_PUBLIC_SOCKET_ENV]:env[HOST_PUBLIC_SOCKET_ENV]??envValue("RPC_HOST_PUBLIC_SOCKET",env),[HOST_CLEANUP_PATHS_ENV]:env[HOST_CLEANUP_PATHS_ENV]??envValue("RPC_HOST_CLEANUP_PATHS",env),[HOST_DAEMON_DIR_ENV]:env[HOST_DAEMON_DIR_ENV],[HOST_INSTANCE_ID_ENV]:env[HOST_INSTANCE_ID_ENV]})}var WATCH_ENV_SUFFIXES=["RPC_HOST_WATCH_FD","RPC_HOST_WATCH_PPID","RPC_HOST_WATCH_PSTART","RPC_HOST_WATCH_PSTART_TICKS","RPC_HOST_LIFETIME_FIFO","RPC_HOST_SCRATCH_DIR","RPC_HOST_PUBLIC_SOCKET","RPC_HOST_CLEANUP_PATHS"];function consumeHostWatchdogEnv(env=process.env){let config=readHostWatchdogConfigFromBrandEnv(env);return scrubHostWatchdogEnv(env),config}function scrubHostWatchdogEnv(env=process.env){for(let suffix of WATCH_ENV_SUFFIXES)for(let name of[`SENPI_${suffix}`,...brandEnvNames(suffix)])delete env[name]}function armHostWatchdog(config,onSupervisorGone){if(!config)return()=>{};let stopped=!1,fired=!1,fire=reason=>{if(stopped||fired)return;fired=!0,disarm(),config.daemonDir!==void 0&&config.instanceId!==void 0&&recordHostCrash(config.daemonDir,{at:new Date().toISOString(),uptimeMs:Math.round(process.uptime()*1e3),kind:"rpc-host-watchdog",generation:config.instanceId,reason});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=()=>{stopped=!0;for(let stop of disarmers.splice(0))stop()},poll=supervisorPoll(config.ppid,{ticks:config.processStartTicks,time:config.processStartTime},fire,()=>stopped);disarmers.push(()=>poll.stop());let pollWanted=!1,pipeLive=!1;config.fd!==void 0&&(pipeLive=watchFdForEof(config.fd,fire,disarmers,()=>{pipeLive=!1,pollWanted&&poll.arm(poll.soleInterval)}));let fallback=()=>{pollWanted=!0,poll.arm(pipeLive?HOST_WATCH_PPID_BACKUP_INTERVAL_MS:poll.soleInterval)},stopLifetime;try{stopLifetime=armLifetimeBinding(config,fire,fallback)}catch{stopLifetime=void 0}return stopLifetime!==void 0?(disarmers.push(stopLifetime),poll.arm(HOST_WATCH_BACKSTOP_INTERVAL_MS)):fallback(),disarm}function watchFdForEof(fd,fire,disarmers,onUnavailable){let stream,streamFailed=!1,fired=!1,fireOnce=reason=>{fired||(fired=!0,fire(reason))};try{stream=new Socket3({fd,readable:!0,writable:!1})}catch{return!1}stream.resume();let onEnd=()=>fireOnce(`supervisor pipe fd ${fd} closed`),onClose=()=>{streamFailed||onEnd()},onError=()=>{streamFailed=!0,onUnavailable()};return stream.once("end",onEnd),process.platform==="win32"&&stream.once("close",onClose),stream.once("error",onError),disarmers.push(()=>{stream.off("end",onEnd),stream.off("close",onClose),stream.off("error",onError),stream.destroy()}),!0}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"?rmSync3(path,{recursive:!0,force:!0,maxRetries:10,retryDelay:100}):await rm(path,{recursive:!0,force:!0})}catch{}}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,ownerFd,presenterBootstrapFd,bindSocket,replaceIdentity;for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg==="--mcp-presenter-fd"&&argv[index+1]==="4"){presenterBootstrapFd=4,index++;continue}if(arg==="--owner-fd"&&index+1<argv.length){if(ownerFd=Number(argv[++index]),!Number.isSafeInteger(ownerFd)||ownerFd<3)return;continue}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||ownerFd===presenterBootstrapFd&&ownerFd!==void 0?void 0:{socket,hostArgs,childCommand,childArgs,agentDir,ownerFd,bindSocket,replaceIdentity,presenterBootstrapFd}}var OWNER_WATCH_FD=3,ownerPipes=new Set;function keepOwnerPipe(child){let pipe=child.stdio[OWNER_WATCH_FD];if(!(pipe instanceof Socket4))throw new Error("RPC owner pipe was not inherited");ownerPipes.add(pipe),pipe.on("error",()=>{}),pipe.unref(),child.once("exit",()=>{ownerPipes.delete(pipe),pipe.destroy()})}function parseSocketIdentity(value){let match=/^(\d+):(\d+)$/.exec(value);return match?{dev:Number(match[1]),ino:Number(match[2])}:void 0}function resolveHostChildLaunch(launch,internalSocket,compiled=isBunBinary){return launch.childCommand?{command:launch.childCommand,args:[...launch.childArgs??[],"--listen",`unix://${internalSocket}`]}:{command:process.execPath,args:[...compiled?[]:[...runtimeExecArgv(),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}}var HOST_CHILD_WATCH_FD=3;function spawnHostChild(options){let{launch,internalSocket,internal,internalSecret,publicSocket}=options,childLaunch=spawnableChildLaunch(resolveHostChildLaunch(launch,internalSocket)),bootstrap=launch.presenterBootstrapFd!==void 0&&!childLaunch.shell;bootstrap&&childLaunch.args.push("--mcp-presenter-fd","4");let child=spawnWithPrivateFds((command,args,options2)=>childProcess.spawn(command,args,options2),childLaunch.command,childLaunch.args,{env:{...process.env,...launch.agentDir?{SENPI_CODING_AGENT_DIR:launch.agentDir}:{},[HOST_DAEMON_DIR_ENV]:options.daemonDir,[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_WATCH_FD_ENV]:String(HOST_CHILD_WATCH_FD),[HOST_WATCH_PPID_ENV]:String(process.pid),[HOST_WATCH_PSTART_ENV]:options.supervisorStart?.time,[HOST_WATCH_PSTART_TICKS_ENV]:options.supervisorStart?.ticks,[HOST_WATCH_LIFETIME_FIFO_ENV]:options.lifetimeFifo,...internal.dir?{[HOST_SCRATCH_DIR_ENV]:internal.dir}:{},[SOCKET_SECRET_FILE_ENV]:process.platform==="win32"&&internalSecret?internal.secretPath:void 0,[INTERNAL_KEY_STDIN_ENV]:options.internalKey?"1":void 0,[HOST_CLEANUP_PATHS_ENV]:options.cleanupPaths.join(`
|
|
15
|
-
`),...process.platform==="win32"?{}:{[HOST_PUBLIC_SOCKET_ENV]:publicSocket}},shell:childLaunch.shell,stdio:[process.platform==="win32"?"ignore":"pipe","ignore","inherit","pipe",...bootstrap?["pipe"]:[]],windowsHide:!0},{final:!0});if(launch.presenterBootstrapFd!==void 0){let fd=launch.presenterBootstrapFd;import("./mcp-presenter-bootstrap-XXJSBV7V.js").then(({presenterBootstrapStream,relayPresenterBootstrap})=>{let upstream=presenterBootstrapStream(fd);if(upstream&&bootstrap)return relayPresenterBootstrap(upstream,child);upstream?.destroy(),child.stdio[4]?.destroy()}).catch(()=>child.stdio[4]?.destroy())}return options.internalKey&&(child.stdin?.on("error",()=>{}),child.stdin?.write(options.internalKey)),child}import{chmod,mkdir as mkdir2,
|
|
15
|
+
`),...process.platform==="win32"?{}:{[HOST_PUBLIC_SOCKET_ENV]:publicSocket}},shell:childLaunch.shell,stdio:[process.platform==="win32"?"ignore":"pipe","ignore","inherit","pipe",...bootstrap?["pipe"]:[]],windowsHide:!0},{final:!0});if(launch.presenterBootstrapFd!==void 0){let fd=launch.presenterBootstrapFd;import("./mcp-presenter-bootstrap-XXJSBV7V.js").then(({presenterBootstrapStream,relayPresenterBootstrap})=>{let upstream=presenterBootstrapStream(fd);if(upstream&&bootstrap)return relayPresenterBootstrap(upstream,child);upstream?.destroy(),child.stdio[4]?.destroy()}).catch(()=>child.stdio[4]?.destroy())}return options.internalKey&&(child.stdin?.on("error",()=>{}),child.stdin?.write(options.internalKey)),child}import{chmod,lstat,mkdir as mkdir2,unlink}from"node:fs/promises";import{createConnection as createConnection2,createServer}from"node:net";import{dirname as dirname2}from"node:path";import{StringDecoder}from"node:string_decoder";function proxyWithAdmission(client,internal,admission,auth){let reply=chunk=>write(client,auth?auth.response(chunk.toString()):chunk),pending=[],refused=new Set,protocols=0,refusals=Promise.resolve(),unsubscribe=admission.onStop(()=>(refusals=refusePending(),refusals));async function refusePending(){let ids=pending.splice(0);for(let id of ids)refused.add(id);try{for(let id of ids)await reply(serializeJsonLine(hostStoppingResponse(id,"open_session",admission)))}catch{fail()}}client.once("close",()=>{unsubscribe(),internal?.destroy()});let fail=()=>{internal?.destroy(),client.destroy()};client.once("error",fail),internal?.once("error",()=>{admission.stopping||fail()}),requests().catch(()=>{admission.stopping||fail()}),internal&&responses(internal).catch(()=>{admission.stopping||fail()});async function requests(){for await(let line of lines(auth?.input??client,MAX_RPC_LINE_CHARACTERS)){if(line===void 0){await reply(serializeJsonLine({type:"response",command:"parse",success:!1,error:`RPC input line exceeds ${MAX_RPC_LINE_CHARACTERS} characters.`}));continue}let request=record(line);admission.stopping&&request?.type==="get_protocol_info"?await reply(serializeJsonLine({id:request.id,type:"response",command:request.type,success:!0,data:admission.protocol()})):admission.stopping&&(request?.type==="open_session"||!internal)?await reply(serializeJsonLine(hostStoppingResponse(request?.id,String(request?.type??"parse"),admission))):internal&&(request?.type==="open_session"&&pending.push(request.id),request?.type==="get_protocol_info"&&protocols++,await write(internal,`${line}
|
|
16
16
|
`))}internal?.end()}async function responses(source){let fragments=[];for await(let chunk of source){let newline=chunk.lastIndexOf(10);if(newline===-1){fragments.push(chunk);continue}let complete=chunk.subarray(0,newline+1);if(!auth&&pending.length===0&&protocols===0&&refused.size===0){client.cork();let written;try{for(let fragment of fragments)client.write(fragment);written=write(client,complete)}finally{client.uncork()}await written}else{let batch=fragments.length>0?Buffer.concat([...fragments,complete]):complete;await reply(filterReplies(batch))}fragments=newline+1<chunk.length?[chunk.subarray(newline+1)]:[]}fragments.length>0&&await reply(filterReplies(Buffer.concat(fragments))),await refusals,client.end(()=>client.destroy())}function filterReplies(batch){if(pending.length===0&&protocols===0&&refused.size===0)return batch;let output=[],changed=!1;for(let start=0;start<batch.length;){let newline=batch.indexOf(10,start),end=newline===-1?batch.length:newline+1,line=batch.subarray(start,end);start=end;let response=line.includes('"open_session"')||line.includes('"get_protocol_info"')?record(line.toString("utf8")):void 0;if(response?.type==="response"&&response.command==="open_session"){if(refused.has(response.id)){changed=!0;continue}let index=pending.indexOf(response.id);index!==-1&&pending.splice(index,1)}if(response?.type==="response"&&response.command==="get_protocol_info"&&(protocols=Math.max(0,protocols-1),response.success===!0)){isRecord(response.data)&&admission.observe(response.data),output.push(Buffer.from(serializeJsonLine({...response,data:admission.protocol()}))),changed=!0;continue}output.push(line)}return changed?Buffer.concat(output):batch}}async function write(socket,line){await new Promise((resolve2,reject)=>{socket.write(line,error=>error?reject(error):resolve2())})}async function*lines(socket,limit){let decoder=new StringDecoder("utf8"),buffer="",discarding=!1;for await(let chunk of socket){let text=typeof chunk=="string"?chunk:decoder.write(chunk),offset=0;for(;offset<text.length;){let newline=text.indexOf(`
|
|
17
17
|
`,offset),end=newline===-1?text.length:newline;if(discarding||(buffer.length+end-offset>limit?(buffer="",discarding=!0,yield void 0):buffer+=text.slice(offset,end)),newline===-1)break;discarding||(yield buffer),buffer="",discarding=!1,offset=newline+1}}buffer+=decoder.end(),!discarding&&buffer.length>0&&(yield buffer)}function record(line){try{let value=JSON.parse(line);return isRecord(value)?value:void 0}catch{return}}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{randomBytes as randomBytes3}from"node:crypto";import{Duplex as Duplex2,PassThrough}from"node:stream";var PREAUTH_BYTES=8*1024,PublicRpcConnection=class{get stream(){return this.view??=this.duplex(),this.view}constructor(socket,endpoint,requireToken=process.env.SENPI_RPC_REQUIRE_TOKEN==="1"){this.input=new PassThrough,this.raw=new PassThrough,this.bytes=0,this.active=!1,this.failed=!1,this.first=!0,this.protocolPending=!1,this.socket=socket,this.endpoint=endpoint,this.requireToken=requireToken,socket.pause(),this.timer=setTimeout(()=>{this.requireToken?this.drop("pre-auth deadline"):!this.active&&!this.failed&&this.challenge===void 0&&this.grace()},SOCKET_HANDSHAKE_TIMEOUT_MS);let detach=attachJsonlLineReader(this.raw,line=>this.line(line),{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>this.active?socket.destroy():this.drop("first frame over the line limit")});socket.on("error",()=>socket.destroy()),socket.once("close",()=>{!this.active&&!this.failed&&!this.requireToken&&!this.first&&this.grace(),clearTimeout(this.timer),detach(),this.raw.destroy(),this.input.end()}),socket.once("end",()=>this.raw.end()),this.input.on("drain",()=>socket.resume()),socket.on("data",chunk=>{for(let offset=0;offset<chunk.length&&!this.failed;){let newline=chunk.indexOf(10,offset),end=newline===-1?chunk.length:newline+1,segment=chunk.subarray(offset,end);if(this.active||(this.bytes+=segment.length),!this.active&&this.requireToken&&this.bytes>PREAUTH_BYTES){this.drop("pre-auth budget exceeded");return}this.raw.write(segment),offset=end}}),endpoint.ready.then(()=>{socket.destroyed||socket.resume()},()=>this.drop("key publication failed"))}duplex(){let input=this.input,stream=new Duplex2({read:()=>input.resume(),write:(chunk,_encoding,callback)=>{let output=this.response(chunk.toString());output===""?callback():this.socket.write(output,callback)},final:callback=>this.socket.end(callback),destroy:(error,callback)=>{this.socket.destroy(),callback(error)}});return input.on("data",chunk=>{stream.push(chunk)||input.pause()}),input.once("end",()=>{stream.push(null),stream.destroy()}),input.readableEnded&&stream.destroy(),stream}line(line){if(this.failed||this.socket.destroyed)return;let request;try{request=authRecord(JSON.parse(line))}catch{}if(!this.active){if(this.first&&request?.type==="get_protocol_info"){this.first=!1,this.protocolPending=!0;let nonce2=authRecord(request.auth)?.client_nonce;if(nonce2!==void 0){if(typeof nonce2!="string"||!RPC_AUTH_HEX.test(nonce2)){this.refuse(request,"auth_failed");return}this.challenge={id:request.id,client:nonce2,server:randomBytes3(32).toString("hex")}}else if(this.requireToken){this.refuse(request,"auth_required");return}else this.grace();this.forward(line);return}if(this.first=!1,request?.type==="authenticate"){let c=this.challenge;if(!c||!rpcProofMatches(rpcAuthProof(this.endpoint.key,"client",this.endpoint.launchId,c.server,c.client),request.client_proof)){this.refuse(request,"auth_failed");return}this.active=!0,clearTimeout(this.timer),this.socket.write(serializeJsonLine({id:request.id,type:"response",command:"authenticate",success:!0}));return}if(this.requireToken){this.refuse(request,"auth_required");return}this.grace()}this.forward(line)}forward(line){this.input.write(`${line}
|
|
18
18
|
`)||this.socket.pause()}grace(){this.active=!0,clearTimeout(this.timer),process.stderr.write(`senpi rpc host: served a client that did not prove the endpoint key on ${this.endpoint.endpoint} (deprecated, refused from the next release; see docs/rpc.md#authentication)
|
|
@@ -20,4 +20,4 @@ import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STALLED_STOP_MAX_MS_ENV,CHILD_STOP_TIMEO
|
|
|
20
20
|
`)}drop(reason){this.failed||(this.failed=!0,clearTimeout(this.timer),this.logDrop(reason),this.socket.destroy())}refuse(request,code){this.failed=!0,clearTimeout(this.timer),this.logDrop(code),this.socket.end(serializeJsonLine({id:request?.id,type:"response",command:request?.type??"parse",success:!1,error:code,errorCode:code}),()=>this.socket.destroy())}response(chunk){if(this.failed)return"";if(this.active&&!this.protocolPending)return chunk;let output="";for(let line of chunk.split(`
|
|
21
21
|
`)){if(!line)continue;let record2=authRecord(JSON.parse(line));if(record2?.type==="response"&&record2.command==="get_protocol_info"&&record2.success===!0){this.protocolPending=!1;let data=authRecord(record2.data)??{},capabilities=Array.isArray(data.capabilities)?data.capabilities:[],c=this.challenge;output+=serializeJsonLine({...record2,data:{...data,capabilities:[...new Set([...capabilities,RPC_AUTH_CAPABILITY])],...c&&record2.id===c.id?{auth:{launch_id:this.endpoint.launchId,server_nonce:c.server,server_proof:rpcAuthProof(this.endpoint.key,"server",this.endpoint.launchId,c.client,c.server)}}:{}}})}else(this.active||!this.requireToken)&&(output+=`${line}
|
|
22
22
|
`)}return output}};function createPublicProxy(options){let{internalSocket,internalSecret,publicSecret,clients}=options;return createServer(client=>{let auth=options.publicEndpoint?new PublicRpcConnection(client,options.publicEndpoint):void 0,accept=async()=>{if(!clients.admit(client))return;client.pause();let internal=options.admission.stopping?void 0:createConnection2(resolveSocketTransportAddress(internalSocket,process.platform,internalSecret));internal&&internalSecret&&sendSocketHandshake(internal,internalSecret);let detach=()=>{clients.release(client)&&options.onAdmit?.(),options.onDetach(),internal?.destroy(),client.destroy()};client.once("close",detach),client.once("error",detach);try{let hop=internal&&options.internalKey?await connectInternalConnection(internal,options.internalKey):internal;if(client.destroyed){hop?.destroy();return}proxyWithAdmission(client,hop,options.admission,auth),auth||client.resume()}catch{detach()}};publicSecret?authenticateSocket(client,publicSecret,()=>{accept()}):accept()})}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})}}var INTERNAL_READINESS_PROBE_MS=1e4;async function waitForListener(socketPath,timeoutMs,secret,internalKey){let deadline=performance.now()+timeoutMs;for(;performance.now()<=deadline;){let probeMs=Math.max(1,Math.min(INTERNAL_READINESS_PROBE_MS,deadline-performance.now())),probe=await canConnect(socketPath,secret,internalKey,probeMs);if(probe==="ready")return;if(probe==="silent")throw new Error(`${socketPath}: host accepted the internal hop but did not answer within ${Math.round(probeMs)}ms`);if(probe!=="refused")throw new Error(`${socketPath}: ${probe.unproven}`);await new Promise(resolveDelay=>setTimeout(resolveDelay,50))}throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`)}async function canConnect(socketPath,secret,internalKey,probeMs){if(internalKey){let socket=createConnection2(resolveSocketTransportAddress(socketPath,process.platform,secret)),accepted=!1,expired=!1;socket.once("connect",()=>{accepted=!0});let timer=setTimeout(()=>{expired=!0,socket.destroy()},probeMs);timer.unref();let outcome=ready=>ready?"ready":accepted&&expired?"silent":"refused";try{let stream=await connectInternalConnection(socket,internalKey);return outcome(await new Promise(resolve2=>{let settle=ready=>{stream.destroy(),resolve2(ready)};stream.once("error",()=>settle(!1)),stream.once("close",()=>settle(!1)),attachJsonlLineReader(stream,line=>{try{let response=JSON.parse(line);response.id==="internal-ready"&&settle(response.success===!0)}catch{settle(!1)}},{maxLineLength:MAX_RPC_LINE_CHARACTERS}),stream.write(`{"id":"internal-ready","type":"get_protocol_info","observe":true}
|
|
23
|
-
`)}))}catch(cause){socket.destroy();let reason=cause instanceof Error?cause.message:"";return reason==="host_identity_unproven"||reason==="auth_failed"?{unproven:reason}:outcome(!1)}finally{clearTimeout(timer)}}return new Promise(resolve2=>{let socket=createConnection2(resolveSocketTransportAddress(socketPath,process.platform,secret));secret&&sendSocketHandshake(socket,secret);let settle=connected=>{socket.destroy(),resolve2(connected?"ready":"refused")};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1))})}async function stampOf(socketPath){try{let entry=await stat(socketPath,{bigint:!0});return{dev:entry.dev,ino:entry.ino,ctimeNs:entry.ctimeNs,socket:entry.isSocket()}}catch(cause){if(cause instanceof Error&&"code"in cause&&cause.code==="ENOENT")return;throw cause}}var sameStamp=(a,b)=>a.dev===b.dev&&a.ino===b.ino&&a.ctimeNs===b.ctimeNs;async function prepareSocketPath(socketPath,hooks={}){if(process.platform==="win32"||socketPath.startsWith("\0"))return;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 mkdir2(dirname2(socketPath),{recursive:!0,mode:448});let probed=await stampOf(socketPath);if(probed===void 0)return;let inUse=evidence=>new Error(`${socketPath}: address already in use by a live server (${evidence}).`);if(!probed.socket)throw inUse("the entry is not a socket");let state=await(hooks.listenerState??socketEntryListenerState)(socketPath);if(state.verdict==="gone")return;if(state.verdict==="live")throw inUse(state.evidence);await hooks.afterStaleProbe?.();let current=await stampOf(socketPath);if(current!==void 0){if(!sameStamp(probed,current))throw inUse("the entry changed after it was probed");try{await unlink(socketPath)}catch(cause){if(cause instanceof Error&&"code"in cause&&cause.code==="ENOENT")return;throw cause}}}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())})}import{rm as rm2}from"node:fs/promises";var LOOP_LAG_ERROR_MS_ENV="SENPI_RPC_LOOP_LAG_ERROR_MS",DEFAULT_LOOP_LAG_ERROR_MS=5e3;function loopLagErrorMs(env=process.env){return parseIdleExitMs(env[LOOP_LAG_ERROR_MS_ENV])??DEFAULT_LOOP_LAG_ERROR_MS}var STALL_WAIT_SLICE_MS=5e3;async function waitOutStalledChild(options){let{child,generation,signalledAt}=options,maxMs=childStalledStopMaxMs(),untilAt=signalledAt+maxMs,stalled=()=>hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:STOP_STALL_EVIDENCE_MAX_AGE_MS}).catch(()=>!1),waited=0;try{for(;Date.now()<untilAt&&await stalled();){waited===0&&supervisorLog(`host child is stalled; waiting up to ${maxMs}ms (${CHILD_STALLED_STOP_MAX_MS_ENV})`),await writeStopProgress(generation,{at:new Date().toISOString(),phase:"waiting_stalled_child",untilAt:new Date(untilAt).toISOString()}).catch(()=>{});let slice=Math.min(STALL_WAIT_SLICE_MS,untilAt-Date.now()),exited=await options.waitForExit(child,slice);if(waited+=slice,exited)break}}finally{await clearStopProgress(generation)}return waited}var WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS=2e3;function supervisorSender(instanceId){return{pid:process.pid,kind:"supervisor",generation:instanceId}}function childExited(child){return child.exitCode!==null||child.signalCode!==null}async function performShutdown(context,reason,exitCode){let{state,child}=context;state.shuttingDown=!0,state.shutdownReason=reason,context.admission.stop();let childStopStarted=!1,hardExit;try{context.drain.stop(),writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`),childStopStarted=!0,await stopChild(context,reason),await state.childExitRecorded,await state.startupComplete.then(void 0,()=>{}),context.stopWatchers(),await context.admission.flush(),context.activity.clients.destroyAll(),process.platform==="win32"&&(hardExit=setTimeout(()=>process.exit(exitCode),WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS)),context.drain.active||await shieldSocketDuringClose(context.publicSocket,()=>closeServer(context.server)),context.internalDir&&await rm2(context.internalDir,{recursive:!0,force:!0}),context.activity.stopObserver(),state.publicSocketOwned&&process.platform!=="win32"&&await unlinkOwnedSocket(context.publicSocket,state.publicSocketIdentity,supervisorLog),await releaseGeneration(context.paths,{instanceId:context.instanceId,pid:process.pid,superseded:state.endpointReplaced})}catch(cause){supervisorLog(`shutdown failed for host child pid ${child.pid??"unknown"}: ${errorMessage(cause)}`),exitCode=1;try{childStopStarted||await reapChildAfterFailure(child),await state.childExitRecorded}catch(reapCause){supervisorLog(`shutdown recovery failed for host child pid ${child.pid??"unknown"}: ${errorMessage(reapCause)}`)}}finally{await context.publicEndpoint?.dispose().catch(cause=>{supervisorLog(`endpoint key cleanup failed: ${errorMessage(cause)}`)}),hardExit&&clearTimeout(hardExit),process.exit(exitCode)}}async function stopChild(context,reason){let{child,generation}=context,pid=child.pid;if(childExited(child)||pid===void 0)return;let termAttempted=!1,killAttempted=!1;try{let outer=await readStopIntent(generation).catch(cause=>{supervisorLog(`cannot read child stop intent: ${errorMessage(cause)}`)}),at=new Date().toISOString(),intent=layeredSupervisorIntent(outer,supervisorSender(context.instanceId),{targetPid:pid,reason,at});await writeStopIntent(generation,intent,supervisorLog);let signalledAt=Date.now();if(termAttempted=!0,signalChild(pid,"SIGTERM"),await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS))return;let stallWaitMs=await waitOutStalledChild({child,generation,signalledAt,waitForExit:waitForChildExit});if(childExited(child))return;if(stallWaitMs>0){let escalated={...intent,reason:`${intent.reason}; escalated_after_stall_wait=${stallWaitMs}`};await writeStopIntent(generation,escalated,supervisorLog)}if(killAttempted=!0,signalChild(pid,"SIGKILL"),!await waitForChildExit(child,CHILD_KILL_EXIT_TIMEOUT_MS))throw new Error(`host child pid ${pid} exit unobserved ${CHILD_KILL_EXIT_TIMEOUT_MS}ms after SIGKILL`)}catch(cause){throw killAttempted||await reapChildAfterFailure(child,termAttempted),cause}}async function reapChildAfterFailure(child,termAttempted=!1){let pid=child.pid;if(!(childExited(child)||pid===void 0)&&!(!termAttempted&&(signalChild(pid,"SIGTERM"),await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS)))&&(signalChild(pid,"SIGKILL"),!await waitForChildExit(child,CHILD_KILL_EXIT_TIMEOUT_MS)))throw new Error(`host child pid ${pid} exit unobserved ${CHILD_KILL_EXIT_TIMEOUT_MS}ms after recovery SIGKILL`)}function signalChild(pid,signal){try{return process.kill(pid,signal),!0}catch{return!1}}function waitForChildExit(child,timeoutMs){return childExited(child)?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)})}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)}function startSupervisorTicker(options){let{activity,owner,draining,shuttingDown,shutdown}=options,tickIntervalMs=Math.max(20,Math.min(1e3,options.idleExitMs/4)),ownerCheck=!1,ticker=setInterval(()=>{!draining()&&activity.refresh()==="exit"&&activity.clients.unclassifiedCount===0&&shutdown("idle",0),!ownerCheck&&!shuttingDown()&&!draining()&&(ownerCheck=!0,owner.shouldExit(activity).then(exit=>{exit&&!shuttingDown()&&!draining()&&shutdown("owner_gone",0)}).finally(()=>{ownerCheck=!1}))},tickIntervalMs);return()=>{clearInterval(ticker),owner.stop()}}var __addDisposableResource=function(env,value,async){if(value!=null){if(typeof value!="object"&&typeof value!="function")throw new TypeError("Object expected.");var dispose,inner;if(async){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");dispose=value[Symbol.asyncDispose]}if(dispose===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");dispose=value[Symbol.dispose],async&&(inner=dispose)}if(typeof dispose!="function")throw new TypeError("Object not disposable.");inner&&(dispose=function(){try{inner.call(this)}catch(e){return Promise.reject(e)}}),env.stack.push({value,dispose,async})}else async&&env.stack.push({async:!0});return value},__disposeResources=(function(SuppressedError2){return function(env){function fail(e){env.error=env.hasError?new SuppressedError2(e,env.error,"An error was suppressed during disposal."):e,env.hasError=!0}var r,s=0;function next(){for(;r=env.stack.pop();)try{if(!r.async&&s===1)return s=0,env.stack.push(r),Promise.resolve().then(next);if(r.dispose){var result=r.dispose.call(r.value);if(r.async)return s|=2,Promise.resolve(result).then(next,function(e){return fail(e),next()})}else s|=1}catch(e){fail(e)}if(s===1)return env.hasError?Promise.reject(env.error):Promise.resolve();if(env.hasError)throw env.error}return next()}})(typeof SuppressedError=="function"?SuppressedError:function(error,suppressed,message){var e=new Error(message);return e.name="SuppressedError",e.error=error,e.suppressed=suppressed,e});async function runHostSupervisor(launch){let env_1={stack:[],error:void 0,hasError:!1};try{let shutdown=function(reason,exitCode){return shutdownPromise??=performShutdown(teardown,reason,exitCode),shutdownPromise},paths=createHostDaemonPaths({socket:launch.socket,agentDir:launch.agentDir??getAgentDir()}),told=process.env[HOST_INSTANCE_ID_ENV],instanceId=told!==void 0&&told.trim()!==""?told:randomUUID2(),generation=generationPaths(paths,instanceId),created=await mkdir3(generation.dir,{recursive:!0,mode:448}).catch(cause=>{throw new HostDaemonStateError(generation.dir,cause)}),startupRegistered=!1,_generationStartup=__addDisposableResource(env_1,{async[Symbol.asyncDispose](){created!==void 0&&!startupRegistered&&await rm3(generation.dir,{recursive:!0,force:!0})}},!0);await createGenerationDirectory(generation);let policy=resolveHostPolicy(await readSettingsFile(paths.settingsFile),process.env),publicSocket=launch.socket,publicEndpoint=process.platform==="win32"?void 0:new RpcPublicEndpoint(launch.agentDir??getAgentDir(),publicSocket),bindSocket=launch.bindSocket??publicSocket,successor=launch.bindSocket!==void 0,publicSecret=process.platform==="win32"?await ensurePublicSocketSecret(publicSocket):void 0,hop=await prepareInternalHop(paths.dir),{internal,internalSocket,internalSecret,internalKey}=hop,state={shuttingDown:!1,shutdownReason:void 0,childExitRecorded:Promise.resolve(),startupComplete:Promise.resolve(),publicSocketOwned:!1,publicSocketIdentity:void 0,endpointReplaced:!1},owner=new SupervisorOwner(generation.dir),activity=new SupervisorActivity({idleExitMs:policy.coldStart==="persistent"?Number.POSITIVE_INFINITY:policy.idleExitMs,internalSocket,...hop.transport,instanceId,settled:()=>state.shuttingDown,onActivity:()=>owner.activity()}),watchers=[],child=spawnHostChild({launch,internalSocket,internal,...hop.transport,supervisorStart:hop.supervisorStart,lifetimeFifo:hop.lifetimeFifo,daemonDir:paths.dir,instanceId,cleanupPaths:hostCrashCleanupPaths({pointerFile:paths.pointerFile,generationPidFile:generation.pidFile,settingsFile:paths.settingsFile,publicSocket,successor:!!successor,platform:process.platform}),publicSocket}),childStartedAt=Date.now();child.stdio[HOST_CHILD_WATCH_FD]?.on("error",()=>{}),child.pid!==void 0&&recordChildPid(generation.childPidFile,child.pid,()=>child.exitCode===null&&child.signalCode===null),child.once("exit",(code,signal)=>{let reason=state.shutdownReason;if(state.childExitRecorded=noteChildExit({daemonDir:paths.dir,generation,instanceId,code,signal,childStartedAt,...state.shuttingDown&&reason!==void 0?{shutdown:{reason,supervisor:supervisorSender(instanceId)}}:{}}),state.shuttingDown)return;let verdict=classifyChildExit(code,signal);state.childExitRecorded.then(()=>shutdown(verdict.reason,verdict.exitCode))});let admission=new HostAdmission({protocolVersion:1,serverVersion:VERSION,capabilities:[],instanceId}),drain=new SupervisorDrain(child,()=>state.shuttingDown,()=>admission.stop(),{file:generation.childDrainRequestFile,sender:supervisorSender(instanceId)}),server=createPublicProxy({internalSocket,...hop.transport,...publicSecret?{publicSecret}:{},...publicEndpoint?{publicEndpoint}:{},clients:activity.clients,admission,onDetach:()=>activity.refresh(),onAdmit:()=>owner.activity()});server.once("error",cause=>{state.shuttingDown||shutdown(`public socket listener failed: ${errorMessage(cause)}`,1)}),watchers.push(startSupervisorTicker({idleExitMs:policy.idleExitMs,activity,owner,draining:()=>drain.active,shuttingDown:()=>state.shuttingDown,shutdown}));let teardown={paths,generation,instanceId,publicSocket,server,internalDir:internal.dir,child,activity,drain,admission,state,...publicEndpoint?{publicEndpoint}:{},stopWatchers:()=>{for(let stop of watchers.splice(0))stop()}},shutdownPromise;registerSupervisorSignals(shutdown,()=>drain.drain()),startupRegistered=!0;try{if((launch.ownerFd!==void 0||await readSettingsFile(generation.settingsFile))&&await owner.start(launch.ownerFd),await waitForListener(internalSocket,3e4,internalSecret,internalKey),await activity.openObserver(),state.shuttingDown)return;state.startupComplete=(async()=>{await prepareSocketPath(bindSocket),await listen(server,bindSocket,publicSecret),await publicEndpoint?.publish(),state.publicSocketOwned=!0,successor&&await adoptPublicSocket(bindSocket,publicSocket,launch.replaceIdentity),state.publicSocketIdentity=await statSocketIdentity(publicSocket),state.publicSocketIdentity&&internal.dir&&await writeSocketIdentityFile(join6(internal.dir,PUBLIC_SOCKET_IDENTITY_FILE),state.publicSocketIdentity),watchers.push(drainOnPublicSocketLoss(publicSocket,state.publicSocketIdentity,()=>state.shuttingDown||drain.active,drain,()=>{state.endpointReplaced=!0},{file:paths.pointerFile,instanceId})),watchers.push(await drain.acceptRequests(generation))})(),await state.startupComplete}catch(cause){await shutdown(`startup failed: ${errorMessage(cause)}`,1)}if(state.shuttingDown)return;process.platform==="win32"&&watchers.push(await watchWin32ChildIdentity(child,()=>state.shuttingDown,()=>{shutdown("rpc host child exit observed by identity watchdog",0)})),writeHostReady(publicSocket,policy.coldStart,policy.idleExitMs),await new Promise(()=>{})}catch(e_1){env_1.error=e_1,env_1.hasError=!0}finally{let result_1=__disposeResources(env_1);result_1&&await result_1}}if(!isBundledNode&&isCliModuleEntry(import.meta.url)){let launch=parseSupervisorArgs(process.argv.slice(2));launch||(writeStderrLine("usage: host-lifecycle.ts --socket <path> [host cli args...]"),process.exit(2)),runHostSupervisor(launch)}export{runtimeExecArgv,loopLagErrorMs,recordProcessLifetime,isHostCrash,readHostCrashRecords,classifyChildExit,noteEscalatedStop,resolveCliMainPath,resolveCliMainPathAsync,ClientOccupancy,acceptInternalConnection,INTERNAL_HOST_DIR_PREFIX,internalHostDirRoots,createInternalSocketPath,consumeHostWatchdogEnv,scrubHostWatchdogEnv,armHostWatchdog,INTERNAL_SUPERVISOR_FLAG,findInternalSupervisorArgs,parseSupervisorArgs,OWNER_WATCH_FD,keepOwnerPipe,resolveHostChildLaunch,spawnableChildLaunch,PublicRpcConnection,prepareSocketPath,runHostSupervisor};
|
|
23
|
+
`)}))}catch(cause){socket.destroy();let reason=cause instanceof Error?cause.message:"";return reason==="host_identity_unproven"||reason==="auth_failed"?{unproven:reason}:outcome(!1)}finally{clearTimeout(timer)}}return new Promise(resolve2=>{let socket=createConnection2(resolveSocketTransportAddress(socketPath,process.platform,secret));secret&&sendSocketHandshake(socket,secret);let settle=connected=>{socket.destroy(),resolve2(connected?"ready":"refused")};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1))})}async function stampOf(socketPath){try{let entry=await lstat(socketPath,{bigint:!0});return{dev:entry.dev,ino:entry.ino,ctimeNs:entry.ctimeNs,socket:entry.isSocket()}}catch(cause){if(cause instanceof Error&&"code"in cause&&cause.code==="ENOENT")return;throw cause}}var sameStamp=(a,b)=>a.dev===b.dev&&a.ino===b.ino&&a.ctimeNs===b.ctimeNs;async function prepareSocketPath(socketPath,hooks={}){if(process.platform==="win32"||socketPath.startsWith("\0"))return;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 mkdir2(dirname2(socketPath),{recursive:!0,mode:448});let probed=await stampOf(socketPath);if(probed===void 0)return;let inUse=evidence=>new Error(`${socketPath}: address already in use by a live server (${evidence}).`);if(!probed.socket)throw inUse("the entry is not a socket");let probe=hooks.listenerState??socketEntryListenerState,state=await probe(socketPath);if(state.verdict==="gone")return;if(state.verdict==="live")throw inUse(state.evidence);await hooks.afterStaleProbe?.();let unchanged=async()=>{let current=await stampOf(socketPath);if(current===void 0)return!1;if(!sameStamp(probed,current))throw inUse("the entry changed after it was probed");return!0};if(!await unchanged())return;let again=await probe(socketPath);if(again.verdict!=="gone"){if(again.verdict==="live")throw inUse(again.evidence);if(await unchanged())try{await unlink(socketPath)}catch(cause){if(cause instanceof Error&&"code"in cause&&cause.code==="ENOENT")return;throw cause}}}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())})}import{rm as rm2}from"node:fs/promises";var LOOP_LAG_ERROR_MS_ENV="SENPI_RPC_LOOP_LAG_ERROR_MS",DEFAULT_LOOP_LAG_ERROR_MS=5e3;function loopLagErrorMs(env=process.env){return parseIdleExitMs(env[LOOP_LAG_ERROR_MS_ENV])??DEFAULT_LOOP_LAG_ERROR_MS}var STALL_WAIT_SLICE_MS=5e3;async function waitOutStalledChild(options){let{child,generation,signalledAt}=options,maxMs=childStalledStopMaxMs(),untilAt=signalledAt+maxMs,stalled=()=>hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:STOP_STALL_EVIDENCE_MAX_AGE_MS}).catch(()=>!1),waited=0;try{for(;Date.now()<untilAt&&await stalled();){waited===0&&supervisorLog(`host child is stalled; waiting up to ${maxMs}ms (${CHILD_STALLED_STOP_MAX_MS_ENV})`),await writeStopProgress(generation,{at:new Date().toISOString(),phase:"waiting_stalled_child",untilAt:new Date(untilAt).toISOString()}).catch(()=>{});let slice=Math.min(STALL_WAIT_SLICE_MS,untilAt-Date.now()),exited=await options.waitForExit(child,slice);if(waited+=slice,exited)break}}finally{await clearStopProgress(generation)}return waited}var WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS=2e3;function supervisorSender(instanceId){return{pid:process.pid,kind:"supervisor",generation:instanceId}}function childExited(child){return child.exitCode!==null||child.signalCode!==null}async function performShutdown(context,reason,exitCode){let{state,child}=context;state.shuttingDown=!0,state.shutdownReason=reason,context.admission.stop();let childStopStarted=!1,hardExit;try{context.drain.stop(),writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`),childStopStarted=!0,await stopChild(context,reason),await state.childExitRecorded,await state.startupComplete.then(void 0,()=>{}),context.stopWatchers(),await context.admission.flush(),context.activity.clients.destroyAll(),process.platform==="win32"&&(hardExit=setTimeout(()=>process.exit(exitCode),WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS)),context.drain.active||await shieldSocketDuringClose(context.publicSocket,()=>closeServer(context.server)),context.internalDir&&await rm2(context.internalDir,{recursive:!0,force:!0}),context.activity.stopObserver(),state.publicSocketOwned&&process.platform!=="win32"&&await unlinkOwnedSocket(context.publicSocket,state.publicSocketIdentity,supervisorLog),await releaseGeneration(context.paths,{instanceId:context.instanceId,pid:process.pid,superseded:state.endpointReplaced})}catch(cause){supervisorLog(`shutdown failed for host child pid ${child.pid??"unknown"}: ${errorMessage(cause)}`),exitCode=1;try{childStopStarted||await reapChildAfterFailure(child),await state.childExitRecorded}catch(reapCause){supervisorLog(`shutdown recovery failed for host child pid ${child.pid??"unknown"}: ${errorMessage(reapCause)}`)}}finally{await context.publicEndpoint?.dispose().catch(cause=>{supervisorLog(`endpoint key cleanup failed: ${errorMessage(cause)}`)}),hardExit&&clearTimeout(hardExit),process.exit(exitCode)}}async function stopChild(context,reason){let{child,generation}=context,pid=child.pid;if(childExited(child)||pid===void 0)return;let termAttempted=!1,killAttempted=!1;try{let outer=await readStopIntent(generation).catch(cause=>{supervisorLog(`cannot read child stop intent: ${errorMessage(cause)}`)}),at=new Date().toISOString(),intent=layeredSupervisorIntent(outer,supervisorSender(context.instanceId),{targetPid:pid,reason,at});await writeStopIntent(generation,intent,supervisorLog);let signalledAt=Date.now();if(termAttempted=!0,signalChild(pid,"SIGTERM"),await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS))return;let stallWaitMs=await waitOutStalledChild({child,generation,signalledAt,waitForExit:waitForChildExit});if(childExited(child))return;if(stallWaitMs>0){let escalated={...intent,reason:`${intent.reason}; escalated_after_stall_wait=${stallWaitMs}`};await writeStopIntent(generation,escalated,supervisorLog)}if(killAttempted=!0,signalChild(pid,"SIGKILL"),!await waitForChildExit(child,CHILD_KILL_EXIT_TIMEOUT_MS))throw new Error(`host child pid ${pid} exit unobserved ${CHILD_KILL_EXIT_TIMEOUT_MS}ms after SIGKILL`)}catch(cause){throw killAttempted||await reapChildAfterFailure(child,termAttempted),cause}}async function reapChildAfterFailure(child,termAttempted=!1){let pid=child.pid;if(!(childExited(child)||pid===void 0)&&!(!termAttempted&&(signalChild(pid,"SIGTERM"),await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS)))&&(signalChild(pid,"SIGKILL"),!await waitForChildExit(child,CHILD_KILL_EXIT_TIMEOUT_MS)))throw new Error(`host child pid ${pid} exit unobserved ${CHILD_KILL_EXIT_TIMEOUT_MS}ms after recovery SIGKILL`)}function signalChild(pid,signal){try{return process.kill(pid,signal),!0}catch{return!1}}function waitForChildExit(child,timeoutMs){return childExited(child)?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)})}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)}function startSupervisorTicker(options){let{activity,owner,draining,shuttingDown,shutdown}=options,tickIntervalMs=Math.max(20,Math.min(1e3,options.idleExitMs/4)),ownerCheck=!1,ticker=setInterval(()=>{!draining()&&activity.refresh()==="exit"&&activity.clients.unclassifiedCount===0&&shutdown("idle",0),!ownerCheck&&!shuttingDown()&&!draining()&&(ownerCheck=!0,owner.shouldExit(activity).then(exit=>{exit&&!shuttingDown()&&!draining()&&shutdown("owner_gone",0)}).finally(()=>{ownerCheck=!1}))},tickIntervalMs);return()=>{clearInterval(ticker),owner.stop()}}var __addDisposableResource=function(env,value,async){if(value!=null){if(typeof value!="object"&&typeof value!="function")throw new TypeError("Object expected.");var dispose,inner;if(async){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");dispose=value[Symbol.asyncDispose]}if(dispose===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");dispose=value[Symbol.dispose],async&&(inner=dispose)}if(typeof dispose!="function")throw new TypeError("Object not disposable.");inner&&(dispose=function(){try{inner.call(this)}catch(e){return Promise.reject(e)}}),env.stack.push({value,dispose,async})}else async&&env.stack.push({async:!0});return value},__disposeResources=(function(SuppressedError2){return function(env){function fail(e){env.error=env.hasError?new SuppressedError2(e,env.error,"An error was suppressed during disposal."):e,env.hasError=!0}var r,s=0;function next(){for(;r=env.stack.pop();)try{if(!r.async&&s===1)return s=0,env.stack.push(r),Promise.resolve().then(next);if(r.dispose){var result=r.dispose.call(r.value);if(r.async)return s|=2,Promise.resolve(result).then(next,function(e){return fail(e),next()})}else s|=1}catch(e){fail(e)}if(s===1)return env.hasError?Promise.reject(env.error):Promise.resolve();if(env.hasError)throw env.error}return next()}})(typeof SuppressedError=="function"?SuppressedError:function(error,suppressed,message){var e=new Error(message);return e.name="SuppressedError",e.error=error,e.suppressed=suppressed,e});async function runHostSupervisor(launch){let env_1={stack:[],error:void 0,hasError:!1};try{let shutdown=function(reason,exitCode){return shutdownPromise??=performShutdown(teardown,reason,exitCode),shutdownPromise},paths=createHostDaemonPaths({socket:launch.socket,agentDir:launch.agentDir??getAgentDir()}),told=process.env[HOST_INSTANCE_ID_ENV],instanceId=told!==void 0&&told.trim()!==""?told:randomUUID2(),generation=generationPaths(paths,instanceId),created=await mkdir3(generation.dir,{recursive:!0,mode:448}).catch(cause=>{throw new HostDaemonStateError(generation.dir,cause)}),startupRegistered=!1,_generationStartup=__addDisposableResource(env_1,{async[Symbol.asyncDispose](){created!==void 0&&!startupRegistered&&await rm3(generation.dir,{recursive:!0,force:!0})}},!0);await createGenerationDirectory(generation);let policy=resolveHostPolicy(await readSettingsFile(paths.settingsFile),process.env),publicSocket=launch.socket,publicEndpoint=process.platform==="win32"?void 0:new RpcPublicEndpoint(launch.agentDir??getAgentDir(),publicSocket),bindSocket=launch.bindSocket??publicSocket,successor=launch.bindSocket!==void 0,publicSecret=process.platform==="win32"?await ensurePublicSocketSecret(publicSocket):void 0,hop=await prepareInternalHop(paths.dir),{internal,internalSocket,internalSecret,internalKey}=hop,state={shuttingDown:!1,shutdownReason:void 0,childExitRecorded:Promise.resolve(),startupComplete:Promise.resolve(),publicSocketOwned:!1,publicSocketIdentity:void 0,endpointReplaced:!1},owner=new SupervisorOwner(generation.dir),activity=new SupervisorActivity({idleExitMs:policy.coldStart==="persistent"?Number.POSITIVE_INFINITY:policy.idleExitMs,internalSocket,...hop.transport,instanceId,settled:()=>state.shuttingDown,onActivity:()=>owner.activity()}),watchers=[],child=spawnHostChild({launch,internalSocket,internal,...hop.transport,supervisorStart:hop.supervisorStart,lifetimeFifo:hop.lifetimeFifo,daemonDir:paths.dir,instanceId,cleanupPaths:hostCrashCleanupPaths({pointerFile:paths.pointerFile,generationPidFile:generation.pidFile,settingsFile:paths.settingsFile,publicSocket,successor:!!successor,platform:process.platform}),publicSocket}),childStartedAt=Date.now();child.stdio[HOST_CHILD_WATCH_FD]?.on("error",()=>{}),child.pid!==void 0&&recordChildPid(generation.childPidFile,child.pid,()=>child.exitCode===null&&child.signalCode===null),child.once("exit",(code,signal)=>{let reason=state.shutdownReason;if(state.childExitRecorded=noteChildExit({daemonDir:paths.dir,generation,instanceId,code,signal,childStartedAt,...state.shuttingDown&&reason!==void 0?{shutdown:{reason,supervisor:supervisorSender(instanceId)}}:{}}),state.shuttingDown)return;let verdict=classifyChildExit(code,signal);state.childExitRecorded.then(()=>shutdown(verdict.reason,verdict.exitCode))});let admission=new HostAdmission({protocolVersion:1,serverVersion:VERSION,capabilities:[],instanceId}),drain=new SupervisorDrain(child,()=>state.shuttingDown,()=>admission.stop(),{file:generation.childDrainRequestFile,sender:supervisorSender(instanceId)}),server=createPublicProxy({internalSocket,...hop.transport,...publicSecret?{publicSecret}:{},...publicEndpoint?{publicEndpoint}:{},clients:activity.clients,admission,onDetach:()=>activity.refresh(),onAdmit:()=>owner.activity()});server.once("error",cause=>{state.shuttingDown||shutdown(`public socket listener failed: ${errorMessage(cause)}`,1)}),watchers.push(startSupervisorTicker({idleExitMs:policy.idleExitMs,activity,owner,draining:()=>drain.active,shuttingDown:()=>state.shuttingDown,shutdown}));let teardown={paths,generation,instanceId,publicSocket,server,internalDir:internal.dir,child,activity,drain,admission,state,...publicEndpoint?{publicEndpoint}:{},stopWatchers:()=>{for(let stop of watchers.splice(0))stop()}},shutdownPromise;registerSupervisorSignals(shutdown,()=>drain.drain()),startupRegistered=!0;try{if((launch.ownerFd!==void 0||await readSettingsFile(generation.settingsFile))&&await owner.start(launch.ownerFd),await waitForListener(internalSocket,3e4,internalSecret,internalKey),await activity.openObserver(),state.shuttingDown)return;state.startupComplete=(async()=>{await prepareSocketPath(bindSocket),await listen(server,bindSocket,publicSecret),await publicEndpoint?.publish(),state.publicSocketOwned=!0,successor&&await adoptPublicSocket(bindSocket,publicSocket,launch.replaceIdentity),state.publicSocketIdentity=await statSocketIdentity(publicSocket),state.publicSocketIdentity&&internal.dir&&await writeSocketIdentityFile(join6(internal.dir,PUBLIC_SOCKET_IDENTITY_FILE),state.publicSocketIdentity),watchers.push(drainOnPublicSocketLoss(publicSocket,state.publicSocketIdentity,()=>state.shuttingDown||drain.active,drain,()=>{state.endpointReplaced=!0},{file:paths.pointerFile,instanceId})),watchers.push(await drain.acceptRequests(generation))})(),await state.startupComplete}catch(cause){await shutdown(`startup failed: ${errorMessage(cause)}`,1)}if(state.shuttingDown)return;process.platform==="win32"&&watchers.push(await watchWin32ChildIdentity(child,()=>state.shuttingDown,()=>{shutdown("rpc host child exit observed by identity watchdog",0)})),writeHostReady(publicSocket,policy.coldStart,policy.idleExitMs),await new Promise(()=>{})}catch(e_1){env_1.error=e_1,env_1.hasError=!0}finally{let result_1=__disposeResources(env_1);result_1&&await result_1}}if(!isBundledNode&&isCliModuleEntry(import.meta.url)){let launch=parseSupervisorArgs(process.argv.slice(2));launch||(writeStderrLine("usage: host-lifecycle.ts --socket <path> [host cli args...]"),process.exit(2)),runHostSupervisor(launch)}export{runtimeExecArgv,loopLagErrorMs,recordProcessLifetime,isHostCrash,readHostCrashRecords,classifyChildExit,noteEscalatedStop,resolveCliMainPath,resolveCliMainPathAsync,ClientOccupancy,acceptInternalConnection,INTERNAL_HOST_DIR_PREFIX,internalHostDirRoots,createInternalSocketPath,consumeHostWatchdogEnv,scrubHostWatchdogEnv,armHostWatchdog,INTERNAL_SUPERVISOR_FLAG,findInternalSupervisorArgs,parseSupervisorArgs,OWNER_WATCH_FD,keepOwnerPipe,resolveHostChildLaunch,spawnableChildLaunch,PublicRpcConnection,prepareSocketPath,runHostSupervisor};
|