@code-yeongyu/senpi 2026.10.25-1 → 2026.10.25-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 +16 -0
- package/dist/bundle/chunks/{chunk-BTNYLNWZ.js → chunk-2EFVQWXZ.js} +2 -2
- package/dist/bundle/chunks/{chunk-RHHBXIRN.js → chunk-4WZRVZNX.js} +1 -1
- package/dist/bundle/chunks/{chunk-J5P2VL3Y.js → chunk-B6TPQDBW.js} +1 -1
- package/dist/bundle/chunks/{chunk-VOBD6FQG.js → chunk-FHXR4ZAC.js} +1 -1
- package/dist/bundle/chunks/{chunk-7IRLFYNM.js → chunk-G2UETS2R.js} +2 -2
- package/dist/bundle/chunks/{chunk-URBJS24R.js → chunk-J2U5VDG7.js} +15 -15
- package/dist/bundle/chunks/{chunk-YDCRA5ES.js → chunk-JRXKLIEQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-3VOG6WFU.js → chunk-KJZAY5YH.js} +1 -1
- package/dist/bundle/chunks/{chunk-EYBDBR7V.js → chunk-KUE4AQN6.js} +1 -1
- package/dist/bundle/chunks/{chunk-FWXMMMCV.js → chunk-LYGAV6KU.js} +1 -1
- package/dist/bundle/chunks/{chunk-SGDOZT6B.js → chunk-MXZPAUFB.js} +1 -1
- package/dist/bundle/chunks/chunk-O5RYI3IW.js +2 -0
- package/dist/bundle/chunks/{chunk-II22E3CV.js → chunk-OI4NMCKP.js} +1 -1
- package/dist/bundle/chunks/{chunk-7UUOGZKR.js → chunk-RXKNOEQQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-QH2HSCMX.js → chunk-TTU2RNVX.js} +3 -3
- package/dist/bundle/chunks/{chunk-PXKF2RHD.js → chunk-UFJ2K7Q7.js} +1 -1
- package/dist/bundle/chunks/chunk-VNN2V74Y.js +5 -0
- package/dist/bundle/chunks/{chunk-BMYNMUVZ.js → chunk-W2BKZBYJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-RVYSJBZ7.js → chunk-WFXUCVIR.js} +1 -1
- package/dist/bundle/chunks/{chunk-7WAJCESX.js → chunk-XBUSVKWC.js} +1 -1
- package/dist/bundle/chunks/{chunk-EWOEVVQT.js → chunk-YN7ELQ43.js} +1 -1
- package/dist/bundle/chunks/{cli-main-TABBP55A.js → cli-main-SWKFMTZQ.js} +1 -1
- package/dist/bundle/chunks/{host-command-OQR4RDTM.js → host-command-BC6UWP33.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-U36U7JTE.js → host-lifecycle-TN5NEGNF.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +3 -3
- package/dist/bundle/chunks/{host-session-command-IGB27ZPJ.js → host-session-command-MGVBLBRV.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-ZDJGSSZO.js → host-socket-request-AS2OCRLP.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-DGQNSXUA.js → interactive-mode-SCSROHD5.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-M7HVUMRH.js → multi-session-host-VTTY5MFT.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-FSR5P6YL.js → package-manager-cli-DZFOC3MF.js} +1 -1
- package/dist/bundle/chunks/{role-M2MTVACJ.js → role-JVSBNKGE.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-SZAJNKKL.js → rpc-mode-TOXYD4XA.js} +1 -1
- package/dist/bundle/chunks/{rpc-monitor-source-OL5KU6NO.js → rpc-monitor-source-B5NQ4ZVH.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-CLNODAYE.js → runtime-session-V5OO7ZRM.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-XBW4EOG5.js → schedule-command-SLISTG4V.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-WEF3XTJR.js → session-control-endpoint-HFFMBALG.js} +1 -1
- package/dist/bundle/chunks/{session-picker-KQUFWDQC.js → session-picker-465FVXQG.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +18 -18
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +3 -3
- 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/agent-session.d.ts +1 -0
- package/dist/core/agent-session.js +28 -9
- package/dist/core/engine-turn-limit.d.ts +2 -0
- package/dist/core/engine-turn-limit.js +7 -1
- package/dist/core/extensions/builtin/anthropic-subscription/auth-attempt.js +5 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +2 -1
- package/dist/core/extensions/builtin/loop/session-hold.js +2 -1
- package/dist/core/lifecycle-runtime-facts.js +3 -0
- package/dist/core/lifecycle-session-binding.js +6 -2
- package/dist/core/run-resume-turn.d.ts +1 -0
- package/dist/core/run-resume-turn.js +4 -3
- package/dist/core/stop-resume-directive.d.ts +1 -1
- package/dist/core/stop-resume-directive.js +10 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/pause-footer.d.ts +5 -0
- package/dist/modes/interactive/pause-footer.js +2 -0
- package/dist/modes/rpc/host-reservations.js +3 -2
- package/dist/modes/rpc/host-stalled-evidence.js +2 -1
- package/dist/modes/rpc/tool-child/group-ownership.js +4 -2
- package/dist/utils/process-identity.d.ts +7 -0
- package/dist/utils/process-identity.js +32 -5
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-7ASLQ243.js +0 -2
- package/dist/bundle/chunks/chunk-XUFUKDKJ.js +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CUSTOM_UNSUPPORTED_CAPABILITY,DEFAULT_PROBE_TIMEOUT_MS,EXTENSION_EVENTS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,RPC_CLIENT_CAPABILITIES_ENV,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,acquireHostEnsureLock,anyGenerationLive,busyLegacyHostDetail,computeRuntimeBuildId,decideHostAction,describeSessions,electPointer,engineBuildIdentity,gcEndpoint,gcHostEndpoints,holdProtocolInfo,holdSessionCount,hostEnsureLockOptions,hostEnsureLockTarget,hostLaunchProfile,judgeStaleEngine,observeProtocolInfo,parseHostStopGeneration,probeProtocolInfo,probeSocketReachable,provenLegacyOwner,retireIdleLegacyHost,signalGeneration,socketHostLaunchProfile,staleStopGeneration,stopHost}from"./chunk-BMYNMUVZ.js";import{endpointKindOfSocket,listHostEndpoints}from"./chunk-FWXMMMCV.js";import{envSlotVarNames}from"./chunk-4AOMNOGY.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{isSessionRuntimeKind,isToolRuntimeKind,toolRuntimeCapability}from"./chunk-U67ML6CQ.js";import{requestOnSocket}from"./chunk-EWOEVVQT.js";import{rpcKeyRoot,withRpcKeyRoot}from"./chunk-II22E3CV.js";import{INTERNAL_HOST_DIR_PREFIX,INTERNAL_SUPERVISOR_FLAG,OWNER_WATCH_FD,internalHostDirRoots,isHostCrash,keepOwnerPipe,loopLagErrorMs,noteEscalatedStop,readHostCrashRecords,resolveCliMainPath,runtimeExecArgv}from"./chunk-7IRLFYNM.js";import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STOP_TIMEOUT_MS,DEFAULT_HOST_IDLE_EXIT_MS,acquireOwnershipSafeLock,activeStopProgress,childStalledStopMaxMs,claimOwnerIsLive,clearHostRegistration,hostChildAlive,hostLoopStalled,provenOwner,pruneDeadGenerations,readGenerationRows,readHostProcessMetrics,readHostRegistration,readSessionPathClaims,readStopIntent,releaseGeneration,stallRefusalWindowMs,writeGenerationRecord,writeHostRegistration,writeStopIntent,writtenByThisProcess}from"./chunk-XUFUKDKJ.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,callerHostOwner,claimHostOwner,createDaemonDirectories,createHostDaemonPaths,ensureEndpointIdentity,generationPaths,hostDaemonDirectoryPaths,parseJson,parseShardSocket,readFileOrUndefined,readHostOwner,readHostSettings,sameEndpoint,sameHostOwner,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,writeHostOwner,writeHostSettings,writeStateFile}from"./chunk-RHHBXIRN.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-RVYSJBZ7.js";import{providerCredentialEnvNames}from"./chunk-T36LJ6MW.js";import{MAX_SOCKET_PATH_BYTES,generationBindPath,socketEntryListenerState,statSocketIdentity}from"./chunk-VRDU425E.js";import{createSocketSecret,socketSecretPath}from"./chunk-ZGAB7WQA.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-7YO7VQZW.js";import{ProcessIdentityUnreadableError,processIsLive,processMatchesPidFile,readProcessStartTime,waitForStartTime}from"./chunk-7ASLQ243.js";import{writeSync as writeSync2}from"node:fs";import{join as join6,resolve as resolve5}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path=>["--extension",path])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^BSK_(HOME|BIN)$/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],PROVIDER_CREDENTIAL_ENV_NAMES=new Set([...providerCredentialEnvNames(),...envSlotVarNames()]),WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","OMO_BROWSER_ENGINE","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID"]);function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?PROVIDER_CREDENTIAL_ENV_NAMES.has(name)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||PROVIDER_CREDENTIAL_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{mkdir,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname4}from"node:path";var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}function decideEnsureAction(options,startedByUs,protocol){if(options.upgrade!=="if-engine-differs"||isHostGenerationProcess())return decideHostAction(ensureClient(options,startedByUs),protocol,"never");let decision=decideHostAction(ensureClient(options,startedByUs),protocol,"upgrade");return decision.action==="fallback"?{action:"reuse",reason:"compatible",upgradeable:!1}:decision}function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:[...REQUIRED_HOST_CAPABILITIES,...requestedToolRuntime(options.hostArgs??[])],identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function requestedToolRuntime(hostArgs){for(let index=0;index<hostArgs.length;index++){let arg=hostArgs[index]??"",value=arg==="--tool-runtime"?hostArgs[index+1]:arg.startsWith("--tool-runtime=")?arg.slice(15):void 0;if(value!==void 0&&isToolRuntimeKind(value))return[toolRuntimeCapability(value)]}return[]}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}async function refuseIfStalled(paths,instanceId,socket,protocol){let generation=generationPaths(paths,instanceId);if(await hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:stallRefusalWindowMs()})&&await hostChildAlive(generation)!==!1)throw new HostEnsureRefusedError(socket,"host_stalled",protocol)}async function refuseIfForeignHeld(paths,registered,socket,protocol){if(!await publicEndpointAccepts(socket))return;let holder=await readHostHolder(paths,registered);throw new HostEnsureRefusedError(socket,"foreign_writer",protocol,void 0,holder)}async function readHostHolder(paths,registered){let record=parseJson(await readFileOrUndefined(generationPaths(paths,registered.instanceId).pidFile))??{};return{pid:registered.record.pid,instanceId:registered.instanceId,generation:registered.generation,processStartTime:registered.record.processStartTime,engineVersion:typeof record.engineVersion=="string"?record.engineVersion:null,launchProfileId:typeof record.launchProfileId=="string"?record.launchProfileId:null,writerPid:registered.writer?.pid??null}}var FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS=2e3;async function publicEndpointAccepts(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!0;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:probeSocketReachable(socket,FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS)}async function unregisteredEndpointHeld(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!1;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:(await socketEntryListenerState(socket)).verdict==="live"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile2}from"node:fs/promises";var DEFAULT_STOP_TIMEOUT_MS=Math.max(CHILD_STOP_TIMEOUT_MS,childStalledStopMaxMs())+CHILD_KILL_EXIT_TIMEOUT_MS+5e3,SIGKILL_GRACE_MS=2e3,STOP_PROGRESS_FRESH_MS=1e4,AFTER_STALL_WAIT_GRACE_MS=CHILD_KILL_EXIT_TIMEOUT_MS+5e3,STOP_WAIT_BUDGET_MS=Math.max(DEFAULT_STOP_TIMEOUT_MS,childStalledStopMaxMs()+AFTER_STALL_WAIT_GRACE_MS)+SIGKILL_GRACE_MS;function ensureSender(){return{pid:process.pid,kind:"ensure"}}async function announceStop(target,targetPid){let intent={sender:target.sender,targetPid,reason:target.reason,signal:"SIGTERM",at:new Date().toISOString()};return await writeStopIntent(target.generation,intent),intent}async function matchesPidFileOrUnknown(pidFile,probe){try{return await processMatchesPidFile(pidFile,probe)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!1;throw error}}async function recordEscalation(target,announced){let current=await readStopIntent(target.generation).catch(()=>{});await noteEscalatedStop(target.daemonDir,target.instanceId,current??announced)}async function stopSpawnedChild(child,childExit,termTimeoutMs,target){let exited=()=>child.exitCode!==null||child.signalCode!==null,pid=child.pid;if(exited()||pid===void 0)return;let waitFor=async ms=>{let timer;try{return await Promise.race([childExit.then(()=>!0),new Promise(resolve6=>{timer=setTimeout(()=>resolve6(exited()),ms)})])}finally{clearTimeout(timer)}},announced=await announceStop(target,pid);if(signalPid(pid,"SIGTERM"),!await waitWhileSupervisorReports(target,termTimeoutMs,waitFor)){if(signalPid(pid,"SIGKILL"),!await waitFor(SIGKILL_GRACE_MS))throw new Error(`RPC socket host pid ${pid} remained alive after SIGKILL`);await recordEscalation(target,announced)}}async function stopManagedHost(pidFile,termTimeoutMs,target,readStartTime=readProcessStartTime){let announced=await announceStop(target,pidFile.pid);if(await signalValidated(pidFile,"SIGTERM",readStartTime),!await waitWhileSupervisorReports(target,termTimeoutMs,ms=>waitForGone(pidFile,ms,readStartTime))){if(await signalValidated(pidFile,"SIGKILL",readStartTime),!await waitForGone(pidFile,SIGKILL_GRACE_MS,readStartTime))throw new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);await recordEscalation(target,announced)}}async function waitWhileSupervisorReports(target,termTimeoutMs,waitFor){if(await waitFor(termTimeoutMs))return!0;let extended=!1;for(;;){let untilAt=await activeStopProgress(target.generation,Date.now(),STOP_PROGRESS_FRESH_MS);if(untilAt===void 0)return extended&&await waitFor(AFTER_STALL_WAIT_GRACE_MS);if(extended=!0,await waitFor(Math.min(STOP_PROGRESS_FRESH_MS,Math.max(1,untilAt-Date.now()))))return!0}}async function resolvePidFileOwnership(pidFile,readStartTime=readProcessStartTime){try{return await processMatchesPidFile(pidFile,readStartTime,processIsLive,{attempts:1})?"owns":"gone"}catch(error){if(error instanceof ProcessIdentityUnreadableError)return"unknown";throw error}}async function signalValidated(pidFile,signal,readStartTime=readProcessStartTime){await resolvePidFileOwnership(pidFile,readStartTime)==="owns"&&signalPid(pidFile.pid,signal)}async function waitForGone(pidFile,timeoutMs,readStartTime=readProcessStartTime){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await resolvePidFileOwnership(pidFile,readStartTime)==="gone")return!0;await delay(50)}return await resolvePidFileOwnership(pidFile,readStartTime)==="gone"}function signalPid(pid,signal){try{process.kill(pid,signal)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}import{existsSync}from"node:fs";import{basename,dirname as dirname2,join as join2,resolve as resolve2}from"node:path";import{fileURLToPath}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null,bundledSupervisor=resolveBundledSupervisorEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...runtimeExecArgv(),sibling,...supervisorArgs]}:bundledSupervisor!==null?{command:process.execPath,args:[...runtimeExecArgv(),bundledSupervisor,INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:{command:process.execPath,args:[...runtimeExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}var BUNDLED_SUPERVISOR_ENTRY="host-supervisor.js";function resolveBundledSupervisorEntryPath(){let entry=join2(dirname2(resolveCliMainPath()),BUNDLED_SUPERVISOR_ENTRY);return existsSync(entry)?entry:void 0}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath(import.meta.url);if(basename(dirname2(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname2(modulePath),`host-lifecycle${extension}`);return existsSync(sibling)?sibling:void 0}var SPAWNED_HOST_PROBE_TIMEOUT_MS=1e4;async function pollProtocolInfo(socket,timeoutMs,isCompatible2,childExit){let deadline=Date.now()+timeoutMs,lastProtocol;for(;Date.now()<=deadline;){let probe=holdProtocolInfo(socket,Math.min(SPAWNED_HOST_PROBE_TIMEOUT_MS,Math.max(1,deadline-Date.now()))),raced=childExit?await Promise.race([probe,childExit]):await probe;if(isChildExit(raced)){let held=await probe;if(!held)return{ready:!1,protocol:lastProtocol,exited:raced};if(lastProtocol=held.info,isCompatible2(held.info))return{ready:!0,protocol:held.info,hold:held.hold};held.hold.release()}else if(raced){if(lastProtocol=raced.info,isCompatible2(raced.info))return{ready:!0,protocol:raced.info,hold:raced.hold};raced.hold.release()}await delay2(50)}return{ready:!1,protocol:lastProtocol}}function isChildExit(value){return!!value&&"code"in value&&"signal"in value}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}var EXPECTED_RUNTIME_BUILD_ID_ENV="SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID",NEW_WORK_COMMANDS=new Set(["prompt","steer","follow_up","send_custom_message","continue_from_leaf","resume_session","append_user_message","bash","compact","wake","edit_assistant_message","edit_user_message"]),DEFAULT_POLL_MS=200,HostIdleHandover=class{constructor(options){this.options=options}view(){return this.operation?.view}admits(commandType){let state=this.operation?.view.state;return state===void 0||state==="handover_blocked"||!NEW_WORK_COMMANDS.has(commandType)}async begin(request){let current=this.operation;if(current!==void 0&¤t.view.operationId===request.operationId)return sameTerms(current.request,request)?answer(current):{kind:"refused",reason:"operation_conflict",detail:"this operation id names other terms"};if(current!==void 0&¤t.view.state!=="handover_blocked")return current.request.targetRuntimeBuildId===request.targetRuntimeBuildId?answer(current):{kind:"refused",reason:"handover_in_progress",detail:current.view.operationId};let self=this.options.identity();if(self.instanceId!==request.ifInstanceId||self.generation!==request.ifGeneration)return{kind:"refused",reason:"stale_generation",detail:`this host is ${self.instanceId} generation ${self.generation}`};if(self.runtimeBuildId===request.targetRuntimeBuildId)return{kind:"refused",reason:"already_current",detail:self.runtimeBuildId};let operation={request,view:{operationId:request.operationId,state:"handover_pending",targetRuntimeBuildId:request.targetRuntimeBuildId}};return this.operation=operation,this.options.log?.(`handover ${request.operationId} pending: no new work is admitted`),this.idleNow()?(await this.switchOver(operation),answer(operation)):(this.timer=setInterval(()=>this.observe(),this.options.pollMs??DEFAULT_POLL_MS),this.timer.unref?.(),answer(operation))}observe(){let operation=this.operation;operation?.view.state==="handover_pending"&&this.idleNow()&&this.switchOver(operation)}dispose(){this.stopTimer()}idleNow(){try{return this.options.isIdle()}catch(cause){return this.options.log?.(`handover idle check failed, waiting: ${String(cause)}`),!1}}async switchOver(operation){if(operation.view.state!=="handover_pending")return;this.stopTimer(),operation.view={...operation.view,state:"handover_switching"};let outcome=await this.options.perform(operation.request).catch(cause=>({ok:!1,reason:`successor_unavailable: ${String(cause)}`}));operation.view=outcome.ok?{...operation.view,state:"handover_completed",successor:outcome.successor}:{...operation.view,state:"handover_blocked",reason:outcome.reason},this.options.log?.(`handover ${operation.view.operationId} ${operation.view.state}`)}stopTimer(){this.timer!==void 0&&clearInterval(this.timer),this.timer=void 0}};function sameTerms(a,b){return a.targetRuntimeBuildId===b.targetRuntimeBuildId&&a.ifInstanceId===b.ifInstanceId&&a.ifGeneration===b.ifGeneration}function answer(operation){return{kind:"operation",view:operation.view}}function initialHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[ENV_AGENT_DIR]:options.agentDir??getAgentDir(),[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir})}function successorHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),...options.agentDir?{[ENV_AGENT_DIR]:options.agentDir}:{},[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir,...options.expectedRuntimeBuildId!==void 0&&{[EXPECTED_RUNTIME_BUILD_ID_ENV]:options.expectedRuntimeBuildId}})}var DEFAULT_READINESS_TIMEOUT_MS=1e4;async function startHost(paths,socket,options,generation=0){let testOptions=options._test,lifetimeOwner=options.owner?await callerHostOwner():null,instanceId=randomUUID(),stopTarget=reason=>({daemonDir:paths.dir,generation:generationPaths(paths,instanceId),instanceId,sender:ensureSender(),reason});process.platform==="win32"&&await createSocketSecret(socketSecretPath(socket)),await writeHostSettings(paths,{socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??9e5,generation,instanceId}),await writeHostOwner(generationPaths(paths,instanceId).dir,lifetimeOwner);let stderr=await open(paths.stderrLog,generation===0?"w":"a",384),pidFile,child,exitedEarly,childExit;try{let supervisorArgs=["--socket",socket,...options.owner?["--owner-fd",String(OWNER_WATCH_FD)]:[],...options.hostArgs??[]],launch=testOptions?.spawn??testOptions?.launch?.(supervisorArgs)??defaultHostLaunch(supervisorArgs);if(child=spawn(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:initialHostEnvironment({agentDir:options.agentDir,env:options.env,paths,instanceId,generation}),stdio:options.owner?["ignore","ignore",stderr.fd,"pipe"]:["ignore","ignore",stderr.fd]}),childExit=new Promise(resolveExit=>{child.once("exit",(code,signal)=>{exitedEarly={code,signal},resolveExit(exitedEarly)})}),options.owner&&keepOwnerPipe(child),child.pid===void 0)throw new Error("failed to spawn RPC socket host");let probe=testOptions?.readProcessStartTime??readProcessStartTime,observedStartTime=await Promise.race([waitForStartTime(child.pid,1e4,probe),childExit.then(()=>{throw new Error("RPC socket host exited before its start time could be read")})]),unhurriedProbe=testOptions?.readProcessStartTime?testOptions.readProcessStartTime:pid=>readProcessStartTime(pid,process.platform,15e3),processStartTime=observedStartTime??await unhurriedProbe(child.pid).catch(()=>{});pidFile={pid:child.pid,processStartTime:processStartTime??null},await testOptions?.beforePidFileWrite?.(),await writeHostRegistration(paths,{record:pidFile,socket,instanceId,generation,launchProfileId:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd()).profile_id,build:engineBuildIdentity()}),child.unref()}catch(error){let exitedBeforeCleanup=exitedEarly;if(!exitedBeforeCleanup&&child?.pid!==void 0&&childExit&&await stopUnregisteredStart(child,childExit,stopTarget("start_failed")),!exitedBeforeCleanup)throw await clearHostRegistration(paths),error;let diagnostic2=await appendStderr(paths,`RPC socket host exited with code ${exitedBeforeCleanup.code??"null"}${exitedBeforeCleanup.signal?` (${exitedBeforeCleanup.signal})`:""} before answering get_protocol_info`);throw await clearHostRegistration(paths),new Error(diagnostic2)}finally{await stderr.close()}let readinessTimeoutMs=testOptions?.readinessTimeoutMs??DEFAULT_READINESS_TIMEOUT_MS,result=await pollProtocolInfo(socket,readinessTimeoutMs,isCompatible,childExit);if(result.ready)return{pid:pidFile.pid,socket,reused:!1,release:result.hold.release};await testOptions?.beforeReadinessTeardown?.();let stopFailure=await stopSpawnedChild(child,childExit,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS,stopTarget("readiness_timeout")).then(()=>{},error=>error instanceof Error?error.message:String(error)),message=result.protocol?`RPC socket host answered get_protocol_info with protocolVersion ${result.protocol.protocolVersion}, serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with protocol version ${HOST_PROTOCOL_VERSION} and required capabilities ${JSON.stringify(REQUIRED_HOST_CAPABILITIES)}`:result.exited?`RPC socket host exited with code ${result.exited.code??"null"}${result.exited.signal?` (${result.exited.signal})`:""} before answering get_protocol_info`:`spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`,diagnostic=await appendStderr(paths,stopFailure===void 0?message:`${message} (teardown also reported: ${stopFailure})`);throw await clearHostRegistration(paths),new Error(diagnostic)}async function stopUnregisteredStart(child,childExit,target){let pid=child.pid,running=()=>child.exitCode===null&&child.signalCode===null;if(pid===void 0||!running())return;let announced=await announceStop(target,pid);try{signalPid(pid,"SIGTERM")}catch{}if(await Promise.race([childExit,delay(2e3)]),!running())return;try{signalPid(pid,"SIGKILL")}catch{}await Promise.race([childExit.then(()=>!0),delay(SIGKILL_GRACE_MS).then(()=>!1)])&&await recordEscalation(target,announced)}async function appendStderr(paths,message){try{let stderr=(await readFile2(paths.stderrLog,"utf8")).trim();return stderr?`${message}
|
|
2
|
+
import{CUSTOM_UNSUPPORTED_CAPABILITY,DEFAULT_PROBE_TIMEOUT_MS,EXTENSION_EVENTS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,RPC_CLIENT_CAPABILITIES_ENV,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,acquireHostEnsureLock,anyGenerationLive,busyLegacyHostDetail,computeRuntimeBuildId,decideHostAction,describeSessions,electPointer,engineBuildIdentity,gcEndpoint,gcHostEndpoints,holdProtocolInfo,holdSessionCount,hostEnsureLockOptions,hostEnsureLockTarget,hostLaunchProfile,judgeStaleEngine,observeProtocolInfo,parseHostStopGeneration,probeProtocolInfo,probeSocketReachable,provenLegacyOwner,retireIdleLegacyHost,signalGeneration,socketHostLaunchProfile,staleStopGeneration,stopHost}from"./chunk-W2BKZBYJ.js";import{endpointKindOfSocket,listHostEndpoints}from"./chunk-LYGAV6KU.js";import{envSlotVarNames}from"./chunk-4AOMNOGY.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{isSessionRuntimeKind,isToolRuntimeKind,toolRuntimeCapability}from"./chunk-U67ML6CQ.js";import{requestOnSocket}from"./chunk-YN7ELQ43.js";import{rpcKeyRoot,withRpcKeyRoot}from"./chunk-OI4NMCKP.js";import{INTERNAL_HOST_DIR_PREFIX,INTERNAL_SUPERVISOR_FLAG,OWNER_WATCH_FD,internalHostDirRoots,isHostCrash,keepOwnerPipe,loopLagErrorMs,noteEscalatedStop,readHostCrashRecords,resolveCliMainPath,runtimeExecArgv}from"./chunk-G2UETS2R.js";import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STOP_TIMEOUT_MS,DEFAULT_HOST_IDLE_EXIT_MS,acquireOwnershipSafeLock,activeStopProgress,childStalledStopMaxMs,claimOwnerIsLive,clearHostRegistration,hostChildAlive,hostLoopStalled,provenOwner,pruneDeadGenerations,readGenerationRows,readHostProcessMetrics,readHostRegistration,readSessionPathClaims,readStopIntent,releaseGeneration,stallRefusalWindowMs,writeGenerationRecord,writeHostRegistration,writeStopIntent,writtenByThisProcess}from"./chunk-VNN2V74Y.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,callerHostOwner,claimHostOwner,createDaemonDirectories,createHostDaemonPaths,ensureEndpointIdentity,generationPaths,hostDaemonDirectoryPaths,parseJson,parseShardSocket,readFileOrUndefined,readHostOwner,readHostSettings,sameEndpoint,sameHostOwner,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,writeHostOwner,writeHostSettings,writeStateFile}from"./chunk-4WZRVZNX.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-WFXUCVIR.js";import{providerCredentialEnvNames}from"./chunk-T36LJ6MW.js";import{MAX_SOCKET_PATH_BYTES,generationBindPath,socketEntryListenerState,statSocketIdentity}from"./chunk-VRDU425E.js";import{createSocketSecret,socketSecretPath}from"./chunk-ZGAB7WQA.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-7YO7VQZW.js";import{ProcessIdentityUnreadableError,processIsLive,processMatchesPidFile,readProcessStartTime,waitForStartTime}from"./chunk-O5RYI3IW.js";import{writeSync as writeSync2}from"node:fs";import{join as join6,resolve as resolve5}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path=>["--extension",path])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^BSK_(HOME|BIN)$/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],PROVIDER_CREDENTIAL_ENV_NAMES=new Set([...providerCredentialEnvNames(),...envSlotVarNames()]),WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","OMO_BROWSER_ENGINE","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID"]);function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?PROVIDER_CREDENTIAL_ENV_NAMES.has(name)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||PROVIDER_CREDENTIAL_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{mkdir,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname4}from"node:path";var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}function decideEnsureAction(options,startedByUs,protocol){if(options.upgrade!=="if-engine-differs"||isHostGenerationProcess())return decideHostAction(ensureClient(options,startedByUs),protocol,"never");let decision=decideHostAction(ensureClient(options,startedByUs),protocol,"upgrade");return decision.action==="fallback"?{action:"reuse",reason:"compatible",upgradeable:!1}:decision}function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:[...REQUIRED_HOST_CAPABILITIES,...requestedToolRuntime(options.hostArgs??[])],identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function requestedToolRuntime(hostArgs){for(let index=0;index<hostArgs.length;index++){let arg=hostArgs[index]??"",value=arg==="--tool-runtime"?hostArgs[index+1]:arg.startsWith("--tool-runtime=")?arg.slice(15):void 0;if(value!==void 0&&isToolRuntimeKind(value))return[toolRuntimeCapability(value)]}return[]}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}async function refuseIfStalled(paths,instanceId,socket,protocol){let generation=generationPaths(paths,instanceId);if(await hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:stallRefusalWindowMs()})&&await hostChildAlive(generation)!==!1)throw new HostEnsureRefusedError(socket,"host_stalled",protocol)}async function refuseIfForeignHeld(paths,registered,socket,protocol){if(!await publicEndpointAccepts(socket))return;let holder=await readHostHolder(paths,registered);throw new HostEnsureRefusedError(socket,"foreign_writer",protocol,void 0,holder)}async function readHostHolder(paths,registered){let record=parseJson(await readFileOrUndefined(generationPaths(paths,registered.instanceId).pidFile))??{};return{pid:registered.record.pid,instanceId:registered.instanceId,generation:registered.generation,processStartTime:registered.record.processStartTime,engineVersion:typeof record.engineVersion=="string"?record.engineVersion:null,launchProfileId:typeof record.launchProfileId=="string"?record.launchProfileId:null,writerPid:registered.writer?.pid??null}}var FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS=2e3;async function publicEndpointAccepts(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!0;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:probeSocketReachable(socket,FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS)}async function unregisteredEndpointHeld(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!1;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:(await socketEntryListenerState(socket)).verdict==="live"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile2}from"node:fs/promises";var DEFAULT_STOP_TIMEOUT_MS=Math.max(CHILD_STOP_TIMEOUT_MS,childStalledStopMaxMs())+CHILD_KILL_EXIT_TIMEOUT_MS+5e3,SIGKILL_GRACE_MS=2e3,STOP_PROGRESS_FRESH_MS=1e4,AFTER_STALL_WAIT_GRACE_MS=CHILD_KILL_EXIT_TIMEOUT_MS+5e3,STOP_WAIT_BUDGET_MS=Math.max(DEFAULT_STOP_TIMEOUT_MS,childStalledStopMaxMs()+AFTER_STALL_WAIT_GRACE_MS)+SIGKILL_GRACE_MS;function ensureSender(){return{pid:process.pid,kind:"ensure"}}async function announceStop(target,targetPid){let intent={sender:target.sender,targetPid,reason:target.reason,signal:"SIGTERM",at:new Date().toISOString()};return await writeStopIntent(target.generation,intent),intent}async function matchesPidFileOrUnknown(pidFile,probe){try{return await processMatchesPidFile(pidFile,probe)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!1;throw error}}async function recordEscalation(target,announced){let current=await readStopIntent(target.generation).catch(()=>{});await noteEscalatedStop(target.daemonDir,target.instanceId,current??announced)}async function stopSpawnedChild(child,childExit,termTimeoutMs,target){let exited=()=>child.exitCode!==null||child.signalCode!==null,pid=child.pid;if(exited()||pid===void 0)return;let waitFor=async ms=>{let timer;try{return await Promise.race([childExit.then(()=>!0),new Promise(resolve6=>{timer=setTimeout(()=>resolve6(exited()),ms)})])}finally{clearTimeout(timer)}},announced=await announceStop(target,pid);if(signalPid(pid,"SIGTERM"),!await waitWhileSupervisorReports(target,termTimeoutMs,waitFor)){if(signalPid(pid,"SIGKILL"),!await waitFor(SIGKILL_GRACE_MS))throw new Error(`RPC socket host pid ${pid} remained alive after SIGKILL`);await recordEscalation(target,announced)}}async function stopManagedHost(pidFile,termTimeoutMs,target,readStartTime=readProcessStartTime){let announced=await announceStop(target,pidFile.pid);if(await signalValidated(pidFile,"SIGTERM",readStartTime),!await waitWhileSupervisorReports(target,termTimeoutMs,ms=>waitForGone(pidFile,ms,readStartTime))){if(await signalValidated(pidFile,"SIGKILL",readStartTime),!await waitForGone(pidFile,SIGKILL_GRACE_MS,readStartTime))throw new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);await recordEscalation(target,announced)}}async function waitWhileSupervisorReports(target,termTimeoutMs,waitFor){if(await waitFor(termTimeoutMs))return!0;let extended=!1;for(;;){let untilAt=await activeStopProgress(target.generation,Date.now(),STOP_PROGRESS_FRESH_MS);if(untilAt===void 0)return extended&&await waitFor(AFTER_STALL_WAIT_GRACE_MS);if(extended=!0,await waitFor(Math.min(STOP_PROGRESS_FRESH_MS,Math.max(1,untilAt-Date.now()))))return!0}}async function resolvePidFileOwnership(pidFile,readStartTime=readProcessStartTime){try{return await processMatchesPidFile(pidFile,readStartTime,processIsLive,{attempts:1})?"owns":"gone"}catch(error){if(error instanceof ProcessIdentityUnreadableError)return"unknown";throw error}}async function signalValidated(pidFile,signal,readStartTime=readProcessStartTime){await resolvePidFileOwnership(pidFile,readStartTime)==="owns"&&signalPid(pidFile.pid,signal)}async function waitForGone(pidFile,timeoutMs,readStartTime=readProcessStartTime){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await resolvePidFileOwnership(pidFile,readStartTime)==="gone")return!0;await delay(50)}return await resolvePidFileOwnership(pidFile,readStartTime)==="gone"}function signalPid(pid,signal){try{process.kill(pid,signal)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}import{existsSync}from"node:fs";import{basename,dirname as dirname2,join as join2,resolve as resolve2}from"node:path";import{fileURLToPath}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null,bundledSupervisor=resolveBundledSupervisorEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...runtimeExecArgv(),sibling,...supervisorArgs]}:bundledSupervisor!==null?{command:process.execPath,args:[...runtimeExecArgv(),bundledSupervisor,INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:{command:process.execPath,args:[...runtimeExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}var BUNDLED_SUPERVISOR_ENTRY="host-supervisor.js";function resolveBundledSupervisorEntryPath(){let entry=join2(dirname2(resolveCliMainPath()),BUNDLED_SUPERVISOR_ENTRY);return existsSync(entry)?entry:void 0}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath(import.meta.url);if(basename(dirname2(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname2(modulePath),`host-lifecycle${extension}`);return existsSync(sibling)?sibling:void 0}var SPAWNED_HOST_PROBE_TIMEOUT_MS=1e4;async function pollProtocolInfo(socket,timeoutMs,isCompatible2,childExit){let deadline=Date.now()+timeoutMs,lastProtocol;for(;Date.now()<=deadline;){let probe=holdProtocolInfo(socket,Math.min(SPAWNED_HOST_PROBE_TIMEOUT_MS,Math.max(1,deadline-Date.now()))),raced=childExit?await Promise.race([probe,childExit]):await probe;if(isChildExit(raced)){let held=await probe;if(!held)return{ready:!1,protocol:lastProtocol,exited:raced};if(lastProtocol=held.info,isCompatible2(held.info))return{ready:!0,protocol:held.info,hold:held.hold};held.hold.release()}else if(raced){if(lastProtocol=raced.info,isCompatible2(raced.info))return{ready:!0,protocol:raced.info,hold:raced.hold};raced.hold.release()}await delay2(50)}return{ready:!1,protocol:lastProtocol}}function isChildExit(value){return!!value&&"code"in value&&"signal"in value}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}var EXPECTED_RUNTIME_BUILD_ID_ENV="SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID",NEW_WORK_COMMANDS=new Set(["prompt","steer","follow_up","send_custom_message","continue_from_leaf","resume_session","append_user_message","bash","compact","wake","edit_assistant_message","edit_user_message"]),DEFAULT_POLL_MS=200,HostIdleHandover=class{constructor(options){this.options=options}view(){return this.operation?.view}admits(commandType){let state=this.operation?.view.state;return state===void 0||state==="handover_blocked"||!NEW_WORK_COMMANDS.has(commandType)}async begin(request){let current=this.operation;if(current!==void 0&¤t.view.operationId===request.operationId)return sameTerms(current.request,request)?answer(current):{kind:"refused",reason:"operation_conflict",detail:"this operation id names other terms"};if(current!==void 0&¤t.view.state!=="handover_blocked")return current.request.targetRuntimeBuildId===request.targetRuntimeBuildId?answer(current):{kind:"refused",reason:"handover_in_progress",detail:current.view.operationId};let self=this.options.identity();if(self.instanceId!==request.ifInstanceId||self.generation!==request.ifGeneration)return{kind:"refused",reason:"stale_generation",detail:`this host is ${self.instanceId} generation ${self.generation}`};if(self.runtimeBuildId===request.targetRuntimeBuildId)return{kind:"refused",reason:"already_current",detail:self.runtimeBuildId};let operation={request,view:{operationId:request.operationId,state:"handover_pending",targetRuntimeBuildId:request.targetRuntimeBuildId}};return this.operation=operation,this.options.log?.(`handover ${request.operationId} pending: no new work is admitted`),this.idleNow()?(await this.switchOver(operation),answer(operation)):(this.timer=setInterval(()=>this.observe(),this.options.pollMs??DEFAULT_POLL_MS),this.timer.unref?.(),answer(operation))}observe(){let operation=this.operation;operation?.view.state==="handover_pending"&&this.idleNow()&&this.switchOver(operation)}dispose(){this.stopTimer()}idleNow(){try{return this.options.isIdle()}catch(cause){return this.options.log?.(`handover idle check failed, waiting: ${String(cause)}`),!1}}async switchOver(operation){if(operation.view.state!=="handover_pending")return;this.stopTimer(),operation.view={...operation.view,state:"handover_switching"};let outcome=await this.options.perform(operation.request).catch(cause=>({ok:!1,reason:`successor_unavailable: ${String(cause)}`}));operation.view=outcome.ok?{...operation.view,state:"handover_completed",successor:outcome.successor}:{...operation.view,state:"handover_blocked",reason:outcome.reason},this.options.log?.(`handover ${operation.view.operationId} ${operation.view.state}`)}stopTimer(){this.timer!==void 0&&clearInterval(this.timer),this.timer=void 0}};function sameTerms(a,b){return a.targetRuntimeBuildId===b.targetRuntimeBuildId&&a.ifInstanceId===b.ifInstanceId&&a.ifGeneration===b.ifGeneration}function answer(operation){return{kind:"operation",view:operation.view}}function initialHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[ENV_AGENT_DIR]:options.agentDir??getAgentDir(),[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir})}function successorHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),...options.agentDir?{[ENV_AGENT_DIR]:options.agentDir}:{},[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir,...options.expectedRuntimeBuildId!==void 0&&{[EXPECTED_RUNTIME_BUILD_ID_ENV]:options.expectedRuntimeBuildId}})}var DEFAULT_READINESS_TIMEOUT_MS=1e4;async function startHost(paths,socket,options,generation=0){let testOptions=options._test,lifetimeOwner=options.owner?await callerHostOwner():null,instanceId=randomUUID(),stopTarget=reason=>({daemonDir:paths.dir,generation:generationPaths(paths,instanceId),instanceId,sender:ensureSender(),reason});process.platform==="win32"&&await createSocketSecret(socketSecretPath(socket)),await writeHostSettings(paths,{socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??9e5,generation,instanceId}),await writeHostOwner(generationPaths(paths,instanceId).dir,lifetimeOwner);let stderr=await open(paths.stderrLog,generation===0?"w":"a",384),pidFile,child,exitedEarly,childExit;try{let supervisorArgs=["--socket",socket,...options.owner?["--owner-fd",String(OWNER_WATCH_FD)]:[],...options.hostArgs??[]],launch=testOptions?.spawn??testOptions?.launch?.(supervisorArgs)??defaultHostLaunch(supervisorArgs);if(child=spawn(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:initialHostEnvironment({agentDir:options.agentDir,env:options.env,paths,instanceId,generation}),stdio:options.owner?["ignore","ignore",stderr.fd,"pipe"]:["ignore","ignore",stderr.fd]}),childExit=new Promise(resolveExit=>{child.once("exit",(code,signal)=>{exitedEarly={code,signal},resolveExit(exitedEarly)})}),options.owner&&keepOwnerPipe(child),child.pid===void 0)throw new Error("failed to spawn RPC socket host");let probe=testOptions?.readProcessStartTime??readProcessStartTime,observedStartTime=await Promise.race([waitForStartTime(child.pid,1e4,probe),childExit.then(()=>{throw new Error("RPC socket host exited before its start time could be read")})]),unhurriedProbe=testOptions?.readProcessStartTime?testOptions.readProcessStartTime:pid=>readProcessStartTime(pid,process.platform,15e3),processStartTime=observedStartTime??await unhurriedProbe(child.pid).catch(()=>{});pidFile={pid:child.pid,processStartTime:processStartTime??null},await testOptions?.beforePidFileWrite?.(),await writeHostRegistration(paths,{record:pidFile,socket,instanceId,generation,launchProfileId:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd()).profile_id,build:engineBuildIdentity()}),child.unref()}catch(error){let exitedBeforeCleanup=exitedEarly;if(!exitedBeforeCleanup&&child?.pid!==void 0&&childExit&&await stopUnregisteredStart(child,childExit,stopTarget("start_failed")),!exitedBeforeCleanup)throw await clearHostRegistration(paths),error;let diagnostic2=await appendStderr(paths,`RPC socket host exited with code ${exitedBeforeCleanup.code??"null"}${exitedBeforeCleanup.signal?` (${exitedBeforeCleanup.signal})`:""} before answering get_protocol_info`);throw await clearHostRegistration(paths),new Error(diagnostic2)}finally{await stderr.close()}let readinessTimeoutMs=testOptions?.readinessTimeoutMs??DEFAULT_READINESS_TIMEOUT_MS,result=await pollProtocolInfo(socket,readinessTimeoutMs,isCompatible,childExit);if(result.ready)return{pid:pidFile.pid,socket,reused:!1,release:result.hold.release};await testOptions?.beforeReadinessTeardown?.();let stopFailure=await stopSpawnedChild(child,childExit,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS,stopTarget("readiness_timeout")).then(()=>{},error=>error instanceof Error?error.message:String(error)),message=result.protocol?`RPC socket host answered get_protocol_info with protocolVersion ${result.protocol.protocolVersion}, serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with protocol version ${HOST_PROTOCOL_VERSION} and required capabilities ${JSON.stringify(REQUIRED_HOST_CAPABILITIES)}`:result.exited?`RPC socket host exited with code ${result.exited.code??"null"}${result.exited.signal?` (${result.exited.signal})`:""} before answering get_protocol_info`:`spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`,diagnostic=await appendStderr(paths,stopFailure===void 0?message:`${message} (teardown also reported: ${stopFailure})`);throw await clearHostRegistration(paths),new Error(diagnostic)}async function stopUnregisteredStart(child,childExit,target){let pid=child.pid,running=()=>child.exitCode===null&&child.signalCode===null;if(pid===void 0||!running())return;let announced=await announceStop(target,pid);try{signalPid(pid,"SIGTERM")}catch{}if(await Promise.race([childExit,delay(2e3)]),!running())return;try{signalPid(pid,"SIGKILL")}catch{}await Promise.race([childExit.then(()=>!0),delay(SIGKILL_GRACE_MS).then(()=>!1)])&&await recordEscalation(target,announced)}async function appendStderr(paths,message){try{let stderr=(await readFile2(paths.stderrLog,"utf8")).trim();return stderr?`${message}
|
|
3
3
|
${stderr}`:message}catch(error){if(isNodeErrorCode(error,"ENOENT"))return message;throw error}}import{appendFile}from"node:fs/promises";import{basename as basename2,join as join4}from"node:path";import{readFile as readFile3,rename,writeFile}from"node:fs/promises";import{join as join3}from"node:path";var GC_SKIP_INITIAL_BACKOFF_MS=10*6e4,GC_SKIP_MAX_BACKOFF_MS=1440*6e4,skipEntrySchema=external_exports.object({skipUntil:external_exports.number(),backoffMs:external_exports.number()}),markerSchema=external_exports.object({completedAt:external_exports.number(),cursor:external_exports.string().nullable(),examined:external_exports.number(),removed:external_exports.number(),stoppedBy:external_exports.enum(["time","count","exhausted"]),skip:external_exports.record(external_exports.string(),skipEntrySchema)});function hostGcPassMarkerPath(agentDir){return join3(agentDir,"rpc-host-daemon","gc-last-run.json")}function parseHostGcPassMarker(text){try{let parsed=markerSchema.safeParse(JSON.parse(text));return parsed.success?parsed.data:void 0}catch(error){if(error instanceof SyntaxError)return;throw error}}async function readHostGcPassMarker(agentDir){let text=await readFile3(hostGcPassMarkerPath(agentDir),"utf8").catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});return text===void 0?void 0:parseHostGcPassMarker(text)}async function writeHostGcPassMarker(agentDir,marker){let path=hostGcPassMarkerPath(agentDir),staged=`${path}.${process.pid}.tmp`;await writeFile(staged,`${JSON.stringify(marker)}
|
|
4
4
|
`,{mode:384}),await rename(staged,path)}function nextSkip(previous,now){let backoffMs=previous===void 0?GC_SKIP_INITIAL_BACKOFF_MS:Math.min(previous.backoffMs*2,GC_SKIP_MAX_BACKOFF_MS);return{skipUntil:now+backoffMs,backoffMs}}var OPPORTUNISTIC_GC_BUDGET={budgetMs:1500,maxEndpoints:32,minIntervalMs:3e5};async function gcHostEndpointsOpportunistically(options){let now=options.now??Date.now,budgetMs=options.budgetMs??OPPORTUNISTIC_GC_BUDGET.budgetMs,maxEndpoints=options.maxEndpoints??OPPORTUNISTIC_GC_BUDGET.maxEndpoints,minIntervalMs=options.minIntervalMs??OPPORTUNISTIC_GC_BUDGET.minIntervalMs,previous=await readHostGcPassMarker(options.agentDir),startedAt=now();if(previous!==void 0&&startedAt-previous.completedAt<minIntervalMs)return{ran:!1};process.platform!=="win32"&&await gcRpcPublicKeys(options.agentDir,{deadline:startedAt+budgetMs,maxRecords:maxEndpoints});let candidates=await gcCandidates(options),present=new Set(candidates.map(endpoint=>endpoint.name)),skip={};for(let[name,entry]of Object.entries(previous?.skip??{}))present.has(name)&&(skip[name]=entry);let cursor=previous?.cursor??null,examined=0,removed=0,stoppedBy="exhausted";for(let endpoint of rotateAfter(candidates,cursor)){if((skip[endpoint.name]?.skipUntil??0)>now())continue;if(examined>=maxEndpoints){stoppedBy="count";break}if(now()-startedAt>=budgetMs){stoppedBy="time";break}examined+=1,cursor=endpoint.name;let outcome=await gcEndpoint(endpoint.socket,endpoint.dir,{staleEngine:{}}).catch(()=>({removed:!1}));"stopped"in outcome?delete skip[endpoint.name]:outcome.removed?(removed+=1,delete skip[endpoint.name]):skip[endpoint.name]=nextSkip(skip[endpoint.name],now())}let marker={completedAt:now(),cursor,examined,removed,stoppedBy,skip};return await writeHostGcPassMarker(options.agentDir,marker),{ran:!0,marker}}var passesRunning=new Map;function scheduleOpportunisticHostGc(options){if(passesRunning.has(options.agentDir))return;let pass=new Promise(resolve6=>{setImmediate(()=>{gcHostEndpointsOpportunistically(options).then(()=>{},error=>recordPassFailure(options.agentDir,error)).finally(()=>{passesRunning.delete(options.agentDir),resolve6()})}).unref()});passesRunning.set(options.agentDir,pass)}async function gcCandidates(options){let targetName=basename2(createHostDaemonPaths({socket:options.exclude,agentDir:options.agentDir}).dir),candidates=[];for(let endpoint of await listHostEndpoints(options.agentDir)){let name=basename2(endpoint.dir);endpoint.socket===null||name===targetName||sameEndpoint(endpoint.socket,options.exclude)||candidates.push({...endpoint,socket:endpoint.socket,name})}return candidates}function rotateAfter(endpoints,cursor){if(cursor===null)return endpoints;let start=endpoints.findIndex(endpoint=>endpoint.name>cursor);return start<=0?endpoints:[...endpoints.slice(start),...endpoints.slice(0,start)]}async function recordPassFailure(agentDir,error){let line=`${new Date().toISOString()} gc pass failed: ${error instanceof Error?error.message:String(error)}
|
|
5
5
|
`;await appendFile(join4(agentDir,"rpc-host-daemon","gc-pass.log"),line,{mode:384}).catch(logError=>{logError instanceof Error&&"code"in logError&&logError.code==="ENOENT"||process.emitWarning(`host gc pass failed and could not be recorded: ${String(logError)}`)})}import{realpath as realpath2}from"node:fs/promises";import{basename as basename3,dirname as dirname3,resolve as resolve3}from"node:path";async function foreignAgentDirRefusal(socket,callerAgentDir,host){let hostAgentDir=host.agentDir??await layoutAgentDir(socket);if(hostAgentDir===void 0)return;let detail=await agentDirMismatch(socket,callerAgentDir,hostAgentDir);return detail===void 0?void 0:{action:"refuse",reason:"foreign_agent_dir",upgradeable:!1,detail}}async function agentDirMismatch(socket,callerAgentDir,hostAgentDir){let[ours,theirs]=await Promise.all([canonicalDirectory(callerAgentDir),canonicalDirectory(hostAgentDir)]);if(theirs!==ours)return`${socket} is served by the host of agent dir ${theirs}, and this client's agent dir is ${ours}; a host is only replaced by a client of its own agent dir - run with that agent dir to upgrade it, or use a socket of your own`}async function layoutAgentDir(socket){let rpcDirectory=dirname3(socket);if(basename3(socket)!=="rpc.sock"||basename3(rpcDirectory)!=="rpc")return;let agentDir=dirname3(rpcDirectory),paths=createHostDaemonPaths({socket,agentDir});return await provenOwner(await readHostRegistration(paths),socket)===void 0?void 0:agentDir}async function canonicalDirectory(path){return realpath2(path).catch(()=>resolve3(path))}import{spawn as spawn2}from"node:child_process";import{randomUUID as randomUUID2}from"node:crypto";import{open as open2,rm,writeFile as writeFile2}from"node:fs/promises";var DEFAULT_HANDOFF_READINESS_MS=3e4,SUCCESSOR_EXIT_WAIT_MS=5e3,SUCCESSOR_START_BUDGET_MS=1e4+DEFAULT_HANDOFF_READINESS_MS+2e3+SUCCESSOR_EXIT_WAIT_MS;async function startSuccessor(context){let{options,paths,host,owner,drainGate}=context,generation=(host.generation??0)+1,instanceId=randomUUID2(),bindSocket=generationBindPath(options.socket,generation);if(Buffer.byteLength(bindSocket)>MAX_SOCKET_PATH_BYTES)return{action:"refuse",reason:"socket_path_too_long",upgradeable:!0,detail:bindSocket};let replaced=await statSocketIdentity(options.socket);if(!replaced)return{action:"refuse",reason:"socket_replaced",upgradeable:!0};let running=await readHostSettings(paths),lifetimeOwner=host.instanceId?await readHostOwner(generationPaths(paths,host.instanceId).dir):null,inheritOwnerPipe=lifetimeOwner?.pid===process.pid&&sameHostOwner(lifetimeOwner,await callerHostOwner()),bootSettings=await readFileOrUndefined(paths.settingsFile);await writeHostSettings(paths,{socket:options.socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??running?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??running?.idleExitMs??9e5,generation,instanceId});let child,exited;try{await writeHostOwner(generationPaths(paths,instanceId).dir,lifetimeOwner??null),await options._test?.beforeSpawn?.();let argv=["--socket",options.socket,"--bind",bindSocket,"--replace",`${replaced.dev}:${replaced.ino}`,...inheritOwnerPipe?["--owner-fd",String(OWNER_WATCH_FD)]:[],...options.hostArgs??[]],launch=(options._test?.launch??options.launch)?.(argv)??defaultHostLaunch(argv),stderr=await open2(paths.stderrLog,"a",384),spawned=spawn2(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:successorHostEnvironment({agentDir:options.agentDir,env:options.env,expectedRuntimeBuildId:options.expectedRuntimeBuildId,paths,generation,instanceId}),stdio:inheritOwnerPipe?["ignore","ignore",stderr.fd,"pipe"]:["ignore","ignore",stderr.fd]});if(child=spawned,exited=new Promise(resolve6=>spawned.once("exit",()=>resolve6())),await stderr.close(),inheritOwnerPipe&&keepOwnerPipe(spawned),child.pid===void 0)throw new Error("failed to spawn the successor generation");let processStartTime=await waitForStartTime(child.pid,1e4).catch(()=>{})??null,registration={record:{pid:child.pid,processStartTime},socket:options.socket,instanceId,generation,launchProfileId:hostLaunchProfile(["--mode","rpc","--multi-session",...options.hostArgs??[]],process.cwd()).profile_id};await writeGenerationRecord(paths,registration),await options._test?.afterSpawn?.(child.pid);let answer2=await awaitSuccessor(options,host,exited);if(!answer2){let reason=await abortReason(options.socket,replaced),cleanupFailure=await abandonSuccessor({child,exited,paths,instanceId,bootSettings,reason:"successor_readiness_timeout"});return{action:"refuse",reason,upgradeable:!0,...cleanupFailure&&{detail:cleanupFailure}}}return await options._test?.beforeRegistration?.(),await writeHostRegistration(paths,{...registration,...successorBuild(answer2)}),child.unref(),owner!==void 0&&(drainGate===void 0||await drainGate())&&signalGeneration(owner.pid,"SIGUSR1"),{action:"handoff",pid:child.pid,socket:options.socket,generation:answer2.generation??generation,instanceId:answer2.instanceId??""}}catch(cause){let cleanupFailure=await abandonSuccessor({child,exited,paths,instanceId,bootSettings,reason:"successor_start_failed"}),detail=cause instanceof Error?cause.message:String(cause);return{action:"refuse",reason:"successor_unavailable",upgradeable:!0,detail:cleanupFailure?`${detail}; ${cleanupFailure}`:detail}}}async function abandonSuccessor(context){let{child,exited,paths,instanceId,bootSettings}=context,target={daemonDir:paths.dir,generation:generationPaths(paths,instanceId),instanceId,sender:{pid:process.pid,kind:"successor"},reason:context.reason},killed=child?.pid!==void 0&&child.exitCode===null&&child.signalCode===null?await announceStop(target,child.pid):void 0;killed!==void 0&&child?.pid!==void 0&&signalPid(child.pid,"SIGKILL");try{bootSettings===void 0?await rm(paths.settingsFile,{force:!0}):await writeFile2(paths.settingsFile,bootSettings,{mode:HOST_STATE_FILE_MODE}),child?.pid===void 0?await rm(generationPaths(paths,instanceId).dir,{recursive:!0,force:!0}):exited!==void 0&&await exitedWithin(exited,SUCCESSOR_EXIT_WAIT_MS)&&(killed!==void 0&&await recordEscalation(target,killed),await releaseGeneration(paths,{instanceId,pid:child.pid}));return}catch(cause){return`successor cleanup failed: ${cause instanceof Error?cause.message:String(cause)}`}}async function exitedWithin(exited,ms){let timer,timedOut=new Promise(resolve6=>{timer=setTimeout(()=>resolve6(!1),ms)});try{return await Promise.race([exited.then(()=>!0),timedOut])}finally{clearTimeout(timer)}}function successorBuild(answer2){return answer2.engineVersion===void 0||answer2.engineOrdinal===void 0?{}:{build:{text:answer2.engineVersion,ordinal:answer2.engineOrdinal}}}async function awaitSuccessor(options,previous,exited){let deadline=Date.now()+(options._test?.readinessTimeoutMs??DEFAULT_HANDOFF_READINESS_MS),childGone=!1;for(exited.then(()=>{childGone=!0});Date.now()<=deadline;){let answer2=await probeProtocolInfo(options.socket,2e3);if(answer2&&answer2.instanceId!==void 0&&answer2.instanceId!==previous.instanceId)return answer2;if(childGone)return;await delay3(50)}}async function abortReason(socket,replaced){let current=await statSocketIdentity(socket).catch(()=>{});return current===void 0||current.dev!==replaced.dev||current.ino!==replaced.ino?"socket_replaced":"successor_unavailable"}function delay3(ms){return new Promise(resolve6=>setTimeout(resolve6,ms))}var SESSION_COUNT_TIMEOUT_MS=1e4;async function handoffUnregisteredHost(options,paths,host){let counted=await holdSessionCount(options.socket,SESSION_COUNT_TIMEOUT_MS);try{let legacy=await provenLegacyOwner(paths,options.socket),sessions=counted?.sessions;if(sessions!==0)return legacy!==void 0?{action:"refuse",reason:"legacy_host",upgradeable:!0,detail:busyLegacyHostDetail(legacy.pid,options.socket,sessions)}:{action:"refuse",reason:"unknown_owner",upgradeable:!0,detail:`${options.socket} has no provable owner and holds ${describeSessions(sessions)}; it is never signalled - let that work finish, then retry`};let result=await startSuccessor({options,paths,host,owner:legacy,drainGate:async()=>await counted?.recount(SESSION_COUNT_TIMEOUT_MS)===0});return result.action==="handoff"&&legacy===void 0&&warnUnsignalledPredecessor(options.socket,host),result}finally{counted?.close()}}function warnUnsignalledPredecessor(socket,host){process.stderr.write(`generation handoff: no provable owner for ${socket}; the host it replaced (instance ${host.instanceId??"unknown"}, engine ${host.engineVersion??"unknown"}) listed 0 sessions and was not signalled; it drains itself on losing the public socket
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CONFIG_COMMAND_ARGV,HOST_COMMAND_ARGV,SCHEDULE_COMMAND_ARGV,isPackageCommandArgv}from"./chunk-
|
|
2
|
+
import{CONFIG_COMMAND_ARGV,HOST_COMMAND_ARGV,SCHEDULE_COMMAND_ARGV,isPackageCommandArgv}from"./chunk-XBUSVKWC.js";import{homedir}from"node:os";try{process.cwd()}catch{let fallback=homedir();process.chdir(fallback),console.error(`the current working directory no longer exists; continuing from ${fallback}`)}import*as nodeModule from"node:module";async function enableStartupCompileCache(){let enable=nodeModule.enableCompileCache;if(typeof enable!="function")return;let args=process.argv.slice(2);if(!isPackageCommandArgv(args)&&args[0]!==CONFIG_COMMAND_ARGV&&(args.includes("--version")||args.includes("-v")))return;let scheduleWatch=!1;if(args[0]===SCHEDULE_COMMAND_ARGV&&args[1]==="run")for(let index=2;index<args.length;index++){let arg=args[index];arg==="--watch"?scheduleWatch=!0:["--exec","--poll-seconds","--timeout-seconds","--concurrency"].includes(arg??"")&&index++}if(!(isPackageCommandArgv(args)||args[0]===HOST_COMMAND_ARGV||args[0]===SCHEDULE_COMMAND_ARGV&&!scheduleWatch)){if(!scheduleWatch&&args.some(arg=>["--help","-h","--export","--list-models","--list-tips"].includes(arg)))try{let{parseArgs}=await import("./args-JXULI4EH.js"),parsed=parseArgs(args);if(parsed.version||parsed.export||parsed.listModels!==void 0||parsed.listTips||parsed.help&&!(parsed.mode==="rpc"&&parsed.multiSession))return}catch{}try{let result=enable();result.directory!==void 0&&process.env.NODE_COMPILE_CACHE===void 0&&(process.env.NODE_COMPILE_CACHE=result.directory)}catch{}}}export{enableStartupCompileCache};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{isTuiControlSocket}from"./chunk-
|
|
2
|
+
import{isTuiControlSocket}from"./chunk-OI4NMCKP.js";import{HOST_DAEMON_LAYOUT,createHostDaemonPaths,hostDaemonDirectoryPaths,parseJson,readFileOrUndefined,socketNamesDirectory}from"./chunk-4WZRVZNX.js";import{readdir}from"node:fs/promises";import{basename,join}from"node:path";var ENDPOINT_DIRECTORY_NAME=/^[0-9a-f]{16}$/;async function listHostEndpoints(agentDir){let flatDir=join(agentDir,"rpc-host-daemon");if(parseJson(await readFileOrUndefined(join(flatDir,"layout.json")).catch(()=>{}))?.layout!==HOST_DAEMON_LAYOUT)return[];let dirs=(await readdir(flatDir,{withFileTypes:!0}).catch(()=>[])).filter(entry=>entry.isDirectory()&&ENDPOINT_DIRECTORY_NAME.test(entry.name)).map(entry=>join(flatDir,entry.name)).sort(),endpoints=[];for(let dir of dirs)endpoints.push(await identifyEndpoint(dir));return endpoints}async function identifyEndpoint(dir){let paths=hostDaemonDirectoryPaths(dir),named=await recordNaming(paths.endpointFile,dir);if(named!==void 0)return{socket:named.socket,dir,identity:"endpoint",endpoint_kind:endpointKindOf(named.record)};let booted=await recordNaming(paths.settingsFile,dir);if(booted!==void 0)return{socket:booted.socket,dir,identity:"settings",endpoint_kind:"rpc_host"};let generations=await readdir(paths.generationsDir).catch(()=>[]);for(let instanceId of generations.sort()){let recorded=await recordNaming(join(paths.generationsDir,instanceId,"settings.json"),dir);if(recorded!==void 0)return{socket:recorded.socket,dir,identity:"generation-settings",endpoint_kind:"rpc_host"}}return{socket:null,dir,identity:"unknown",endpoint_kind:"rpc_host"}}async function endpointKindOfSocket(socket,agentDir){if(isTuiControlSocket(socket))return"tui";let paths=createHostDaemonPaths({socket,agentDir}),named=await recordNaming(paths.endpointFile,paths.dir);return named===void 0?"rpc_host":endpointKindOf(named.record)}function endpointKindOf(record){return record.endpoint_kind==="tui"?"tui":"rpc_host"}async function recordNaming(file,dir){let record=parseJson(await readFileOrUndefined(file).catch(()=>{})),socket=record?.socket;if(!(record===void 0||typeof socket!="string"||socket===""))return socketNamesDirectory(socket,basename(dir))?{socket,record}:void 0}export{listHostEndpoints,endpointKindOfSocket};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{RPC_ERROR_SESSION_NOT_ATTACHED,RPC_ERROR_UNKNOWN_COMMAND,SUMMARIZATION_MAX_DURATION_CAP_MS,SUMMARIZATION_TOTAL_BUDGET_MS,clientMessageIdentity,isAbortGraceInRange}from"./chunk-GY5MR5KR.js";import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{DETACH_CONNECTION_CAPABILITY}from"./chunk-
|
|
2
|
+
import{RPC_ERROR_SESSION_NOT_ATTACHED,RPC_ERROR_UNKNOWN_COMMAND,SUMMARIZATION_MAX_DURATION_CAP_MS,SUMMARIZATION_TOTAL_BUDGET_MS,clientMessageIdentity,isAbortGraceInRange}from"./chunk-GY5MR5KR.js";import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{DETACH_CONNECTION_CAPABILITY}from"./chunk-W2BKZBYJ.js";import{connectAuthenticatedRpcSocket,socketNeedsHandshake}from"./chunk-OI4NMCKP.js";import{ORIGIN_HOST_INSTANCE_FIELD,attachJsonlLineReader,originHostInstance,serializeJsonLine}from"./chunk-WFXUCVIR.js";import{fuzzyFilter}from"./chunk-FDL4CF6F.js";import{readSocketSecret,resolveSocketTransportAddress,sendSocketHandshake,socketSecretPath}from"./chunk-ZGAB7WQA.js";var COMMAND_TOKEN=/^\/[A-Za-z][A-Za-z0-9:_-]*$/,MAX_SUGGESTIONS=3,UnknownCommandError=class extends Error{constructor(command,suggestions,reason){super(formatUnknownCommandMessage(command,suggestions,reason)),this.name="UnknownCommandError",this.command=command,this.suggestions=suggestions,this.reason=reason}};function formatUnknownCommandMessage(command,suggestions,reason){if(reason==="interactive_only")return`/${command} is an interactive command and cannot be sent as a prompt.`;let hint=suggestions.length===0?"":` Did you mean ${suggestions.map(name=>`/${name}`).join(", ")}?`;return`Unknown command /${command}.${hint}`}var UNKNOWN_COMMAND_CONFIRM_HINT='Resend with "unknownCommandAsText": true to send it as text.';function unknownCommandErrorFromWire(data){if(typeof data!="object"||data===null)return;let command=Reflect.get(data,"command"),suggestions=Reflect.get(data,"suggestions"),reason=Reflect.get(data,"reason");if(typeof command!="string"||!Array.isArray(suggestions)||reason!=="unknown"&&reason!=="interactive_only")return;let names=suggestions.filter(name=>typeof name=="string");return new UnknownCommandError(command,names,reason)}function commandShapedName(text){let token=text.trim().split(/\s/,1)[0]??"";return COMMAND_TOKEN.test(token)?token.slice(1):void 0}function findUnknownCommand(text,catalog){let command=commandShapedName(text);if(command===void 0||catalog.promptCommands.has(command))return;if(catalog.interactiveCommands.has(command))return new UnknownCommandError(command,[],"interactive_only");let known=[...new Set([...catalog.promptCommands,...catalog.interactiveCommands])],suggestions=fuzzyFilter(known,command,name=>name).slice(0,MAX_SUGGESTIONS);return new UnknownCommandError(command,suggestions,"unknown")}import{existsSync}from"node:fs";function getMissingSessionCwdIssue(sessionManager,fallbackCwd){let sessionFile=sessionManager.getSessionFile();if(!sessionFile)return;let sessionCwd=sessionManager.getCwd();if(!(!sessionCwd||existsSync(sessionCwd)))return{sessionFile,sessionCwd,fallbackCwd}}function formatMissingSessionCwdError(issue){let sessionFile=issue.sessionFile?`
|
|
3
3
|
Session file: ${issue.sessionFile}`:"";return`Stored session working directory does not exist: ${issue.sessionCwd}${sessionFile}
|
|
4
4
|
Current working directory: ${issue.fallbackCwd}`}function formatMissingSessionCwdPrompt(issue){return`cwd from session file does not exist
|
|
5
5
|
${issue.sessionCwd}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
+
import{execFile,execFileSync}from"node:child_process";var WINDOWS_FILETIME_EPOCH=116444736000000000n,PROCESS_START_TOLERANCE_MS=3e3;function processStartTimeMs(identity){if(/^\d+$/.test(identity)){let parsed2=Number((BigInt(identity)-WINDOWS_FILETIME_EPOCH)/10000n);return Number.isFinite(parsed2)?parsed2:void 0}let localIdentity=identity.trim(),korean=/^(\d{4})\uB144\s+(\d{1,2})\uC6D4\s+(\d{1,2})\uC77C\s+[\uC6D4\uD654\uC218\uBAA9\uAE08\uD1A0\uC77C]\uC694\uC77C\s+(\d{1,2})\uC2DC\s+(\d{1,2})\uBD84\s+(\d{1,2})\uCD08$/.exec(localIdentity),japanese=/^[\u65E5\u6708\u706B\u6C34\u6728\u91D1\u571F](?:\u66DC\u65E5)?\s+(\d{1,2})\/\s*(\d{1,2})\s+(\d{2}):(\d{2}):(\d{2})\s+(\d{4})$/.exec(localIdentity),parts=korean?korean.slice(1):japanese?[japanese[6],japanese[1],japanese[2],japanese[3],japanese[4],japanese[5]]:void 0;if(parts===void 0){let parsed2=Date.parse(identity);return Number.isFinite(parsed2)?parsed2:void 0}let[year=NaN,month=NaN,day=NaN,hour=NaN,minute=NaN,second=NaN]=parts.map(Number),parsed=new Date(year,month-1,day,hour,minute,second,0);return parsed.getFullYear()===year&&parsed.getMonth()===month-1&&parsed.getDate()===day&&parsed.getHours()===hour&&parsed.getMinutes()===minute&&parsed.getSeconds()===second?parsed.getTime():void 0}function sameProcessStartMs(recorded,observed){return recorded!==void 0&&observed!==void 0&&Number.isFinite(recorded)&&Number.isFinite(observed)&&Math.abs(recorded-observed)<=PROCESS_START_TOLERANCE_MS}function parseDaemonPidFile(text){let parsed;try{parsed=JSON.parse(text)}catch(error){if(error instanceof SyntaxError)return;throw error}let unguarded=parsed!==null&&isRecord(parsed)&&parsed.processStartTime===null;if(!(!isRecord(parsed)||typeof parsed.pid!="number"||!unguarded&&typeof parsed.processStartTime!="string")&&!(!Number.isInteger(parsed.pid)||parsed.pid<=0)){if(unguarded)return{pid:parsed.pid,processStartTime:null};if(!(typeof parsed.processStartTime!="string"||parsed.processStartTime.trim()===""))return{pid:parsed.pid,processStartTime:parsed.processStartTime}}}var ProcessIdentityUnreadableError=class extends Error{constructor(pid,attempts,cause){super(`process identity for live pid ${pid} stayed unreadable after ${attempts} probe attempt(s): ${cause instanceof Error?cause.message:String(cause)}`),this.name="ProcessIdentityUnreadableError",this.pid=pid,this.attempts=attempts,this.cause=cause}};async function processMatchesPidFile(pidFile,readStartTime=readProcessStartTime,isLive=processIsRunning,retry={}){if(pidFile.processStartTime===null){if(!isLive(pidFile.pid))return!1;throw new ProcessIdentityUnreadableError(pidFile.pid,0,new Error("pidfile carries no process identity guard"))}let attempts=Math.max(1,retry.attempts??5),delayMs=retry.delayMs??200,lastError;for(let attempt=1;attempt<=attempts;attempt++)try{let current=await readStartTime(pidFile.pid);if(current!==void 0){let recorded=processStartTimeMs(pidFile.processStartTime),observed=processStartTimeMs(current);if(recorded!==void 0&&observed!==void 0)return sameProcessStartMs(recorded,observed)}if(!isLive(pidFile.pid))return!1;lastError=new Error("process identity probe returned no usable identity for a live process"),attempt<attempts&&await new Promise(resolve=>setTimeout(resolve,delayMs))}catch(error){if(!isLive(pidFile.pid))return!1;lastError=error,attempt<attempts&&await new Promise(resolve=>setTimeout(resolve,delayMs))}throw new ProcessIdentityUnreadableError(pidFile.pid,attempts,lastError)}async function readProcessIdentity(pid,platform=process.platform,timeoutMs,isLive=processIsLive,timeZone){let command=platform==="win32"?{executable:"powershell.exe",args:["-NoProfile","-NonInteractive","-Command",`$process = Get-CimInstance Win32_Process -Filter "ProcessId=${String(pid)}" -ErrorAction Stop; if ($null -eq $process) { Write-Output '__SENPI_ABSENT__'; exit 0 }; $process.CreationDate.ToFileTimeUtc().ToString("D", [Globalization.CultureInfo]::InvariantCulture)`]}:{executable:"ps",args:["-o","stat=,lstart=","-p",String(pid)]};return new Promise(resolve=>{let effectiveTimeoutMs=timeoutMs??(platform==="win32"?1e3:void 0);execFile(command.executable,command.args,{windowsHide:!0,...effectiveTimeoutMs===void 0?{}:{timeout:effectiveTimeoutMs},...platform==="win32"&&timeZone===void 0?{}:{env:{...process.env,LC_ALL:"C",LANG:"C",...timeZone?{TZ:timeZone}:{}}}},(error,stdout)=>{if(error){let code="code"in error?error.code:void 0;if(platform!=="win32"&&code===1||!isLive(pid)){resolve({kind:"absent"});return}resolve({kind:"error",error});return}let snapshot=stdout.trim();if(snapshot==="__SENPI_ABSENT__")return resolve({kind:"absent"});let state=platform==="win32"?"":snapshot.split(/\s+/,1)[0]??"";if(state.startsWith("Z"))return resolve({kind:"absent"});let output=platform==="win32"?snapshot:snapshot.slice(state.length).trim();if(!output||platform==="win32"&&!/^\d+$/.test(output))return resolve({kind:"error",error:new Error("invalid process identity output")});resolve({kind:"present",identity:timeZone&&platform!=="win32"?`${output} UTC`:output})}).once("error",error=>resolve({kind:"error",error}))})}async function readProcessStartTime(pid,platform=process.platform,timeoutMs){return readProcessIdentity(pid,platform,timeoutMs).then(result=>{if(result.kind==="error")throw result.error;return result.kind==="present"?result.identity:void 0})}function processIsRunning(pid){if(!processIsLive(pid))return!1;if(process.platform==="win32")return!0;try{return!execFileSync("ps",["-o","stat=","-p",String(pid)],{encoding:"utf8",timeout:2e3}).trim().startsWith("Z")}catch(error){return!(error instanceof Error&&"status"in error&&error.status===1)}}function processIsLive(pid){try{return process.kill(pid,0),!0}catch(error){if(isNodeErrorCode(error,"ESRCH"))return!1;if(isNodeErrorCode(error,"EPERM"))return!0;throw error}}async function waitForStartTime(pid,timeoutMs,readStartTime=readProcessStartTime,isLive=processIsLive){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){let startTime;try{startTime=await readStartTime(pid)}catch{}if(startTime)return startTime;await delay(20)}if(!isLive(pid))throw new Error(`spawned daemon pid ${pid} had no process start time`)}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}export{PROCESS_START_TOLERANCE_MS,processStartTimeMs,sameProcessStartMs,parseDaemonPidFile,ProcessIdentityUnreadableError,processMatchesPidFile,readProcessIdentity,readProcessStartTime,processIsRunning,processIsLive,waitForStartTime};
|
|
@@ -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
|
-
import{ORIGIN_HOST_INSTANCE_FIELD,RPC_AUTH_HEX,RPC_LAUNCH_ID,RpcEndpointAuthError,attachJsonlLineReader,authRecord,originHostInstance,readRpcKeyRecord,rpcAuthProof,rpcProofMatches,serializeJsonLine}from"./chunk-
|
|
2
|
+
import{ORIGIN_HOST_INSTANCE_FIELD,RPC_AUTH_HEX,RPC_LAUNCH_ID,RpcEndpointAuthError,attachJsonlLineReader,authRecord,originHostInstance,readRpcKeyRecord,rpcAuthProof,rpcProofMatches,serializeJsonLine}from"./chunk-WFXUCVIR.js";import{SOCKET_HANDSHAKE_TIMEOUT_MS}from"./chunk-ZGAB7WQA.js";import{getAgentDir}from"./chunk-7YO7VQZW.js";import{createHash}from"node:crypto";import{basename}from"node:path";var TUI_SOCKET_NAME=/^t-[0-9a-f]{16}\.sock$/;function tuiSocketName(instanceId){return`t-${createHash("sha256").update(instanceId,"utf8").digest("hex").slice(0,16)}.sock`}function isTuiControlSocket(socket){return TUI_SOCKET_NAME.test(basename(socket))}function socketNeedsHandshake(socket,platform=process.platform){return platform==="win32"||isTuiControlSocket(socket)}import{AsyncLocalStorage}from"node:async_hooks";import{randomBytes}from"node:crypto";import{createConnection}from"node:net";var keyRoots=new AsyncLocalStorage;function withRpcKeyRoot(root,operation){return keyRoots.run(root,operation)}function rpcKeyRoot(options={},defaultRoot){return options.keyRoot??keyRoots.getStore()??process.env.SENPI_RPC_KEY_ROOT??defaultRoot??getAgentDir()}async function connectAuthenticatedRpcSocket(path,first={type:"get_protocol_info",id:"rpc-auth-protocol",observe:!0,[ORIGIN_HOST_INSTANCE_FIELD]:originHostInstance()},options={},timeoutMs=SOCKET_HANDSHAKE_TIMEOUT_MS){let deadline=Date.now()+timeoutMs;for(let attempt=0;;attempt++){let socket=createConnection(path),earlyError,ignoreLateError=error=>{earlyError??=error};socket.on("error",ignoreLateError);let connected=!1;socket.once("connect",()=>{connected=!0});try{let protocol=await authenticate(socket,path,first,rpcKeyRoot(options),Math.max(1,deadline-Date.now()));return socket.off("error",ignoreLateError),{socket,protocol}}catch(cause){if(socket.destroy(),attempt===0&&cause instanceof RpcEndpointAuthError&&cause.code==="auth_failed")continue;let failure=!(cause instanceof RpcEndpointAuthError)&&earlyError!==void 0?earlyError:cause;throw failure instanceof Error&&Object.assign(failure,{rpcSocketConnected:connected}),failure}}}async function authenticate(socket,path,first,root,timeoutMs){let pending,reject=error=>pending?.reject(error),socketError,onClose=()=>setImmediate(()=>reject(socketError??new Error(`RPC socket closed during authentication: ${path}`))),onError=error=>{socketError??=error,reject(error)};socket.on("error",onError),socket.on("close",onClose);let detach=attachJsonlLineReader(socket,line=>{let response;try{response=authRecord(JSON.parse(line))}catch{return}if(!(response===void 0||pending===void 0||response.id!==pending.id))if(response.success===!0)pending?.resolve(response);else{let code=response.errorCode;reject(code==="auth_failed"||code==="auth_required"?new RpcEndpointAuthError(code,`${path}; set SENPI_RPC_KEY_ROOT to the host's agent dir (${root})`):new Error(`RPC authentication probe refused on ${path}: ${String(response.error)}`))}},{maxLineLength:1024*1024,onOversizedLine:()=>socket.destroy()}),exchange=request=>new Promise((resolve,reject2)=>{if(socket.destroyed){setImmediate(()=>reject2(socketError??new Error(`RPC socket closed during authentication: ${path}`)));return}pending={id:request.id,resolve,reject:reject2},socket.write(serializeJsonLine(request))}),timer=setTimeout(()=>{reject(new Error(`RPC authentication timed out on ${path}`)),socket.destroy()},timeoutMs);try{let nonce=randomBytes(32).toString("hex"),response=await exchange({...first,auth:{client_nonce:nonce}}),data=authRecord(response.data);if(data?.auth===void 0)return response;let auth=authRecord(data.auth);if(typeof auth?.launch_id!="string"||!RPC_LAUNCH_ID.test(auth.launch_id)||typeof auth.server_nonce!="string"||!RPC_AUTH_HEX.test(auth.server_nonce))throw new RpcEndpointAuthError("host_identity_unproven",path);let record=await readRpcKeyRecord(root,auth.launch_id);if(socket.destroyed)throw new Error(`RPC authentication timed out on ${path}`);if(record===void 0)return process.stderr.write(`senpi rpc client: no key record for launch ${auth.launch_id} under ${root}; continuing unauthenticated (refused from the next release; set SENPI_RPC_KEY_ROOT to the host's agent dir)
|
|
3
3
|
`),response;if(typeof record.key!="string")throw new RpcEndpointAuthError("unsafe_key_record",root);let key=Buffer.from(record.key,"hex");if(!rpcProofMatches(rpcAuthProof(key,"server",auth.launch_id,nonce,auth.server_nonce),auth.server_proof))throw new RpcEndpointAuthError("host_identity_unproven",path);return await exchange({id:"rpc-authenticate",type:"authenticate",client_proof:rpcAuthProof(key,"client",auth.launch_id,auth.server_nonce,nonce)}),response}finally{clearTimeout(timer),detach(),socket.off("error",onError),socket.off("close",onClose)}}export{tuiSocketName,isTuiControlSocket,socketNeedsHandshake,withRpcKeyRoot,rpcKeyRoot,connectAuthenticatedRpcSocket};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{listHostEndpoints}from"./chunk-
|
|
2
|
+
import{listHostEndpoints}from"./chunk-LYGAV6KU.js";import{randomBytes}from"node:crypto";var MONITOR_ID_ALPHABET="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function allocateMonitorId(){let id="mon_",buffer=0,bits=0;for(let byte of randomBytes(10))for(buffer=buffer<<8|byte,bits+=8;bits>=5;)bits-=5,id+=MONITOR_ID_ALPHABET[buffer>>bits&31];return id}var STATUS_KINDS=new Set(["session_status","effect_status"]);function parseRpcTarget(target,selfDurableId){let trimmed=target.trim();return trimmed===""?{error:'target is empty; pass "children", "all" or a session id, path or st_ task id'}:trimmed==="children"?selfDurableId===void 0?{error:'target "children" needs a session with a durable id; save the session first, or watch "all"'}:{kind:"children",parent:selfDurableId}:trimmed==="all"?{kind:"all"}:trimmed.startsWith("st_")?{kind:"task",taskId:trimmed}:{kind:"id",id:trimmed}}function defaultEvents(target){return target.kind==="children"?["session_status","effect_status"]:["session_status"]}function subscriptionFor(target,events){let sessions=target.kind==="children"?{childrenOf:target.parent}:target.kind==="id"?{ids:[target.id]}:"all",content=events==="all"?"all":events.filter(kind=>!STATUS_KINDS.has(kind)),mirror=content==="all"?"all":content.length===0?void 0:content;return{sessions,include_workers:!0,include_context:target.kind==="children"||target.kind==="task",effects:events==="all"||events.includes("effect_status"),...mirror===void 0?{}:{mirror}}}function wantsRecord(events,exclude,type){return exclude.includes(type)?!1:events==="all"||events.includes(type)}function matchesTask(target,row){return target.kind!=="task"?!0:row.context?.task_id===target.taskId}async function endpointSockets(agentDir){return(await listHostEndpoints(agentDir)).map(endpoint=>endpoint.socket).filter(socket=>socket!==null)}export{allocateMonitorId,parseRpcTarget,defaultEvents,subscriptionFor,wantsRecord,matchesTask,endpointSockets};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{Text}from"./chunk-FDL4CF6F.js";import{getShellConfig}from"./chunk-BWA4FVFW.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId}from"./chunk-V3CK2AVC.js";import{typebox_exports}from"./chunk-MIENF2YK.js";import{TOOL_CHILD_LEDGER_ENV,TOOL_CHILD_REENTRY_ENV,TOOL_CHILD_REFS_ROOT_ENV,rememberToolChildReentry,scrubToolChildEnv,toolChildReentry}from"./chunk-OXNWERO4.js";import{BACKGROUND_START_GRACE_MS,DEFAULT_COLS,DEFAULT_MAX_SESSIONS,DEFAULT_ROWS,FOREGROUND_ENV_OVERRIDES,KILLED_SESSION_EXIT_GRACE_MS,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,encodeKeys,loadPty,safeRegExp}from"./chunk-NTK2MHJ5.js";import{processIsLive,processStartTimeMs,readProcessStartTime,sameProcessStartMs}from"./chunk-7ASLQ243.js";var ToolChildJobError=class extends Error{constructor(code,message){super(message),this.code=code,this.name="ToolChildJobError"}};var WakeAdmissionError=class extends Error{constructor(bytes){super(`wake_too_large: ${bytes} bytes exceeds the ${TOOL_CHILD_LIMITS.wakePendingBytes}-byte pending budget`),this.code="wake_too_large",this.name="WakeAdmissionError"}},WakeAdmission=class{#pending=new Map;#blocked=[];#pendingBytes=0;get pending(){return this.#pending.size}get blocked(){return this.#blocked.length}send(wakeId,bytes){return bytes>TOOL_CHILD_LIMITS.wakePendingBytes?Promise.reject(new WakeAdmissionError(bytes)):this.#blocked.length===0&&this.#fits(bytes)?(this.#admit(wakeId,bytes),Promise.resolve()):new Promise(release=>{this.#blocked.push({wakeId,bytes,release})})}ack(wakeId){let bytes=this.#pending.get(wakeId);if(bytes!==void 0){this.#pending.delete(wakeId),this.#pendingBytes-=bytes;for(let next=this.#blocked[0];next!==void 0&&this.#fits(next.bytes);next=this.#blocked[0])this.#blocked.shift(),this.#admit(next.wakeId,next.bytes),next.release()}}#fits(bytes){return this.#pending.size<TOOL_CHILD_LIMITS.wakePending&&this.#pendingBytes+bytes<=TOOL_CHILD_LIMITS.wakePendingBytes}#admit(wakeId,bytes){this.#pending.set(wakeId,bytes),this.#pendingBytes+=bytes}};function hostCallCapacity(){return TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE+TOOL_CHILD_LIMITS.HOST_CALL_WAITING}var HostCallAdmission=class{#active=new Set;#waiting=[];get active(){return this.#active.size}get waiting(){return this.#waiting.length}submit(callId){return this.#active.has(callId)||this.#waiting.includes(callId)?refuse(callId,"host_call_duplicate"):this.#active.size<TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE&&this.#waiting.length===0?(this.#active.add(callId),{state:"active"}):this.#active.size+this.#waiting.length>=hostCallCapacity()?refuse(callId,"host_call_capacity"):(this.#waiting.push(callId),{state:"waiting"})}settle(callId){if(!this.#active.delete(callId)){let index=this.#waiting.indexOf(callId);index>=0&&this.#waiting.splice(index,1);return}let next=this.#waiting.shift();return next!==void 0&&this.#active.add(next),next}};function refuse(callId,code){return{state:"refused",frame:{type:"host_call_refused",callId,code}}}import{createHash,randomBytes}from"node:crypto";import{createReadStream}from"node:fs";import{mkdir,readFile,rm as rm2,stat,writeFile}from"node:fs/promises";import{dirname}from"node:path";import{readdir,rm}from"node:fs/promises";import{join}from"node:path";function refGenerationDir(root,generation){return join(root,`gen-${generation}`)}function refFilePath(root,ref){if(!isRefId(ref.refId))throw new Error(`invalid ref id: ${JSON.stringify(ref.refId)}`);return join(refGenerationDir(root,ref.generation),"refs",ref.refId)}async function teardownRefGeneration(root,generation){await rm(refGenerationDir(root,generation),{recursive:!0,force:!0})}var PayloadRefError=class extends Error{constructor(code,message,reason){super(`${code}: ${message}`),this.name="PayloadRefError",this.code=code,this.reason=reason}},PayloadRefWriter=class{#root;#now;#pending=new Map;#ownedBytes=0;constructor(options){this.generation=options.generation,this.budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#root=options.root,this.#now=options.now??Date.now}get ownedBytes(){return this.#ownedBytes}async create(payload){let size=payload.byteLength;if(this.#ownedBytes+size>this.budget)throw new PayloadRefError("ref_budget_exceeded",`${size} bytes on top of ${this.#ownedBytes} owned exceeds ${this.budget}`);this.#ownedBytes+=size;let ref={refId:randomBytes(12).toString("hex"),generation:this.generation,bytes:size,sha256:createHash("sha256").update(payload).digest("hex")},path=refFilePath(this.#root,ref);try{await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,payload,{flag:"wx",mode:384})}catch(error){throw this.#ownedBytes-=size,await rm2(path,{force:!0}),error}return this.#pending.set(ref.refId,{bytes:size,createdAtMs:this.#now()}),ref}async handle(control){let pending=this.#pending.get(control.refId);pending!==void 0&&(this.#pending.delete(control.refId),this.#ownedBytes-=pending.bytes,control.type==="ref_nack"&&await rm2(refFilePath(this.#root,{refId:control.refId,generation:this.generation}),{force:!0}))}pendingIds(){return[...this.#pending.keys()]}overdue(){let deadline=this.#now()-TOOL_CHILD_LIMITS.refAckMs;return[...this.#pending].filter(([,ref])=>ref.createdAtMs<=deadline).map(([refId])=>refId)}async teardown(){this.#pending.clear(),this.#ownedBytes=0,await teardownRefGeneration(this.#root,this.generation)}},isMissingFile=error=>error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ENOTDIR");async function hashFile(path,signal){let hash=createHash("sha256");for await(let chunk of createReadStream(path)){if(signal?.aborted)return"cancelled";hash.update(chunk)}return hash.digest("hex")}var PayloadRefReader=class{#root;#generation;#budget;#send;#owned=new Map;#ownedBytes=0;constructor(options){this.#root=options.root,this.#generation=options.generation,this.#budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#send=options.send}async accept(ref,signal){let reason=await this.#verify(ref,signal);return reason!==void 0?(this.refuse(ref,reason),{ok:!1,reason}):(this.#owned.set(ref.refId,ref),this.#ownedBytes+=ref.bytes,this.#send({type:"ref_ack",refId:ref.refId}),{ok:!0})}refuse(ref,reason){this.#owned.has(ref.refId)||this.#send({type:"ref_nack",refId:ref.refId,reason})}async consume(refId){let ref=this.#owned.get(refId);if(ref===void 0)throw new PayloadRefError("ref_not_owned",`ref ${refId} is not owned by this side`);let path=refFilePath(this.#root,ref),bytes=await readFile(path);return await rm2(path,{force:!0}),this.#owned.delete(refId),this.#ownedBytes-=ref.bytes,bytes}ownedIds(){return[...this.#owned.keys()]}async#verify(ref,signal){if(signal?.aborted)return"cancelled";if(ref.generation!==this.#generation||!isRefId(ref.refId)||this.#owned.has(ref.refId))return"foreign";if(this.#ownedBytes+ref.bytes>this.#budget)return"budget";let path=refFilePath(this.#root,ref);try{if((await stat(path)).size!==ref.bytes)return"corrupt";let digest=await hashFile(path,signal);return digest==="cancelled"?"cancelled":digest===ref.sha256?void 0:"corrupt"}catch(error){if(isMissingFile(error))return"missing";throw error}}};async function packPayload(value,writer){let normalized=value===void 0?null:value,json=JSON.stringify(normalized);return json===void 0||Buffer.byteLength(json,"utf8")<=TOOL_CHILD_LIMITS.REF_THRESHOLD?{inline:!0,value:normalized}:{inline:!1,ref:await writer.create(Buffer.from(json,"utf8"))}}async function unpackPayload(ref,reader,signal){let acceptance=await reader.accept(ref,signal);if(!acceptance.ok)throw new PayloadRefError("ref_rejected",`ref ${ref.refId} was refused (${acceptance.reason})`,acceptance.reason);let bytes=await reader.consume(ref.refId);return JSON.parse(Buffer.from(bytes.buffer,bytes.byteOffset,bytes.byteLength).toString("utf8"))}var ChildHostCalls=class{#channel;#admissions=new Map;#pending=new Map;#refs;#next=0;constructor(channel,refs){this.#channel=channel,this.#refs=refs}load(jobId){let admission=this.#admissions.get(jobId);return{active:admission?.active??0,waiting:admission?.waiting??0}}async call(jobId,target,signal){let label=target.name??target.kind;if(signal.aborted)throw new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);let callId=`h${++this.#next}`,packed=target.args===void 0||this.#refs===void 0?{inline:!0,value:target.args}:await packPayload(target.args,this.#refs.writer),frame={type:"host_call",callId,jobId,kind:target.kind,...target.name===void 0?{}:{name:target.name},...packed.inline?packed.value===void 0?{}:{args:packed.value}:{argsRef:packed.ref}};if(signal.aborted)throw this.#releaseUnsent(frame),new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);return new Promise((resolve,reject)=>{let decision=this.#admission(jobId).submit(callId);if(decision.state==="refused"){this.#forgetIdle(jobId),this.#releaseUnsent(frame),reject(new ToolChildJobError(decision.frame.code,`${label}: host call ${callId} refused`));return}let pending={frame,resolve,reject,sent:!1};this.#pending.set(callId,pending),signal.addEventListener("abort",()=>this.#settle(callId,call=>{call.sent||this.#releaseUnsent(call.frame),call.reject(new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`))}),{once:!0}),decision.state==="active"&&this.#send(pending)})}handle(frame){if(frame.type==="host_reply"){let{valueRef}=frame;return this.#settle(frame.callId,call=>{frame.error!==void 0?call.reject(new ToolChildJobError("host_call_failed",frame.error)):valueRef===void 0?call.resolve(frame.value??null):this.#refs===void 0?call.reject(new ToolChildJobError("host_call_failed","a valueRef reply on a side that reads no refs")):unpackPayload(valueRef,this.#refs.reader).then(call.resolve,error=>call.reject(new ToolChildJobError("host_call_failed",error instanceof Error?error.message:String(error))))}),!0}return frame.type==="host_call_refused"?(this.#settle(frame.callId,call=>call.reject(new ToolChildJobError(frame.code,`host call ${frame.callId} refused by the server`))),!0):!1}close(){for(let callId of[...this.#pending.keys()])this.#settle(callId,call=>call.reject(new ToolChildJobError("tool_child_exited","the channel closed")))}#admission(jobId){let admission=this.#admissions.get(jobId);return admission===void 0&&(admission=new HostCallAdmission,this.#admissions.set(jobId,admission)),admission}#forgetIdle(jobId){let admission=this.#admissions.get(jobId);admission!==void 0&&admission.active===0&&admission.waiting===0&&this.#admissions.delete(jobId)}#send(call){call.sent=!0,this.#channel.send(call.frame)}#releaseUnsent(frame){frame.argsRef!==void 0&&this.#refs?.writer.handle({type:"ref_nack",refId:frame.argsRef.refId,reason:"cancelled"})}#settle(callId,apply){let call=this.#pending.get(callId);if(call===void 0)return;this.#pending.delete(callId);let{jobId}=call.frame,promoted=this.#admissions.get(jobId)?.settle(callId);if(this.#forgetIdle(jobId),apply(call),promoted!==void 0){let next=this.#pending.get(promoted);next!==void 0&&this.#send(next)}}};var JobUpdates=class{#jobId;#channel;#writer;#window;#nextSeq=0;#acked=0;#waiters=[];#ended=!1;#tail=Promise.resolve();constructor(options){this.#jobId=options.jobId,this.#channel=options.channel,this.#writer=options.writer,this.#window=options.window??TOOL_CHILD_LIMITS.updatesInFlight}update(value){let sent=this.#tail.then(()=>this.#send(value));return this.#tail=sent.catch(()=>{}),sent}async#send(value){for(;!this.#ended&&this.#nextSeq-this.#acked>=this.#window;)await new Promise(resolve=>this.#waiters.push(resolve));if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let packed=this.#writer===void 0?{inline:!0,value}:await packPayload(value,this.#writer);if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let seq=++this.#nextSeq;this.#channel.send(packed.inline?{type:"update",jobId:this.#jobId,seq,...packed.value===void 0?{}:{value:packed.value}}:{type:"update",jobId:this.#jobId,seq,valueRef:packed.ref})}acked(seq){seq<=this.#acked||(this.#acked=Math.min(seq,this.#nextSeq),this.#wake())}end(){this.#ended=!0,this.#wake()}#wake(){for(let resolve of this.#waiters.splice(0))resolve()}};var BarrierClock=class _BarrierClock{constructor(buffer){if(buffer.byteLength%Int32Array.BYTES_PER_ELEMENT!==0)throw new Error("barrier clock buffer is misaligned");let length=buffer.byteLength/Int32Array.BYTES_PER_ELEMENT;if(length<5||(length-1)%4!==0)throw new Error("barrier clock buffer has no slots");this.buffer=buffer,this.cells=new Int32Array(buffer),this.slots=(length-1)/4}static create(slots=256){if(!Number.isInteger(slots)||slots<1)throw new Error(`barrier clock needs at least one slot, got ${slots}`);return new _BarrierClock(new SharedArrayBuffer((1+slots*4)*Int32Array.BYTES_PER_ELEMENT))}tick(){return Atomics.add(this.cells,0,1)+1}claimSlot(){for(let slot=0;slot<this.slots;slot++)if(Atomics.compareExchange(this.cells,this.index(slot,3),0,1)===0)return Atomics.store(this.cells,this.index(slot,0),0),Atomics.store(this.cells,this.index(slot,1),0),Atomics.store(this.cells,this.index(slot,2),0),slot}releaseSlot(slot){Atomics.store(this.cells,this.index(slot,3),0)}recordAck(slot){let tick=this.tick();return Atomics.store(this.cells,this.index(slot,0),tick),Atomics.notify(this.cells,this.index(slot,0)),tick}recordInvoke(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=this.tick();return Atomics.store(this.cells,this.index(slot,1),invokeTick),Atomics.add(this.cells,this.index(slot,2),1),{ackTick:ackTick===0?null:ackTick,invokeTick}}waitForAck(slot,timeoutMs=Number.POSITIVE_INFINITY){let at=this.index(slot,0);for(;Atomics.load(this.cells,at)===0;)if(Atomics.wait(this.cells,at,0,timeoutMs)==="timed-out")return"timed-out";return"acked"}read(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=Atomics.load(this.cells,this.index(slot,1));return{ackTick:ackTick===0?null:ackTick,invokeTick:invokeTick===0?null:invokeTick,invocations:Atomics.load(this.cells,this.index(slot,2))}}index(slot,field){if(!Number.isInteger(slot)||slot<0||slot>=this.slots)throw new Error(`no barrier slot ${slot}`);return 1+slot*4+field}};function proofIsOrdered(proof){return proof.ackTick!==null&&proof.ackTick<proof.invokeTick}import{randomUUID}from"node:crypto";import{existsSync,readdirSync,rmSync,watch}from"node:fs";import{writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var PREFIX="SENPI_TOOL_CHILD_TEST_",TEST_CONTROL_DIR_ENV=`${PREFIX}CONTROL_DIR`;function readTestControls(env){let dir=env[TEST_CONTROL_DIR_ENV],value=name=>{let raw=env[`${PREFIX}${name}`];return raw===void 0||raw===""||raw==="0"?void 0:raw};return{enabled:name=>value(name)!==void 0,value,released:file=>dir===void 0?Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)):waitForFile(dir,file),watchPrefix:(prefix,onFile)=>dir===void 0?{ready:Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)),close:()=>{}}:watchPrefix(dir,prefix,onFile)}}function watchPrefix(dir,prefix,onFile){let seen=new Set,report=name=>{!name.startsWith(prefix)||seen.has(name)||(seen.add(name),onFile(name))},sentinel=`.watch-${process.pid}-${randomUUID()}`,resend,live=!1,markReady=()=>{},failReady=()=>{},ready=new Promise((resolve,reject)=>{markReady=resolve,failReady=reject}),watcher=watch(dir,(_event,name)=>{if(name!==null){if(name===sentinel){live=!0,clearTimeout(resend),rmSync(join2(dir,sentinel),{force:!0});for(let existing of readdirSync(dir))report(existing);markReady();return}existsSync(join2(dir,name))&&report(name)}}),touch=()=>{live||writeFile2(join2(dir,sentinel),String(Date.now())).then(()=>{live||(resend=setTimeout(touch,50))},error=>failReady(error))};return touch(),{ready,close:()=>{live=!0,clearTimeout(resend),watcher.close(),rmSync(join2(dir,sentinel),{force:!0})}}}function waitForFile(dir,file){let path=join2(dir,file),sentinel=join2(dir,`.watch-${process.pid}-${randomUUID()}`);return new Promise((resolve,reject)=>{let done=!1,resend,finish=()=>{done||(done=!0,clearTimeout(resend),watcher.close(),rmSync(sentinel,{force:!0}),resolve())},watcher=watch(dir,(_event,name)=>{if(existsSync(path)){finish();return}name!==null&&join2(dir,name)===sentinel&&clearTimeout(resend)}),touch=()=>{done||writeFile2(sentinel,String(Date.now())).then(()=>{done||(existsSync(path)?finish():resend=setTimeout(touch,50))},error=>{done||(done=!0,watcher.close(),reject(error))})};touch()})}var WindowsJobError=class extends Error{constructor(step,win32Error){super(`tool_child_job_assign_failed: ${step} failed (win32 error ${win32Error})`),this.code="tool_child_job_assign_failed",this.name="WindowsJobError",this.win32Error=win32Error}};function extendedLimitInformation(){let info=new Uint8Array(144);return new DataView(info.buffer).setUint32(16,10240,!0),info}var WindowsJob=class _WindowsJob{constructor(kernel,handle){this.closed=!1,this.kernel=kernel,this.handle=handle}static create(kernel){let handle=kernel.CreateJobObjectW(null,null);if(!handle)throw new WindowsJobError("CreateJobObjectW",kernel.GetLastError());let info=extendedLimitInformation();if(kernel.SetInformationJobObject(handle,9,info,info.byteLength)===0){let error=kernel.GetLastError();throw kernel.CloseHandle(handle),new WindowsJobError("SetInformationJobObject",error)}return new _WindowsJob(kernel,handle)}assign(pid){let process2=this.kernel.OpenProcess(4353,0,pid);if(!process2)throw new WindowsJobError("OpenProcess",this.kernel.GetLastError());try{if(this.kernel.AssignProcessToJobObject(this.handle,process2)===0)throw new WindowsJobError("AssignProcessToJobObject",this.kernel.GetLastError());let inJob=new Uint8Array(4);if(this.kernel.IsProcessInJob(process2,this.handle,inJob)===0||new DataView(inJob.buffer).getInt32(0,!0)===0)throw new WindowsJobError("IsProcessInJob",this.kernel.GetLastError())}finally{this.kernel.CloseHandle(process2)}}memberPids(){let list=new Uint8Array(8200);if(this.kernel.QueryInformationJobObject(this.handle,3,list,list.byteLength,null)===0)return[];let view=new DataView(list.buffer),count=Math.min(view.getUint32(4,!0),1024);return Array.from({length:count},(_,index)=>Number(view.getBigUint64(8+index*8,!0)))}terminate(exitCode=1){this.closed||this.kernel.TerminateJobObject(this.handle,exitCode)}close(){this.closed||(this.closed=!0,this.kernel.CloseHandle(this.handle))}};function loadKernel32Job(){if(process.platform!=="win32")return;let ffi=process.getBuiltinModule("bun:ffi");if(ffi===void 0)return;let lib=ffi.dlopen("kernel32.dll",{CreateJobObjectW:{args:["ptr","ptr"],returns:"ptr"},SetInformationJobObject:{args:["ptr","i32","ptr","u32"],returns:"i32"},QueryInformationJobObject:{args:["ptr","i32","ptr","u32","ptr"],returns:"i32"},OpenProcess:{args:["u32","i32","u32"],returns:"ptr"},AssignProcessToJobObject:{args:["ptr","ptr"],returns:"i32"},IsProcessInJob:{args:["ptr","ptr","ptr"],returns:"i32"},TerminateJobObject:{args:["ptr","u32"],returns:"i32"},CloseHandle:{args:["ptr"],returns:"i32"},GetLastError:{args:[],returns:"u32"},GetCurrentProcess:{args:[],returns:"ptr"}}),call=(name,...args)=>{let fn=lib.symbols[name];if(fn===void 0)throw new Error(`kernel32 has no ${name}`);return fn(...args.map(arg=>arg instanceof Uint8Array?ffi.ptr(arg):arg))};return{CreateJobObjectW:()=>call("CreateJobObjectW",null,null),SetInformationJobObject:(job,infoClass,info,length)=>Number(call("SetInformationJobObject",job,infoClass,info,length)),QueryInformationJobObject:(job,infoClass,info,length)=>Number(call("QueryInformationJobObject",job,infoClass,info,length,null)),OpenProcess:(access,inherit,pid)=>call("OpenProcess",access,inherit,pid),AssignProcessToJobObject:(job,process2)=>Number(call("AssignProcessToJobObject",job,process2)),IsProcessInJob:(process2,job,result)=>Number(call("IsProcessInJob",process2,job,result)),TerminateJobObject:(job,exitCode)=>Number(call("TerminateJobObject",job,exitCode)),CloseHandle:handle=>Number(call("CloseHandle",handle)),GetLastError:()=>Number(call("GetLastError")),GetCurrentProcess:()=>call("GetCurrentProcess")}}var defaultInJob;function currentProcessInJob(kernel){if(kernel!==void 0)return queryInJob(kernel);if(defaultInJob===void 0){let loaded=loadKernel32Job();defaultInJob=loaded===void 0?!1:queryInJob(loaded)}return defaultInJob}function queryInJob(kernel){let result=new Uint8Array(4);return kernel.IsProcessInJob(kernel.GetCurrentProcess(),null,result)!==0&&new DataView(result.buffer).getInt32(0,!0)!==0}var FINISHED_SLOT_STATES=256,LaunchGateError=class extends Error{constructor(code,message){super(`${code}: ${message}`),this.name="LaunchGateError",this.code=code}},LaunchGate=class{#channel;#slots=new Map;#finished=new Map;#controls;#next=0;constructor(channel,clock=BarrierClock.create(),env=process.env,creatorInJob=currentProcessInJob){this.#channel=channel,this.clock=clock,this.#controls=readTestControls(env),this.#creatorInJob=creatorInJob}#creatorInJob;started(launchId,pid,breakaway=!1){this.#slots.has(launchId)&&this.#channel.send({type:"command_started",launchId,pid,startedAtMs:Date.now(),creatorInJob:this.#creatorInJob(),breakaway})}get skipsAckWait(){return this.#controls.enabled("SKIP_ACK_WAIT")}request(request){let slot=this.clock.claimSlot();if(slot===void 0)throw new LaunchGateError("tool_child_launch_capacity",`${this.clock.slots} launches in flight`);let launchId=`L${process.pid}-${++this.#next}`,ack,acked=new Promise(resolve=>{ack=resolve});return this.#slots.set(launchId,{slot,ack,lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request}),this.#controls.enabled("STOP_AFTER_SPAWN")&&process.kill(process.pid,"SIGSTOP"),{launchId,slot,acked}}adopt(launchId,slot,request){this.#slots.set(launchId,{slot,ack:()=>{},lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request})}handleWorker(message){message.kind==="launch"?this.adopt(message.launchId,message.slot,message.request):message.kind==="invoking"?this.invoking(message.launchId):message.kind==="started"?this.started(message.launchId,message.pid,message.breakaway):this.done(message.launchId,{...message.exitCode===void 0?{}:{exitCode:message.exitCode},...message.signal===void 0?{}:{signal:message.signal}})}handle(message){if(message.type==="launch_ack"){let entry=this.#slots.get(message.launchId);return entry!==void 0&&(this.clock.recordAck(entry.slot),entry.ack()),!0}if(message.type==="slot_query"){let entry=this.#slots.get(message.launchId),state=entry===void 0?this.#finished.get(message.launchId)??{ackTick:null,invokeTick:null,invocations:0}:this.clock.read(entry.slot);return this.#channel.send({type:"slot_state",launchId:message.launchId,...state}),!0}return!1}invokeNow(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)throw new LaunchGateError("tool_child_launch_unknown",launchId);this.clock.recordInvoke(entry.slot),this.invoking(launchId)}invoking(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)return;let state=this.clock.read(entry.slot),invokeTick=state.invokeTick;if(invokeTick===null)return;let send=()=>this.#channel.send({type:"launch_proof",launchId,ackTick:state.ackTick,invokeTick}),hold=this.#controls.value("HOLD_LAUNCH_PROOF");if(hold!==void 0&&(hold!=="detached"||entry.lifetime==="detached")){this.#controls.released(`release-proof-${launchId}`).then(send);return}send()}endJobGroups(jobId){let ended=[];for(let[launchId,{request}]of this.#slots)if(!(request.jobId!==jobId||request.lifetime!=="owned"||request.containment!=="own-group")&&!(request.pgid===void 0||request.pgid<=1))try{process.kill(-request.pgid,"SIGKILL"),ended.push({launchId,pgid:request.pgid})}catch{}for(let{launchId}of ended)this.done(launchId,{signal:"SIGKILL"});return ended.map(({pgid})=>pgid)}done(launchId,outcome){let entry=this.#slots.get(launchId);entry!==void 0&&(this.#slots.delete(launchId),this.#finished.set(launchId,this.clock.read(entry.slot)),this.#finished.size>FINISHED_SLOT_STATES&&this.#finished.delete(this.#finished.keys().next().value??""),this.clock.releaseSlot(entry.slot),this.#channel.send({type:"launch_done",launchId,...outcome.exitCode===void 0?{}:{exitCode:outcome.exitCode},...outcome.signal===void 0?{}:{signal:outcome.signal}}))}};import{mkdir as mkdir3,readdir as readdir2,readFile as readFile3,rm as rm4,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname3,join as join4}from"node:path";import{appendFile,mkdir as mkdir2,open,readFile as readFile2,rm as rm3}from"node:fs/promises";import{dirname as dirname2,join as join3}from"node:path";function generationLedgerPath(dir,generation){return join3(dir,`g${generation}`,"descendants.ledger")}var DescendantsLedger=class{#path;#durableDir=!1;#entries=new Map;constructor(path){this.#path=path}get path(){return this.#path}entries(){return[...this.#entries.values()]}async append(entry){if(!this.#durableDir){let directory=dirname2(this.#path);await mkdir2(directory,{recursive:!0,mode:448}),await(await open(this.#path,"a",384)).close(),await syncDirectory(directory),await syncDirectory(dirname2(directory)),this.#durableDir=!0}let handle=await open(this.#path,"a",384);try{await handle.write(`${JSON.stringify(entry)}
|
|
2
|
+
import{Text}from"./chunk-FDL4CF6F.js";import{getShellConfig}from"./chunk-BWA4FVFW.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId}from"./chunk-V3CK2AVC.js";import{typebox_exports}from"./chunk-MIENF2YK.js";import{TOOL_CHILD_LEDGER_ENV,TOOL_CHILD_REENTRY_ENV,TOOL_CHILD_REFS_ROOT_ENV,rememberToolChildReentry,scrubToolChildEnv,toolChildReentry}from"./chunk-OXNWERO4.js";import{BACKGROUND_START_GRACE_MS,DEFAULT_COLS,DEFAULT_MAX_SESSIONS,DEFAULT_ROWS,FOREGROUND_ENV_OVERRIDES,KILLED_SESSION_EXIT_GRACE_MS,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,encodeKeys,loadPty,safeRegExp}from"./chunk-NTK2MHJ5.js";import{processIsRunning,processStartTimeMs,readProcessStartTime,sameProcessStartMs}from"./chunk-O5RYI3IW.js";var ToolChildJobError=class extends Error{constructor(code,message){super(message),this.code=code,this.name="ToolChildJobError"}};var WakeAdmissionError=class extends Error{constructor(bytes){super(`wake_too_large: ${bytes} bytes exceeds the ${TOOL_CHILD_LIMITS.wakePendingBytes}-byte pending budget`),this.code="wake_too_large",this.name="WakeAdmissionError"}},WakeAdmission=class{#pending=new Map;#blocked=[];#pendingBytes=0;get pending(){return this.#pending.size}get blocked(){return this.#blocked.length}send(wakeId,bytes){return bytes>TOOL_CHILD_LIMITS.wakePendingBytes?Promise.reject(new WakeAdmissionError(bytes)):this.#blocked.length===0&&this.#fits(bytes)?(this.#admit(wakeId,bytes),Promise.resolve()):new Promise(release=>{this.#blocked.push({wakeId,bytes,release})})}ack(wakeId){let bytes=this.#pending.get(wakeId);if(bytes!==void 0){this.#pending.delete(wakeId),this.#pendingBytes-=bytes;for(let next=this.#blocked[0];next!==void 0&&this.#fits(next.bytes);next=this.#blocked[0])this.#blocked.shift(),this.#admit(next.wakeId,next.bytes),next.release()}}#fits(bytes){return this.#pending.size<TOOL_CHILD_LIMITS.wakePending&&this.#pendingBytes+bytes<=TOOL_CHILD_LIMITS.wakePendingBytes}#admit(wakeId,bytes){this.#pending.set(wakeId,bytes),this.#pendingBytes+=bytes}};function hostCallCapacity(){return TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE+TOOL_CHILD_LIMITS.HOST_CALL_WAITING}var HostCallAdmission=class{#active=new Set;#waiting=[];get active(){return this.#active.size}get waiting(){return this.#waiting.length}submit(callId){return this.#active.has(callId)||this.#waiting.includes(callId)?refuse(callId,"host_call_duplicate"):this.#active.size<TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE&&this.#waiting.length===0?(this.#active.add(callId),{state:"active"}):this.#active.size+this.#waiting.length>=hostCallCapacity()?refuse(callId,"host_call_capacity"):(this.#waiting.push(callId),{state:"waiting"})}settle(callId){if(!this.#active.delete(callId)){let index=this.#waiting.indexOf(callId);index>=0&&this.#waiting.splice(index,1);return}let next=this.#waiting.shift();return next!==void 0&&this.#active.add(next),next}};function refuse(callId,code){return{state:"refused",frame:{type:"host_call_refused",callId,code}}}import{createHash,randomBytes}from"node:crypto";import{createReadStream}from"node:fs";import{mkdir,readFile,rm as rm2,stat,writeFile}from"node:fs/promises";import{dirname}from"node:path";import{readdir,rm}from"node:fs/promises";import{join}from"node:path";function refGenerationDir(root,generation){return join(root,`gen-${generation}`)}function refFilePath(root,ref){if(!isRefId(ref.refId))throw new Error(`invalid ref id: ${JSON.stringify(ref.refId)}`);return join(refGenerationDir(root,ref.generation),"refs",ref.refId)}async function teardownRefGeneration(root,generation){await rm(refGenerationDir(root,generation),{recursive:!0,force:!0})}var PayloadRefError=class extends Error{constructor(code,message,reason){super(`${code}: ${message}`),this.name="PayloadRefError",this.code=code,this.reason=reason}},PayloadRefWriter=class{#root;#now;#pending=new Map;#ownedBytes=0;constructor(options){this.generation=options.generation,this.budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#root=options.root,this.#now=options.now??Date.now}get ownedBytes(){return this.#ownedBytes}async create(payload){let size=payload.byteLength;if(this.#ownedBytes+size>this.budget)throw new PayloadRefError("ref_budget_exceeded",`${size} bytes on top of ${this.#ownedBytes} owned exceeds ${this.budget}`);this.#ownedBytes+=size;let ref={refId:randomBytes(12).toString("hex"),generation:this.generation,bytes:size,sha256:createHash("sha256").update(payload).digest("hex")},path=refFilePath(this.#root,ref);try{await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,payload,{flag:"wx",mode:384})}catch(error){throw this.#ownedBytes-=size,await rm2(path,{force:!0}),error}return this.#pending.set(ref.refId,{bytes:size,createdAtMs:this.#now()}),ref}async handle(control){let pending=this.#pending.get(control.refId);pending!==void 0&&(this.#pending.delete(control.refId),this.#ownedBytes-=pending.bytes,control.type==="ref_nack"&&await rm2(refFilePath(this.#root,{refId:control.refId,generation:this.generation}),{force:!0}))}pendingIds(){return[...this.#pending.keys()]}overdue(){let deadline=this.#now()-TOOL_CHILD_LIMITS.refAckMs;return[...this.#pending].filter(([,ref])=>ref.createdAtMs<=deadline).map(([refId])=>refId)}async teardown(){this.#pending.clear(),this.#ownedBytes=0,await teardownRefGeneration(this.#root,this.generation)}},isMissingFile=error=>error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ENOTDIR");async function hashFile(path,signal){let hash=createHash("sha256");for await(let chunk of createReadStream(path)){if(signal?.aborted)return"cancelled";hash.update(chunk)}return hash.digest("hex")}var PayloadRefReader=class{#root;#generation;#budget;#send;#owned=new Map;#ownedBytes=0;constructor(options){this.#root=options.root,this.#generation=options.generation,this.#budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#send=options.send}async accept(ref,signal){let reason=await this.#verify(ref,signal);return reason!==void 0?(this.refuse(ref,reason),{ok:!1,reason}):(this.#owned.set(ref.refId,ref),this.#ownedBytes+=ref.bytes,this.#send({type:"ref_ack",refId:ref.refId}),{ok:!0})}refuse(ref,reason){this.#owned.has(ref.refId)||this.#send({type:"ref_nack",refId:ref.refId,reason})}async consume(refId){let ref=this.#owned.get(refId);if(ref===void 0)throw new PayloadRefError("ref_not_owned",`ref ${refId} is not owned by this side`);let path=refFilePath(this.#root,ref),bytes=await readFile(path);return await rm2(path,{force:!0}),this.#owned.delete(refId),this.#ownedBytes-=ref.bytes,bytes}ownedIds(){return[...this.#owned.keys()]}async#verify(ref,signal){if(signal?.aborted)return"cancelled";if(ref.generation!==this.#generation||!isRefId(ref.refId)||this.#owned.has(ref.refId))return"foreign";if(this.#ownedBytes+ref.bytes>this.#budget)return"budget";let path=refFilePath(this.#root,ref);try{if((await stat(path)).size!==ref.bytes)return"corrupt";let digest=await hashFile(path,signal);return digest==="cancelled"?"cancelled":digest===ref.sha256?void 0:"corrupt"}catch(error){if(isMissingFile(error))return"missing";throw error}}};async function packPayload(value,writer){let normalized=value===void 0?null:value,json=JSON.stringify(normalized);return json===void 0||Buffer.byteLength(json,"utf8")<=TOOL_CHILD_LIMITS.REF_THRESHOLD?{inline:!0,value:normalized}:{inline:!1,ref:await writer.create(Buffer.from(json,"utf8"))}}async function unpackPayload(ref,reader,signal){let acceptance=await reader.accept(ref,signal);if(!acceptance.ok)throw new PayloadRefError("ref_rejected",`ref ${ref.refId} was refused (${acceptance.reason})`,acceptance.reason);let bytes=await reader.consume(ref.refId);return JSON.parse(Buffer.from(bytes.buffer,bytes.byteOffset,bytes.byteLength).toString("utf8"))}var ChildHostCalls=class{#channel;#admissions=new Map;#pending=new Map;#refs;#next=0;constructor(channel,refs){this.#channel=channel,this.#refs=refs}load(jobId){let admission=this.#admissions.get(jobId);return{active:admission?.active??0,waiting:admission?.waiting??0}}async call(jobId,target,signal){let label=target.name??target.kind;if(signal.aborted)throw new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);let callId=`h${++this.#next}`,packed=target.args===void 0||this.#refs===void 0?{inline:!0,value:target.args}:await packPayload(target.args,this.#refs.writer),frame={type:"host_call",callId,jobId,kind:target.kind,...target.name===void 0?{}:{name:target.name},...packed.inline?packed.value===void 0?{}:{args:packed.value}:{argsRef:packed.ref}};if(signal.aborted)throw this.#releaseUnsent(frame),new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);return new Promise((resolve,reject)=>{let decision=this.#admission(jobId).submit(callId);if(decision.state==="refused"){this.#forgetIdle(jobId),this.#releaseUnsent(frame),reject(new ToolChildJobError(decision.frame.code,`${label}: host call ${callId} refused`));return}let pending={frame,resolve,reject,sent:!1};this.#pending.set(callId,pending),signal.addEventListener("abort",()=>this.#settle(callId,call=>{call.sent||this.#releaseUnsent(call.frame),call.reject(new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`))}),{once:!0}),decision.state==="active"&&this.#send(pending)})}handle(frame){if(frame.type==="host_reply"){let{valueRef}=frame;return this.#settle(frame.callId,call=>{frame.error!==void 0?call.reject(new ToolChildJobError("host_call_failed",frame.error)):valueRef===void 0?call.resolve(frame.value??null):this.#refs===void 0?call.reject(new ToolChildJobError("host_call_failed","a valueRef reply on a side that reads no refs")):unpackPayload(valueRef,this.#refs.reader).then(call.resolve,error=>call.reject(new ToolChildJobError("host_call_failed",error instanceof Error?error.message:String(error))))}),!0}return frame.type==="host_call_refused"?(this.#settle(frame.callId,call=>call.reject(new ToolChildJobError(frame.code,`host call ${frame.callId} refused by the server`))),!0):!1}close(){for(let callId of[...this.#pending.keys()])this.#settle(callId,call=>call.reject(new ToolChildJobError("tool_child_exited","the channel closed")))}#admission(jobId){let admission=this.#admissions.get(jobId);return admission===void 0&&(admission=new HostCallAdmission,this.#admissions.set(jobId,admission)),admission}#forgetIdle(jobId){let admission=this.#admissions.get(jobId);admission!==void 0&&admission.active===0&&admission.waiting===0&&this.#admissions.delete(jobId)}#send(call){call.sent=!0,this.#channel.send(call.frame)}#releaseUnsent(frame){frame.argsRef!==void 0&&this.#refs?.writer.handle({type:"ref_nack",refId:frame.argsRef.refId,reason:"cancelled"})}#settle(callId,apply){let call=this.#pending.get(callId);if(call===void 0)return;this.#pending.delete(callId);let{jobId}=call.frame,promoted=this.#admissions.get(jobId)?.settle(callId);if(this.#forgetIdle(jobId),apply(call),promoted!==void 0){let next=this.#pending.get(promoted);next!==void 0&&this.#send(next)}}};var JobUpdates=class{#jobId;#channel;#writer;#window;#nextSeq=0;#acked=0;#waiters=[];#ended=!1;#tail=Promise.resolve();constructor(options){this.#jobId=options.jobId,this.#channel=options.channel,this.#writer=options.writer,this.#window=options.window??TOOL_CHILD_LIMITS.updatesInFlight}update(value){let sent=this.#tail.then(()=>this.#send(value));return this.#tail=sent.catch(()=>{}),sent}async#send(value){for(;!this.#ended&&this.#nextSeq-this.#acked>=this.#window;)await new Promise(resolve=>this.#waiters.push(resolve));if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let packed=this.#writer===void 0?{inline:!0,value}:await packPayload(value,this.#writer);if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let seq=++this.#nextSeq;this.#channel.send(packed.inline?{type:"update",jobId:this.#jobId,seq,...packed.value===void 0?{}:{value:packed.value}}:{type:"update",jobId:this.#jobId,seq,valueRef:packed.ref})}acked(seq){seq<=this.#acked||(this.#acked=Math.min(seq,this.#nextSeq),this.#wake())}end(){this.#ended=!0,this.#wake()}#wake(){for(let resolve of this.#waiters.splice(0))resolve()}};var BarrierClock=class _BarrierClock{constructor(buffer){if(buffer.byteLength%Int32Array.BYTES_PER_ELEMENT!==0)throw new Error("barrier clock buffer is misaligned");let length=buffer.byteLength/Int32Array.BYTES_PER_ELEMENT;if(length<5||(length-1)%4!==0)throw new Error("barrier clock buffer has no slots");this.buffer=buffer,this.cells=new Int32Array(buffer),this.slots=(length-1)/4}static create(slots=256){if(!Number.isInteger(slots)||slots<1)throw new Error(`barrier clock needs at least one slot, got ${slots}`);return new _BarrierClock(new SharedArrayBuffer((1+slots*4)*Int32Array.BYTES_PER_ELEMENT))}tick(){return Atomics.add(this.cells,0,1)+1}claimSlot(){for(let slot=0;slot<this.slots;slot++)if(Atomics.compareExchange(this.cells,this.index(slot,3),0,1)===0)return Atomics.store(this.cells,this.index(slot,0),0),Atomics.store(this.cells,this.index(slot,1),0),Atomics.store(this.cells,this.index(slot,2),0),slot}releaseSlot(slot){Atomics.store(this.cells,this.index(slot,3),0)}recordAck(slot){let tick=this.tick();return Atomics.store(this.cells,this.index(slot,0),tick),Atomics.notify(this.cells,this.index(slot,0)),tick}recordInvoke(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=this.tick();return Atomics.store(this.cells,this.index(slot,1),invokeTick),Atomics.add(this.cells,this.index(slot,2),1),{ackTick:ackTick===0?null:ackTick,invokeTick}}waitForAck(slot,timeoutMs=Number.POSITIVE_INFINITY){let at=this.index(slot,0);for(;Atomics.load(this.cells,at)===0;)if(Atomics.wait(this.cells,at,0,timeoutMs)==="timed-out")return"timed-out";return"acked"}read(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=Atomics.load(this.cells,this.index(slot,1));return{ackTick:ackTick===0?null:ackTick,invokeTick:invokeTick===0?null:invokeTick,invocations:Atomics.load(this.cells,this.index(slot,2))}}index(slot,field){if(!Number.isInteger(slot)||slot<0||slot>=this.slots)throw new Error(`no barrier slot ${slot}`);return 1+slot*4+field}};function proofIsOrdered(proof){return proof.ackTick!==null&&proof.ackTick<proof.invokeTick}import{randomUUID}from"node:crypto";import{existsSync,readdirSync,rmSync,watch}from"node:fs";import{writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var PREFIX="SENPI_TOOL_CHILD_TEST_",TEST_CONTROL_DIR_ENV=`${PREFIX}CONTROL_DIR`;function readTestControls(env){let dir=env[TEST_CONTROL_DIR_ENV],value=name=>{let raw=env[`${PREFIX}${name}`];return raw===void 0||raw===""||raw==="0"?void 0:raw};return{enabled:name=>value(name)!==void 0,value,released:file=>dir===void 0?Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)):waitForFile(dir,file),watchPrefix:(prefix,onFile)=>dir===void 0?{ready:Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)),close:()=>{}}:watchPrefix(dir,prefix,onFile)}}function watchPrefix(dir,prefix,onFile){let seen=new Set,report=name=>{!name.startsWith(prefix)||seen.has(name)||(seen.add(name),onFile(name))},sentinel=`.watch-${process.pid}-${randomUUID()}`,resend,live=!1,markReady=()=>{},failReady=()=>{},ready=new Promise((resolve,reject)=>{markReady=resolve,failReady=reject}),watcher=watch(dir,(_event,name)=>{if(name!==null){if(name===sentinel){live=!0,clearTimeout(resend),rmSync(join2(dir,sentinel),{force:!0});for(let existing of readdirSync(dir))report(existing);markReady();return}existsSync(join2(dir,name))&&report(name)}}),touch=()=>{live||writeFile2(join2(dir,sentinel),String(Date.now())).then(()=>{live||(resend=setTimeout(touch,50))},error=>failReady(error))};return touch(),{ready,close:()=>{live=!0,clearTimeout(resend),watcher.close(),rmSync(join2(dir,sentinel),{force:!0})}}}function waitForFile(dir,file){let path=join2(dir,file),sentinel=join2(dir,`.watch-${process.pid}-${randomUUID()}`);return new Promise((resolve,reject)=>{let done=!1,resend,finish=()=>{done||(done=!0,clearTimeout(resend),watcher.close(),rmSync(sentinel,{force:!0}),resolve())},watcher=watch(dir,(_event,name)=>{if(existsSync(path)){finish();return}name!==null&&join2(dir,name)===sentinel&&clearTimeout(resend)}),touch=()=>{done||writeFile2(sentinel,String(Date.now())).then(()=>{done||(existsSync(path)?finish():resend=setTimeout(touch,50))},error=>{done||(done=!0,watcher.close(),reject(error))})};touch()})}var WindowsJobError=class extends Error{constructor(step,win32Error){super(`tool_child_job_assign_failed: ${step} failed (win32 error ${win32Error})`),this.code="tool_child_job_assign_failed",this.name="WindowsJobError",this.win32Error=win32Error}};function extendedLimitInformation(){let info=new Uint8Array(144);return new DataView(info.buffer).setUint32(16,10240,!0),info}var WindowsJob=class _WindowsJob{constructor(kernel,handle){this.closed=!1,this.kernel=kernel,this.handle=handle}static create(kernel){let handle=kernel.CreateJobObjectW(null,null);if(!handle)throw new WindowsJobError("CreateJobObjectW",kernel.GetLastError());let info=extendedLimitInformation();if(kernel.SetInformationJobObject(handle,9,info,info.byteLength)===0){let error=kernel.GetLastError();throw kernel.CloseHandle(handle),new WindowsJobError("SetInformationJobObject",error)}return new _WindowsJob(kernel,handle)}assign(pid){let process2=this.kernel.OpenProcess(4353,0,pid);if(!process2)throw new WindowsJobError("OpenProcess",this.kernel.GetLastError());try{if(this.kernel.AssignProcessToJobObject(this.handle,process2)===0)throw new WindowsJobError("AssignProcessToJobObject",this.kernel.GetLastError());let inJob=new Uint8Array(4);if(this.kernel.IsProcessInJob(process2,this.handle,inJob)===0||new DataView(inJob.buffer).getInt32(0,!0)===0)throw new WindowsJobError("IsProcessInJob",this.kernel.GetLastError())}finally{this.kernel.CloseHandle(process2)}}memberPids(){let list=new Uint8Array(8200);if(this.kernel.QueryInformationJobObject(this.handle,3,list,list.byteLength,null)===0)return[];let view=new DataView(list.buffer),count=Math.min(view.getUint32(4,!0),1024);return Array.from({length:count},(_,index)=>Number(view.getBigUint64(8+index*8,!0)))}terminate(exitCode=1){this.closed||this.kernel.TerminateJobObject(this.handle,exitCode)}close(){this.closed||(this.closed=!0,this.kernel.CloseHandle(this.handle))}};function loadKernel32Job(){if(process.platform!=="win32")return;let ffi=process.getBuiltinModule("bun:ffi");if(ffi===void 0)return;let lib=ffi.dlopen("kernel32.dll",{CreateJobObjectW:{args:["ptr","ptr"],returns:"ptr"},SetInformationJobObject:{args:["ptr","i32","ptr","u32"],returns:"i32"},QueryInformationJobObject:{args:["ptr","i32","ptr","u32","ptr"],returns:"i32"},OpenProcess:{args:["u32","i32","u32"],returns:"ptr"},AssignProcessToJobObject:{args:["ptr","ptr"],returns:"i32"},IsProcessInJob:{args:["ptr","ptr","ptr"],returns:"i32"},TerminateJobObject:{args:["ptr","u32"],returns:"i32"},CloseHandle:{args:["ptr"],returns:"i32"},GetLastError:{args:[],returns:"u32"},GetCurrentProcess:{args:[],returns:"ptr"}}),call=(name,...args)=>{let fn=lib.symbols[name];if(fn===void 0)throw new Error(`kernel32 has no ${name}`);return fn(...args.map(arg=>arg instanceof Uint8Array?ffi.ptr(arg):arg))};return{CreateJobObjectW:()=>call("CreateJobObjectW",null,null),SetInformationJobObject:(job,infoClass,info,length)=>Number(call("SetInformationJobObject",job,infoClass,info,length)),QueryInformationJobObject:(job,infoClass,info,length)=>Number(call("QueryInformationJobObject",job,infoClass,info,length,null)),OpenProcess:(access,inherit,pid)=>call("OpenProcess",access,inherit,pid),AssignProcessToJobObject:(job,process2)=>Number(call("AssignProcessToJobObject",job,process2)),IsProcessInJob:(process2,job,result)=>Number(call("IsProcessInJob",process2,job,result)),TerminateJobObject:(job,exitCode)=>Number(call("TerminateJobObject",job,exitCode)),CloseHandle:handle=>Number(call("CloseHandle",handle)),GetLastError:()=>Number(call("GetLastError")),GetCurrentProcess:()=>call("GetCurrentProcess")}}var defaultInJob;function currentProcessInJob(kernel){if(kernel!==void 0)return queryInJob(kernel);if(defaultInJob===void 0){let loaded=loadKernel32Job();defaultInJob=loaded===void 0?!1:queryInJob(loaded)}return defaultInJob}function queryInJob(kernel){let result=new Uint8Array(4);return kernel.IsProcessInJob(kernel.GetCurrentProcess(),null,result)!==0&&new DataView(result.buffer).getInt32(0,!0)!==0}var FINISHED_SLOT_STATES=256,LaunchGateError=class extends Error{constructor(code,message){super(`${code}: ${message}`),this.name="LaunchGateError",this.code=code}},LaunchGate=class{#channel;#slots=new Map;#finished=new Map;#controls;#next=0;constructor(channel,clock=BarrierClock.create(),env=process.env,creatorInJob=currentProcessInJob){this.#channel=channel,this.clock=clock,this.#controls=readTestControls(env),this.#creatorInJob=creatorInJob}#creatorInJob;started(launchId,pid,breakaway=!1){this.#slots.has(launchId)&&this.#channel.send({type:"command_started",launchId,pid,startedAtMs:Date.now(),creatorInJob:this.#creatorInJob(),breakaway})}get skipsAckWait(){return this.#controls.enabled("SKIP_ACK_WAIT")}request(request){let slot=this.clock.claimSlot();if(slot===void 0)throw new LaunchGateError("tool_child_launch_capacity",`${this.clock.slots} launches in flight`);let launchId=`L${process.pid}-${++this.#next}`,ack,acked=new Promise(resolve=>{ack=resolve});return this.#slots.set(launchId,{slot,ack,lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request}),this.#controls.enabled("STOP_AFTER_SPAWN")&&process.kill(process.pid,"SIGSTOP"),{launchId,slot,acked}}adopt(launchId,slot,request){this.#slots.set(launchId,{slot,ack:()=>{},lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request})}handleWorker(message){message.kind==="launch"?this.adopt(message.launchId,message.slot,message.request):message.kind==="invoking"?this.invoking(message.launchId):message.kind==="started"?this.started(message.launchId,message.pid,message.breakaway):this.done(message.launchId,{...message.exitCode===void 0?{}:{exitCode:message.exitCode},...message.signal===void 0?{}:{signal:message.signal}})}handle(message){if(message.type==="launch_ack"){let entry=this.#slots.get(message.launchId);return entry!==void 0&&(this.clock.recordAck(entry.slot),entry.ack()),!0}if(message.type==="slot_query"){let entry=this.#slots.get(message.launchId),state=entry===void 0?this.#finished.get(message.launchId)??{ackTick:null,invokeTick:null,invocations:0}:this.clock.read(entry.slot);return this.#channel.send({type:"slot_state",launchId:message.launchId,...state}),!0}return!1}invokeNow(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)throw new LaunchGateError("tool_child_launch_unknown",launchId);this.clock.recordInvoke(entry.slot),this.invoking(launchId)}invoking(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)return;let state=this.clock.read(entry.slot),invokeTick=state.invokeTick;if(invokeTick===null)return;let send=()=>this.#channel.send({type:"launch_proof",launchId,ackTick:state.ackTick,invokeTick}),hold=this.#controls.value("HOLD_LAUNCH_PROOF");if(hold!==void 0&&(hold!=="detached"||entry.lifetime==="detached")){this.#controls.released(`release-proof-${launchId}`).then(send);return}send()}endJobGroups(jobId){let ended=[];for(let[launchId,{request}]of this.#slots)if(!(request.jobId!==jobId||request.lifetime!=="owned"||request.containment!=="own-group")&&!(request.pgid===void 0||request.pgid<=1))try{process.kill(-request.pgid,"SIGKILL"),ended.push({launchId,pgid:request.pgid})}catch{}for(let{launchId}of ended)this.done(launchId,{signal:"SIGKILL"});return ended.map(({pgid})=>pgid)}done(launchId,outcome){let entry=this.#slots.get(launchId);entry!==void 0&&(this.#slots.delete(launchId),this.#finished.set(launchId,this.clock.read(entry.slot)),this.#finished.size>FINISHED_SLOT_STATES&&this.#finished.delete(this.#finished.keys().next().value??""),this.clock.releaseSlot(entry.slot),this.#channel.send({type:"launch_done",launchId,...outcome.exitCode===void 0?{}:{exitCode:outcome.exitCode},...outcome.signal===void 0?{}:{signal:outcome.signal}}))}};import{mkdir as mkdir3,readdir as readdir2,readFile as readFile3,rm as rm4,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname3,join as join4}from"node:path";import{appendFile,mkdir as mkdir2,open,readFile as readFile2,rm as rm3}from"node:fs/promises";import{dirname as dirname2,join as join3}from"node:path";function generationLedgerPath(dir,generation){return join3(dir,`g${generation}`,"descendants.ledger")}var DescendantsLedger=class{#path;#durableDir=!1;#entries=new Map;constructor(path){this.#path=path}get path(){return this.#path}entries(){return[...this.#entries.values()]}async append(entry){if(!this.#durableDir){let directory=dirname2(this.#path);await mkdir2(directory,{recursive:!0,mode:448}),await(await open(this.#path,"a",384)).close(),await syncDirectory(directory),await syncDirectory(dirname2(directory)),this.#durableDir=!0}let handle=await open(this.#path,"a",384);try{await handle.write(`${JSON.stringify(entry)}
|
|
3
3
|
`),await handle.datasync()}finally{await handle.close()}this.#entries.set(entry.launchId,entry)}static async readPersisted(path){let text;try{text=await readFile2(path,"utf8")}catch{return[]}let entries=[];for(let line of text.split(`
|
|
4
4
|
`))if(line.trim()!=="")try{entries.push(JSON.parse(line))}catch{}return entries}async remove(){this.#entries.clear(),await rm3(this.#path,{force:!0})}};async function syncDirectory(directory){if(process.platform==="win32")return;let handle=await open(directory,"r");try{await handle.sync()}finally{await handle.close()}}var LaunchLog=class{#path;#chain=Promise.resolve();#failedWrites=0;constructor(path){this.#path=path}get path(){return this.#path}get failedWrites(){return this.#failedWrites}settled(){return this.#chain}record(record){let line=`${JSON.stringify({atMs:Date.now(),...record})}
|
|
5
|
-
`;return this.#chain=this.#chain.then(async()=>{try{await mkdir2(dirname2(this.#path),{recursive:!0,mode:448}),await appendFile(this.#path,line,{mode:384})}catch{this.#failedWrites+=1}}),this.#chain}};import{execFile}from"node:child_process";async function classifyGroup(group,ownGroup,probes){if(group.lifetime==="detached")return"detached";if(ownGroup===void 0||group.pgid===ownGroup||group.pgid<=1)return"own-group";if(!probes.groupHasMembers(group.pgid))return"empty";if(!probes.isAlive(group.pgid))return"sweep";let observed=await probes.startOf(group.pgid).catch(()=>{}),recorded=group.leaderStart===void 0?void 0:processStartTimeMs(group.leaderStart);return sameProcessStartMs(recorded,observed===void 0?void 0:processStartTimeMs(observed))?"sweep":"leader-reused"}async function sweepGroups(groups,options,probes=defaultGroupProbes){let ownGroup=await probes.ownGroup(),verdicts=await Promise.all(groups.map(async group=>({group,verdict:await classifyGroup(group,ownGroup,probes)}))),targets=verdicts.filter(entry=>entry.verdict==="sweep").map(entry=>entry.group.pgid);for(let pgid of targets)probes.signalGroup(pgid,"SIGTERM");let remaining=await drain(targets,options.graceMs,options.pollMs??25,probes);for(let pgid of remaining)probes.signalGroup(pgid,"SIGKILL");return remaining=await drain(remaining,options.killWaitMs,options.pollMs??25,probes),verdicts.map(({group,verdict})=>({launchId:group.launchId,pgid:group.pgid,verdict,...verdict==="sweep"?{survived:remaining.includes(group.pgid)}:{}}))}async function drain(pgids,budgetMs,pollMs,probes){let remaining=pgids.filter(pgid=>probes.groupHasMembers(pgid));for(let waited=0;remaining.length>0&&waited<budgetMs;waited+=pollMs)await probes.wait(pollMs),remaining=remaining.filter(pgid=>probes.groupHasMembers(pgid));return remaining}function processGroupOf(pid){return process.platform==="win32"?Promise.resolve(void 0):new Promise(resolve=>{execFile("ps",["-o","pgid=","-p",String(pid)],{timeout:2e3},(error,stdout)=>{let text=String(stdout).trim();resolve(error===null&&/^\d+$/u.test(text)?Number(text):void 0)})})}function groupHasMembers(pgid){try{return process.kill(-pgid,0),!0}catch(error){return error instanceof Error&&"code"in error&&error.code==="EPERM"}}var defaultGroupProbes={groupHasMembers,isAlive:
|
|
5
|
+
`;return this.#chain=this.#chain.then(async()=>{try{await mkdir2(dirname2(this.#path),{recursive:!0,mode:448}),await appendFile(this.#path,line,{mode:384})}catch{this.#failedWrites+=1}}),this.#chain}};import{execFile}from"node:child_process";async function classifyGroup(group,ownGroup,probes){if(group.lifetime==="detached")return"detached";if(ownGroup===void 0||group.pgid===ownGroup||group.pgid<=1)return"own-group";if(!probes.groupHasMembers(group.pgid))return"empty";if(!probes.isAlive(group.pgid))return"sweep";let observed=await probes.startOf(group.pgid).catch(()=>{}),recorded=group.leaderStart===void 0?void 0:processStartTimeMs(group.leaderStart);return sameProcessStartMs(recorded,observed===void 0?void 0:processStartTimeMs(observed))?"sweep":"leader-reused"}async function sweepGroups(groups,options,probes=defaultGroupProbes){let ownGroup=await probes.ownGroup(),verdicts=await Promise.all(groups.map(async group=>({group,verdict:await classifyGroup(group,ownGroup,probes)}))),targets=verdicts.filter(entry=>entry.verdict==="sweep").map(entry=>entry.group.pgid);for(let pgid of targets)probes.signalGroup(pgid,"SIGTERM");let remaining=await drain(targets,options.graceMs,options.pollMs??25,probes);for(let pgid of remaining)probes.signalGroup(pgid,"SIGKILL");return remaining=await drain(remaining,options.killWaitMs,options.pollMs??25,probes),verdicts.map(({group,verdict})=>({launchId:group.launchId,pgid:group.pgid,verdict,...verdict==="sweep"?{survived:remaining.includes(group.pgid)}:{}}))}async function drain(pgids,budgetMs,pollMs,probes){let remaining=pgids.filter(pgid=>probes.groupHasMembers(pgid));for(let waited=0;remaining.length>0&&waited<budgetMs;waited+=pollMs)await probes.wait(pollMs),remaining=remaining.filter(pgid=>probes.groupHasMembers(pgid));return remaining}function processGroupOf(pid){return process.platform==="win32"?Promise.resolve(void 0):new Promise(resolve=>{execFile("ps",["-o","pgid=","-p",String(pid)],{timeout:2e3},(error,stdout)=>{let text=String(stdout).trim();resolve(error===null&&/^\d+$/u.test(text)?Number(text):void 0)})})}function groupHasMembers(pgid){try{return process.kill(-pgid,0),!0}catch(error){return error instanceof Error&&"code"in error&&error.code==="EPERM"}}var defaultGroupProbes={groupHasMembers,isAlive:processIsRunning,startOf:pid=>readProcessStartTime(pid),ownGroup:()=>processGroupOf(process.pid),signalGroup:(pgid,signal)=>{try{process.kill(-pgid,signal)}catch{}},wait:ms=>new Promise(resolve=>setTimeout(resolve,ms))};var SWEEP_TIMING={graceMs:500,killWaitMs:1e3};async function sweepLedger(path){let groups=(await DescendantsLedger.readPersisted(path)).flatMap(entry=>entry.pgid===void 0?[]:[{launchId:entry.launchId,pgid:entry.pgid,leaderStart:entry.leaderStart,lifetime:entry.lifetime}]);return groups.length===0?[]:sweepGroups(groups,SWEEP_TIMING)}var GENERATION_CHILD_FILE="child.pid";async function recordGenerationChild(dir,generation,pid){let generationDir=dirname3(generationLedgerPath(dir,generation));await mkdir3(generationDir,{recursive:!0,mode:448}),await writeFile3(join4(generationDir,GENERATION_CHILD_FILE),String(pid),{mode:384})}async function childAlive(file){let pid=Number(await readFile3(file,"utf8").catch(()=>""));if(!Number.isSafeInteger(pid)||pid<=1)return!1;try{return process.kill(pid,0),!0}catch(error){return Reflect.get(Object(error),"code")==="EPERM"}}async function sweepStaleGenerations(dir){let names=await readdir2(dir).catch(()=>[]),outcomes=[];for(let name of names){let generation=/^g(\d+)$/.exec(name)?.[1];generation!==void 0&&(await childAlive(join4(dir,name,GENERATION_CHILD_FILE))||(outcomes.push(...await sweepLedger(generationLedgerPath(dir,Number(generation)))),await rm4(join4(dir,name),{recursive:!0,force:!0})))}return outcomes}var TOOL_CHILD_GENERATION_ENV="SENPI_TOOL_CHILD_GENERATION",TOOL_CHILD_PROTOCOL_VERSION=2,NEVER_CANCELLED=new AbortController().signal;async function runToolChild(options){let env={...options.env??process.env},exit=options.exit??(code=>process.exit(code)),generation=Number(env[TOOL_CHILD_GENERATION_ENV]);(!Number.isSafeInteger(generation)||generation<0)&&(process.stderr.write(`tool-child: invalid generation
|
|
6
6
|
`),exit(70));let channel=await connectChannel(env),controls=readTestControls(env);controls.enabled("EXIT_ON_START")&&exit(1),rememberToolChildReentry(env[TOOL_CHILD_REENTRY_ENV]),options.env===void 0&&scrubToolChildEnv(process.env);let running=new Map,streams=new Map,gate=new LaunchGate(channel),refsRoot=env[TOOL_CHILD_REFS_ROOT_ENV],refs=refsRoot===void 0?void 0:{writer:new PayloadRefWriter({root:refsRoot,generation}),reader:new PayloadRefReader({root:refsRoot,generation,send:control=>channel.send(control)})},hostCalls=new ChildHostCalls(channel,refs),wakes=new WakeAdmission,wakeSeq=0,session={generation,wake:async(source,value)=>{let wakeId=`w${++wakeSeq}`,bytes=Buffer.byteLength(JSON.stringify(value??null));await wakes.send(wakeId,bytes),channel.send({type:"wake",wakeId,source,bytes,value})}},readerBlocked=!1,shutdownRequested=!1;channel.onMessage(message=>{if(controls.enabled("BLOCK_READER")&&!readerBlocked&&(readerBlocked=!0,Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,3e4)),!gate.handle(message)&&!hostCalls.handle(message)){if(message.type==="ref_ack"||message.type==="ref_nack"){refs?.writer.handle(message);return}switch(message.type){case"ping":channel.send({type:"pong",seq:message.seq});return;case"job":controls.value("EXIT_MID_JOB")===message.kind&&exit(1),runJob(channel,gate,hostCalls,refs,options.handlers,running,streams,message,session);return;case"wake_ack":wakes.ack(message.wakeId);return;case"update_ack":streams.get(message.jobId)?.acked(message.seq);return;case"cancel":if(controls.enabled("IGNORE_CANCEL"))return;running.get(message.jobId)?.abort(),channel.send({type:"cancel_ack",jobId:message.jobId});return;case"shutdown":shutdownRequested=!0,channel.close();return;default:return}}}),controls.enabled("HANG_BEFORE_READY")||channel.send({type:"hello",generation,pid:process.pid,protocol:TOOL_CHILD_PROTOCOL_VERSION,jobKinds:Object.keys(options.handlers).sort()}),controls.enabled("STOP_SELF")&&process.kill(process.pid,"SIGSTOP"),await channel.closed,hostCalls.close();for(let controller of running.values())controller.abort();shutdownRequested||await orphanedByHost(env),exit(0)}function readJobArgs(ref,reader,signal){return reader===void 0?Promise.reject(new ToolChildJobError("tool_child_refs_unavailable","a job sent its arguments by reference, but this child reads no references")):unpackPayload(ref,reader,signal)}async function runJob(channel,gate,hostCalls,refs,handlers,running,streams,job,session){let refReader=refs?.reader,handler=handlers[job.kind];if((handler===void 0||running.has(job.jobId))&&job.argsRef!==void 0&&refReader?.refuse(job.argsRef,"cancelled"),handler===void 0){channel.send({type:"job_error",jobId:job.jobId,code:"tool_child_unknown_kind",message:`no handler for ${job.kind}`});return}if(running.has(job.jobId)){channel.send({type:"job_refused",jobId:job.jobId,code:"tool_child_duplicate_job"});return}let controller=new AbortController;running.set(job.jobId,controller);try{let hostCall=(target,options)=>hostCalls.call(job.jobId,target,options?.survivesCancel===!0?NEVER_CANCELLED:controller.signal),args=job.argsRef===void 0?job.args:await readJobArgs(job.argsRef,refReader,controller.signal),stream=new JobUpdates({jobId:job.jobId,channel,...refs===void 0?{}:{writer:refs.writer}});streams.set(job.jobId,stream);let update=value2=>stream.update(value2),value=await handler(args,{jobId:job.jobId,signal:controller.signal,channel,gate,hostCall,update,generation:session.generation,wake:session.wake});channel.send({type:"result",jobId:job.jobId,value:value??null})}catch(error){let code=error instanceof ToolChildJobError?error.code:controller.signal.aborted?"tool_child_cancelled":"tool_child_job_failed";channel.send({type:"job_error",jobId:job.jobId,code,message:error instanceof Error?error.message:String(error)})}finally{running.delete(job.jobId),streams.get(job.jobId)?.end(),streams.delete(job.jobId)}}async function orphanedByHost(env){let ledger=env[TOOL_CHILD_LEDGER_ENV];if(ledger!==void 0&&await sweepLedger(ledger).catch(()=>[]),process.platform!=="win32")try{process.kill(-process.pid,"SIGKILL")}catch{}}import{realpathSync,statSync}from"node:fs";import{isAbsolute,relative,sep}from"node:path";import{extname}from"node:path";import{fileURLToPath}from"node:url";import realWorkerThreads,{parentPort,Worker}from"node:worker_threads";function goShimScript(fd){return[`IFS= read -r _go <&${fd} || exit 127`,`command -v "$0" >/dev/null 2>&1 || { printf 'ENOENT\\n' >&${fd}; exit 127; }`,`exec "$0" "$@" ${fd}<&-`].join("; ")}function controlFd(callerStdio){return Math.max(3,callerStdio.length)}function withControlPipe(callerStdio,fd,pad,pipe){let stdio=[...callerStdio];for(;stdio.length<fd;)stdio.push(pad);return stdio.push(pipe),stdio}function isLaunchMessage(value){return typeof value=="object"&&value!==null&&"kind"in value&&(value.kind==="launch"||value.kind==="invoking"||value.kind==="started"||value.kind==="done")}function startGatedWorker(gate,file,jobId,options={}){let workerData={...options.workerData,barrierClock:gate.clock.buffer,jobId,reentry:toolChildReentry()},worker=new Worker(file,{...options,workerData});return worker.on("message",message=>{isLaunchMessage(message)&&gate.handleWorker(message)}),worker}function siblingWorkerUrl(sourceSpecifier,callerUrl){let extension=extname(fileURLToPath(callerUrl));return new URL(sourceSpecifier.replace(/\.ts$/,extension),callerUrl)}var MODULE_JOB_KIND="module",TOOL_CHILD_MODULE_ROOTS_ENV="SENPI_TOOL_CHILD_MODULE_ROOTS";function parseModuleJobArgs(value){if(typeof value!="object"||value===null)throw new ToolChildJobError("module_job_invalid","args must be an object");let modulePath=Reflect.get(value,"modulePath"),exportName=Reflect.get(value,"export");if(typeof modulePath!="string"||!isAbsolute(modulePath))throw new ToolChildJobError("module_job_invalid","modulePath must be an absolute path");if(typeof exportName!="string"||exportName.length===0)throw new ToolChildJobError("module_job_invalid","export must be a non-empty string");return{modulePath,export:exportName,args:Reflect.get(value,"args")}}function parseModuleRoots(env){let raw=env[TOOL_CHILD_MODULE_ROOTS_ENV];if(raw===void 0||raw==="")return[];let parsed=JSON.parse(raw);if(!Array.isArray(parsed)||!parsed.every(root=>typeof root=="string"&&isAbsolute(root)))throw new ToolChildJobError("module_job_invalid",`${TOOL_CHILD_MODULE_ROOTS_ENV} must be a JSON array of absolute paths`);return parsed}function realpathOrUndefined(path){try{return realpathSync(path)}catch{return}}function containedModulePath(modulePath,roots){let resolved=realpathOrUndefined(modulePath);if(resolved===void 0)throw new ToolChildJobError("offload_module_unavailable",`${modulePath} does not exist`);for(let root of roots){let realRoot=realpathOrUndefined(root);if(realRoot===void 0)continue;if(resolved===realRoot&&statSync(resolved).isFile())return resolved;let inside=relative(realRoot,resolved);if(inside!==""&&!inside.startsWith(`..${sep}`)&&inside!==".."&&!isAbsolute(inside))return resolved}throw new ToolChildJobError("module_job_outside_roots",`${modulePath} is not inside an installed extension directory`)}var MODULE_CANCEL_GRACE_MS=2e3;function createModuleJobHandler(env={...process.env}){return async(value,context)=>{let job=parseModuleJobArgs(value),modulePath=containedModulePath(job.modulePath,parseModuleRoots(env)),worker=startGatedWorker(context.gate,siblingWorkerUrl("./module-job-worker.ts",import.meta.url),context.jobId,{workerData:{modulePath,exportName:job.export,args:job.args}}),cancelled=!1,graceTimer,locks=new JobFileLocks(context),abort=()=>{cancelled=!0,worker.postMessage({kind:"cancel"}),graceTimer=setTimeout(()=>{worker.terminate()},MODULE_CANCEL_GRACE_MS)};context.signal.addEventListener("abort",abort,{once:!0});try{let outcome=new Promise((resolve,reject)=>{worker.on("message",message=>{if(typeof message!="object"||message===null)return;let kind=Reflect.get(message,"kind");if(kind==="host_call"){forwardHostCall(worker,context,locks,message);return}kind==="module_result"?resolve(Reflect.get(message,"value")):kind==="module_error"&&reject(new ToolChildJobError(String(Reflect.get(message,"code")),String(Reflect.get(message,"message"))))}),worker.once("error",error=>reject(new ToolChildJobError("module_job_failed",error instanceof Error?error.message:String(error)))),worker.once("exit",code=>reject(new ToolChildJobError("module_job_failed",`worker exited (${code})`)))});try{return await outcome}catch(error){throw cancelled?new ToolChildJobError("tool_child_cancelled","the job was cancelled"):error}}finally{context.signal.removeEventListener("abort",abort),clearTimeout(graceTimer),await worker.terminate(),cancelled&&context.gate.endJobGroups(context.jobId),await locks.releaseAll()}}}var JobFileLocks=class{#context;#held=new Set;#closed=!1;constructor(context){this.#context=context}granted(lockId){return this.#closed?(this.#unlock(lockId),!1):(this.#held.add(lockId),!0)}released(lockId){this.#held.delete(lockId)}async releaseAll(){this.#closed=!0;let held=[...this.#held];this.#held.clear(),await Promise.allSettled(held.map(lockId=>this.#unlock(lockId)))}#unlock(lockId){return this.#context.hostCall({kind:"unlock_file",args:{lockId}},{survivesCancel:!0})}};function forwardHostCall(worker,context,locks,message){let callId=Reflect.get(message,"callId"),kind=Reflect.get(message,"hostKind"),name=Reflect.get(message,"name");if(typeof callId!="string"||!isHostCallKind(kind))return;let args=Reflect.get(message,"args"),lockCall=kind==="lock_file"||kind==="unlock_file";context.hostCall({kind,...typeof name=="string"?{name}:{},...args===void 0?{}:{args}},{survivesCancel:lockCall}).then(value=>{let lockId=typeof value=="object"&&value!==null?Reflect.get(value,"lockId"):void 0;if(!(kind==="lock_file"&&typeof lockId=="string"&&!locks.granted(lockId))){if(kind==="unlock_file"){let released=typeof args=="object"&&args!==null?Reflect.get(args,"lockId"):void 0;typeof released=="string"&&locks.released(released)}worker.postMessage({kind:"host_reply",callId,value})}},error=>worker.postMessage({kind:"host_reply",callId,error:error instanceof Error?error.message:String(error),code:error instanceof ToolChildJobError?error.code:"host_call_failed"}))}function isHostCallKind(value){return typeof value=="string"&&HOST_CALL_KINDS.some(kind=>kind===value)}var DEFAULT_MAX_LINES=2e3,DEFAULT_MAX_BYTES=51200;function splitLinesForCounting(content){if(content.length===0)return[];let lines=content.split(`
|
|
7
7
|
`);return content.endsWith(`
|
|
8
8
|
`)&&lines.pop(),lines}function formatSize(bytes){return bytes<1024?`${bytes}B`:bytes<1024*1024?`${(bytes/1024).toFixed(1)}KB`:`${(bytes/(1024*1024)).toFixed(1)}MB`}function truncateHead(content,options={}){let maxLines=options.maxLines??2e3,maxBytes=options.maxBytes??51200,totalBytes=Buffer.byteLength(content,"utf-8"),lines=splitLinesForCounting(content),totalLines=lines.length;if(totalLines<=maxLines&&totalBytes<=maxBytes)return{content,truncated:!1,truncatedBy:null,totalLines,totalBytes,outputLines:totalLines,outputBytes:totalBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes};if(Buffer.byteLength(lines[0],"utf-8")>maxBytes)return{content:"",truncated:!0,truncatedBy:"bytes",totalLines,totalBytes,outputLines:0,outputBytes:0,lastLinePartial:!1,firstLineExceedsLimit:!0,maxLines,maxBytes};let outputLinesArr=[],outputBytesCount=0,truncatedBy="lines";for(let i=0;i<lines.length&&i<maxLines;i++){let line=lines[i],lineBytes=Buffer.byteLength(line,"utf-8")+(i>0?1:0);if(outputBytesCount+lineBytes>maxBytes){truncatedBy="bytes";break}outputLinesArr.push(line),outputBytesCount+=lineBytes}outputLinesArr.length>=maxLines&&outputBytesCount<=maxBytes&&(truncatedBy="lines");let outputContent=outputLinesArr.join(`
|
|
9
9
|
`),finalOutputBytes=Buffer.byteLength(outputContent,"utf-8");return{content:outputContent,truncated:!0,truncatedBy,totalLines,totalBytes,outputLines:outputLinesArr.length,outputBytes:finalOutputBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes}}function truncateTail(content,options={}){let maxLines=options.maxLines??2e3,maxBytes=options.maxBytes??51200,totalBytes=Buffer.byteLength(content,"utf-8"),lines=splitLinesForCounting(content),totalLines=lines.length;if(totalLines<=maxLines&&totalBytes<=maxBytes)return{content,truncated:!1,truncatedBy:null,totalLines,totalBytes,outputLines:totalLines,outputBytes:totalBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes};let outputLinesArr=[],outputBytesCount=0,truncatedBy="lines",lastLinePartial=!1;for(let i=lines.length-1;i>=0&&outputLinesArr.length<maxLines;i--){let line=lines[i],lineBytes=Buffer.byteLength(line,"utf-8")+(outputLinesArr.length>0?1:0);if(outputBytesCount+lineBytes>maxBytes){if(truncatedBy="bytes",outputLinesArr.length===0){let truncatedLine=truncateStringToBytesFromEnd(line,maxBytes);outputLinesArr.unshift(truncatedLine),outputBytesCount=Buffer.byteLength(truncatedLine,"utf-8"),lastLinePartial=!0}break}outputLinesArr.unshift(line),outputBytesCount+=lineBytes}outputLinesArr.length>=maxLines&&outputBytesCount<=maxBytes&&(truncatedBy="lines");let outputContent=outputLinesArr.join(`
|
|
10
|
-
`),finalOutputBytes=Buffer.byteLength(outputContent,"utf-8");return{content:outputContent,truncated:!0,truncatedBy,totalLines,totalBytes,outputLines:outputLinesArr.length,outputBytes:finalOutputBytes,lastLinePartial,firstLineExceedsLimit:!1,maxLines,maxBytes}}function truncateStringToBytesFromEnd(str,maxBytes){let buf=Buffer.from(str,"utf-8");if(buf.length<=maxBytes)return str;let start=buf.length-maxBytes;for(;start<buf.length&&(buf[start]&192)===128;)start++;return buf.slice(start).toString("utf-8")}function truncateLine(line,maxChars=500){return line.length<=maxChars?{text:line,wasTruncated:!1}:{text:`${line.slice(0,maxChars)}... [truncated]`,wasTruncated:!0}}function truncateToVisualLines(text,maxVisualLines,width,paddingX=0,keep="end"){if(!text)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var TerminalManager=class{constructor(options={}){this.runtimes=new Map,this.monitorIds=new Map,this.exited=new Set,this.reservations=0,this.maxSessions=options.maxSessions??DEFAULT_MAX_SESSIONS,this.scrollback=options.scrollback,options.idScope!==void 0&&(this.idScope=options.idScope)}get size(){return this.runtimes.size}get activeSize(){return this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations}reserve(){if(this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations>=this.maxSessions)return null;this.reservations+=1;let released=!1;return()=>{released||(released=!0,this.reservations-=1)}}async create(command,options){let pty=await loadPty(),release=this.reserve();if(!release)throw new pty.SessionRegistryCapacityError(this.maxSessions);this.registry??=new pty.SessionRegistry({maxSessions:this.maxSessions,...this.idScope===void 0?{}:{idScope:this.idScope}});let registry=this.registry,runtimeOptions={...options,scrollback:this.scrollback},{TerminalRuntimeSession}=await import("./runtime-session-
|
|
10
|
+
`),finalOutputBytes=Buffer.byteLength(outputContent,"utf-8");return{content:outputContent,truncated:!0,truncatedBy,totalLines,totalBytes,outputLines:outputLinesArr.length,outputBytes:finalOutputBytes,lastLinePartial,firstLineExceedsLimit:!1,maxLines,maxBytes}}function truncateStringToBytesFromEnd(str,maxBytes){let buf=Buffer.from(str,"utf-8");if(buf.length<=maxBytes)return str;let start=buf.length-maxBytes;for(;start<buf.length&&(buf[start]&192)===128;)start++;return buf.slice(start).toString("utf-8")}function truncateLine(line,maxChars=500){return line.length<=maxChars?{text:line,wasTruncated:!1}:{text:`${line.slice(0,maxChars)}... [truncated]`,wasTruncated:!0}}function truncateToVisualLines(text,maxVisualLines,width,paddingX=0,keep="end"){if(!text)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var TerminalManager=class{constructor(options={}){this.runtimes=new Map,this.monitorIds=new Map,this.exited=new Set,this.reservations=0,this.maxSessions=options.maxSessions??DEFAULT_MAX_SESSIONS,this.scrollback=options.scrollback,options.idScope!==void 0&&(this.idScope=options.idScope)}get size(){return this.runtimes.size}get activeSize(){return this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations}reserve(){if(this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations>=this.maxSessions)return null;this.reservations+=1;let released=!1;return()=>{released||(released=!0,this.reservations-=1)}}async create(command,options){let pty=await loadPty(),release=this.reserve();if(!release)throw new pty.SessionRegistryCapacityError(this.maxSessions);this.registry??=new pty.SessionRegistry({maxSessions:this.maxSessions,...this.idScope===void 0?{}:{idScope:this.idScope}});let registry=this.registry,runtimeOptions={...options,scrollback:this.scrollback},{TerminalRuntimeSession}=await import("./runtime-session-V5OO7ZRM.js"),runtime=new TerminalRuntimeSession(command,runtimeOptions),entry;try{entry=await registry.create({command,session:runtime.session})}catch(error){throw release(),runtime.dispose(),runtime.session.kill(),error}return this.runtimes.set(entry.id,runtime),runtime.session.onExit(()=>{this.exited.add(entry.id)}),release(),this.reconcileRuntimes(),{id:entry.id,runtime}}get(id){let registry=this.registry;return!registry||!registry.get(id)?null:this.runtimes.get(id)??null}bindMonitorId(monitorId,sessionId){this.monitorIds.set(monitorId,sessionId)}monitorIdOf(runtimeId){for(let[monitorId,sessionId]of this.monitorIds)if(sessionId===runtimeId)return monitorId}resolveId(idOrMonitorId){if(idOrMonitorId.startsWith("mon_"))return this.monitorIds.get(idOrMonitorId);let registry=this.registry;if(registry)return registry.get(idOrMonitorId)?idOrMonitorId:void 0}list(){let registry=this.registry;if(!registry)return[];let result=[];for(let entry of registry.list()){let runtime=this.runtimes.get(entry.id);runtime&&result.push({id:entry.id,runtime})}return result}async stop(id){let registry=this.registry;if(!registry)return!1;let stopped=await registry.stop(id);return this.reconcileRuntimes(),stopped}async teardown(){let registry=this.registry;registry&&await registry.teardown(),this.registry=void 0;for(let runtime of this.runtimes.values())runtime.dispose();this.runtimes.clear(),this.exited.clear(),this.monitorIds.clear()}reconcileRuntimes(){let registry=this.registry;if(!registry)return;let liveIds=new Set(registry.list().map(entry=>entry.id));for(let[id,runtime]of this.runtimes)if(!liveIds.has(id)){runtime.dispose(),this.runtimes.delete(id),this.exited.delete(id);for(let[monitorId,sessionId]of this.monitorIds)sessionId===id&&this.monitorIds.delete(monitorId)}}};function modelOnlyText(text){return{type:"text",text,audience:"model"}}function isModelOnlyText(part){return typeof part=="object"&&part!==null&&"type"in part&&part.type==="text"&&"audience"in part&&part.audience==="model"}var TERMINAL_TOOL_MAX_LINES=2e3,TERMINAL_TOOL_MAX_BYTES=50*1024,OSC_PATTERN=/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,CSI_PATTERN=/\x1b\[[0-?]*[ -/]*[@-~]/g,DESIGNATE_AND_SINGLE_PATTERN=/\x1b(?:[()#%*+][0-9A-Za-z]|[0-9<=>@-Z\\-_])/g,C0_CONTROL_PATTERN=/[\x00-\x07\x0b\x0c\x0e-\x1f\x7f]/g;function stripEscapeSequences(text){return text.replace(OSC_PATTERN,"").replace(CSI_PATTERN,"").replace(DESIGNATE_AND_SINGLE_PATTERN,"").replace(C0_CONTROL_PATTERN,"")}function collapseRedraws(line){let cells=[],cursor=0;for(let ch of line)ch==="\r"?cursor=0:ch==="\b"?cursor>0&&(cursor-=1):(cells[cursor]=ch,cursor+=1);return cells.join("")}function sanitizeTerminalOutput(raw){return stripEscapeSequences(raw).replace(/\r\n/g,`
|
|
11
11
|
`).split(`
|
|
12
12
|
`).map(collapseRedraws).join(`
|
|
13
13
|
`)}function formatTerminalToolOutput(raw){let sanitized=sanitizeTerminalOutput(raw).trimEnd(),truncation=truncateTail(sanitized,{maxLines:TERMINAL_TOOL_MAX_LINES,maxBytes:TERMINAL_TOOL_MAX_BYTES});if(!truncation.truncated)return{text:sanitized,body:sanitized,truncated:!1,truncation};let marker=truncation.lastLinePartial?`[Showing last ${formatSize(truncation.outputBytes)} of a single line; earlier output dropped]`:`[Showing lines ${truncation.totalLines-truncation.outputLines+1}-${truncation.totalLines} of ${truncation.totalLines}; earlier output dropped]`;return{text:`${truncation.content}
|
|
@@ -1,4 +1,4 @@
|
|
|
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{TOOL_CHILD_ROLE_ENV,channelEnvPresent}from"./chunk-V3CK2AVC.js";var role=process.env[TOOL_CHILD_ROLE_ENV];if(role!==void 0&&role!==""){if(role==="launch-shim"){let{runLaunchShimRole}=await import("./launch-shim-role-Q6NG2YCV.js");runLaunchShimRole()}role!=="tool-child"&&(process.stderr.write(`senpi: unknown internal role ${JSON.stringify(role)}
|
|
3
3
|
`),process.exit(70)),channelEnvPresent(process.env)||(process.stderr.write(`tool-child: channel unavailable
|
|
4
|
-
`),process.exit(70));let{runToolChildRole}=await import("./role-
|
|
4
|
+
`),process.exit(70));let{runToolChildRole}=await import("./role-JVSBNKGE.js");await runToolChildRole()}
|