@code-yeongyu/senpi 2026.11.6-3 → 2026.11.9-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 +34 -0
- package/dist/bundle/chunks/{chunk-5LKB732P.js → chunk-3TZQXZKH.js} +1 -1
- package/dist/bundle/chunks/{chunk-X53PD4ZC.js → chunk-45MVD7BU.js} +1 -1
- package/dist/bundle/chunks/{chunk-L7ZIS3MC.js → chunk-4JIBEZZE.js} +3 -3
- package/dist/bundle/chunks/{chunk-CF5OGBC4.js → chunk-4NYNMAYF.js} +1 -1
- package/dist/bundle/chunks/{chunk-6CEDL5S2.js → chunk-4UR6UFBH.js} +1 -1
- package/dist/bundle/chunks/{chunk-F5JLDCYD.js → chunk-527Q2UYM.js} +5 -5
- package/dist/bundle/chunks/{chunk-7DRWPZ3N.js → chunk-622VYTRI.js} +1 -1
- package/dist/bundle/chunks/{chunk-V2QAYGOK.js → chunk-7CFORZPE.js} +22 -22
- package/dist/bundle/chunks/{chunk-GKAYPJ4E.js → chunk-7PROV6BB.js} +1 -1
- package/dist/bundle/chunks/{chunk-4E7GDG4H.js → chunk-7VMEE62L.js} +1 -1
- package/dist/bundle/chunks/{chunk-4BATXPB7.js → chunk-K3UHGDUQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-MJTCZUXS.js → chunk-LHSWAJJL.js} +1 -1
- package/dist/bundle/chunks/{chunk-SB6MXNO5.js → chunk-M7GF73FO.js} +2 -2
- package/dist/bundle/chunks/{chunk-CFEHJ4VU.js → chunk-NDSWTAYJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-JMQOLOC2.js → chunk-Q6NR6644.js} +1 -1
- package/dist/bundle/chunks/{chunk-EO2VPZ2K.js → chunk-SGAFIMAU.js} +1 -1
- package/dist/bundle/chunks/{chunk-BASS47UD.js → chunk-STGOYIXC.js} +1 -1
- package/dist/bundle/chunks/{chunk-DSWDJ7HT.js → chunk-WQ4RBPMS.js} +1 -1
- package/dist/bundle/chunks/chunk-XZDCMDUH.js +2 -0
- package/dist/bundle/chunks/{chunk-LUZVGPQ7.js → chunk-Y5L4UFMI.js} +1 -1
- package/dist/bundle/chunks/{cli-main-RWHDZKTQ.js → cli-main-XBEFQW5A.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-G5LYF62Q.js → hand-entry-QFEY3JMQ.js} +1 -1
- package/dist/bundle/chunks/{headless-host-ES74ZB6M.js → headless-host-YXUGONR3.js} +1 -1
- package/dist/bundle/chunks/{host-command-I2JZ5JM7.js → host-command-VHX2ILLM.js} +1 -1
- package/dist/bundle/chunks/{host-session-command-Y52NFPP2.js → host-session-command-P3MRW63Z.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-PA7DGVS6.js → interactive-mode-YGL3QHU6.js} +1 -1
- package/dist/bundle/chunks/{main-OBL6375C.js → main-5SD4DHMC.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-NM6I5BWZ.js → multi-session-host-PGRHY3JP.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-GNRQ5MVR.js → package-manager-cli-SADLU7QX.js} +1 -1
- package/dist/bundle/chunks/{role-F56BS2ZQ.js → role-4BUU46VW.js} +3 -3
- package/dist/bundle/chunks/{rotation-stream-BN2YK2MC.js → rotation-stream-TODBIHXJ.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-G4KIP7XS.js → rpc-mode-27TC7W6K.js} +1 -1
- package/dist/bundle/chunks/{run-attached-tui-XTGPAGYM.js → run-attached-tui-MXCC5IZR.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-L4M3TSQ3.js → schedule-command-MX56D6UE.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-V46WMCDF.js → session-control-endpoint-IL6ERD4U.js} +1 -1
- package/dist/bundle/chunks/{session-picker-AG6KSR5A.js → session-picker-6VRC25MJ.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +44 -44
- package/dist/bundle/cli.js +2 -2
- 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-services.d.ts +2 -0
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session.d.ts +8 -0
- package/dist/core/agent-session.js +51 -4
- package/dist/core/egress/classify.d.ts +8 -3
- package/dist/core/egress/classify.js +177 -158
- package/dist/core/egress/console-redactor.d.ts +7 -0
- package/dist/core/egress/console-redactor.js +74 -0
- package/dist/core/egress/credentials.d.ts +73 -0
- package/dist/core/egress/credentials.js +20 -0
- package/dist/core/egress/device-custody.d.ts +1 -1
- package/dist/core/egress/device-custody.js +18 -15
- package/dist/core/egress/device-proxy-call.d.ts +59 -0
- package/dist/core/egress/device-proxy-call.js +148 -0
- package/dist/core/egress/device-proxy-lost-calls.d.ts +27 -0
- package/dist/core/egress/device-proxy-lost-calls.js +28 -0
- package/dist/core/egress/device-proxy-ports.d.ts +49 -0
- package/dist/core/egress/device-proxy-ports.js +2 -0
- package/dist/core/egress/device-proxy-request.d.ts +34 -0
- package/dist/core/egress/device-proxy-request.js +69 -0
- package/dist/core/egress/device-proxy-waits.d.ts +40 -0
- package/dist/core/egress/device-proxy-waits.js +67 -0
- package/dist/core/egress/device-proxy.d.ts +3 -0
- package/dist/core/egress/device-proxy.js +214 -0
- package/dist/core/egress/endpoint.js +2 -1
- package/dist/core/egress/entry-verify.d.ts +13 -0
- package/dist/core/egress/entry-verify.js +33 -0
- package/dist/core/egress/hpke.js +13 -9
- package/dist/core/egress/key-policy-template.d.ts +7 -1
- package/dist/core/egress/ledger-schema.d.ts +80 -0
- package/dist/core/egress/ledger-schema.js +117 -0
- package/dist/core/egress/ledger.d.ts +55 -0
- package/dist/core/egress/ledger.js +159 -0
- package/dist/core/egress/pinned-infra.d.ts +23 -2
- package/dist/core/egress/pinned-infra.js +9 -2
- package/dist/core/egress/redact.d.ts +10 -0
- package/dist/core/egress/redact.js +134 -0
- package/dist/core/egress/sealed-source.d.ts +35 -0
- package/dist/core/egress/sealed-source.js +140 -0
- package/dist/core/egress/verified-keys.js +1 -1
- package/dist/core/egress/wire.d.ts +5 -3
- package/dist/core/egress/wire.js +5 -3
- package/dist/core/extensions/builtin/monitor-state-event.d.ts +26 -0
- package/dist/core/extensions/builtin/monitor-state-event.js +2 -0
- package/dist/core/extensions/builtin/terminal/background-age.d.ts +25 -0
- package/dist/core/extensions/builtin/terminal/background-age.js +91 -0
- package/dist/core/extensions/builtin/terminal/extension-state.d.ts +1 -1
- package/dist/core/extensions/builtin/terminal/extension-state.js +21 -3
- package/dist/core/extensions/builtin/terminal/notify.d.ts +6 -0
- package/dist/core/extensions/builtin/terminal/notify.js +39 -5
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +9 -2
- package/dist/core/extensions/builtin/terminal/session-bundle.js +36 -1
- package/dist/core/extensions/builtin/terminal/settings.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/settings.js +8 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.d.ts +15 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.js +87 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.js +6 -6
- package/dist/core/extensions/builtin/terminal/tools/child-placement.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/tools/child-placement.js +43 -6
- package/dist/core/extensions/builtin/terminal/tools/context.d.ts +11 -2
- package/dist/core/extensions/session-control-types.d.ts +15 -0
- package/dist/core/extensions/session-control-types.js +11 -0
- package/dist/core/external-admission.d.ts +16 -2
- package/dist/core/external-admission.js +22 -4
- package/dist/core/retry-fallback/controller.d.ts +1 -0
- package/dist/core/retry-fallback/controller.js +3 -0
- package/dist/core/retry-fallback/unusable.d.ts +2 -0
- package/dist/core/retry-fallback/unusable.js +7 -1
- package/dist/core/retry-fallback/usage-limit.d.ts +6 -1
- package/dist/core/retry-fallback/usage-limit.js +9 -4
- package/dist/core/sdk.d.ts +6 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/terminal-settings.d.ts +1 -0
- package/dist/core/turn-origin.d.ts +4 -0
- package/dist/core/turn-origin.js +10 -0
- package/dist/modes/interactive/components/remote-delivery-message.d.ts +2 -1
- package/dist/modes/interactive/components/remote-delivery-message.js +13 -5
- package/dist/modes/rpc/admit-external-message-command.d.ts +37 -0
- package/dist/modes/rpc/admit-external-message-command.js +61 -0
- package/dist/modes/rpc/admit-external-message-wire.d.ts +42 -0
- package/dist/modes/rpc/admit-external-message-wire.js +55 -0
- package/dist/modes/rpc/connection-handler.js +14 -0
- package/dist/modes/rpc/effect-commands.d.ts +1 -1
- package/dist/modes/rpc/host-idle-handover.js +1 -0
- package/dist/modes/rpc/method-classes-schema-delivery.d.ts +32 -0
- package/dist/modes/rpc/method-classes-schema-delivery.js +22 -0
- package/dist/modes/rpc/method-classes-schema-session.d.ts +27 -0
- package/dist/modes/rpc/method-classes-schema-session.js +2 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +27 -0
- package/dist/modes/rpc/method-classes.d.ts +1 -0
- package/dist/modes/rpc/method-classes.js +2 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -3
- package/dist/modes/rpc/rpc-response-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-command-types.d.ts +2 -1
- package/dist/modes/rpc/tool-child/terminal-jobs.d.ts +1 -0
- package/dist/modes/rpc/tool-child/terminal-jobs.js +17 -1
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +19 -2
- package/docs/rpc.md +57 -0
- package/docs/terminal-tools.md +25 -1
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-UODSYQ2D.js +0 -2
|
@@ -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{parseEntryLine,resolveMovedPath,sessionInfoName,visibleMessage}from"./chunk-GTJJ73DE.js";import{appendToolResultUserWords}from"./chunk-22YXCY7K.js";import{BaseContentHash,EventLoopSlicer,TranscriptJournal,blockCallKey,captureAndCloseFileIdentity,captureFileIdentity,captureTranscriptBase,compactUpdatesEnabled,discardFailedFirstFlush,discardFailedFirstFlushAsync,loadEntriesFromFile,loadEntriesFromFileAsync,loadedContentFingerprints,loadedFileIdentities,mapInSlices,parseSessionEntryLine,readForkSource,replaceFileAtomically,sessionRecoveryCause,snapshotTranscript,terminateFinalSessionLine,truncateToLastCompleteLine}from"./chunk-J2I56WLK.js";import{SessionWriteFence}from"./chunk-SOMFLLPD.js";import{appendRecordWrites,createAdmissionLine,divergenceWrite,manifestWrite,openSessionStore,openSyncSessionStore,readSessionState,rewriteRecordWrite}from"./chunk-
|
|
2
|
+
import{parseEntryLine,resolveMovedPath,sessionInfoName,visibleMessage}from"./chunk-GTJJ73DE.js";import{appendToolResultUserWords}from"./chunk-22YXCY7K.js";import{BaseContentHash,EventLoopSlicer,TranscriptJournal,blockCallKey,captureAndCloseFileIdentity,captureFileIdentity,captureTranscriptBase,compactUpdatesEnabled,discardFailedFirstFlush,discardFailedFirstFlushAsync,loadEntriesFromFile,loadEntriesFromFileAsync,loadedContentFingerprints,loadedFileIdentities,mapInSlices,parseSessionEntryLine,readForkSource,replaceFileAtomically,sessionRecoveryCause,snapshotTranscript,terminateFinalSessionLine,truncateToLastCompleteLine}from"./chunk-J2I56WLK.js";import{SessionWriteFence}from"./chunk-SOMFLLPD.js";import{appendRecordWrites,createAdmissionLine,divergenceWrite,manifestWrite,openSessionStore,openSyncSessionStore,readSessionState,rewriteRecordWrite}from"./chunk-7PROV6BB.js";import{dropFailedAssistantTurns}from"./chunk-YUVC7SJB.js";import{copyContextProvenance}from"./chunk-ZDHAJROE.js";import{getCurrentSystemMessage,isModelType,lazyStream,normalizeProviderId}from"./chunk-OKMHSVCA.js";import{APP_NAME,getAgentDir,getSessionsDir,normalizePath,resolvePath}from"./chunk-SODMQEHO.js";var VIRTUAL_MODEL_API="pi-virtual",VIRTUAL_MODEL_STATE_ENTRY="pi.virtual-model-state",THINKING_LEVELS=["off","minimal","low","medium","high","xhigh","max"];function isVirtualModel(model){return model.api===VIRTUAL_MODEL_API}function findLatestResponse(messages){for(let i=messages.length-1;i>=0;i--){let message=messages[i];if(message.role==="assistant"&&message.stopReason!=="error"&&message.stopReason!=="aborted")return message}}function getBranchSelection(branch,getModel){for(let i=branch.length-1;i>=0;i--){let entry=branch[i];if(entry.type==="model_change")return{provider:entry.provider,modelId:entry.modelId};if(entry.type==="message"&&entry.message.role==="assistant"&&!isVirtualModel(entry.message)){let response={provider:entry.message.provider,modelId:entry.message.model},change=findLastModelChange(branch,i),model=change&&getModel(change.provider,change.modelId);return change&&model&&isVirtualModel(model)?change:response}}}function findLastModelChange(branch,before){for(let i=before-1;i>=0;i--){let entry=branch[i];if(entry.type==="model_change")return{provider:entry.provider,modelId:entry.modelId}}}function getVirtualModelState(branch,provider,modelId){for(let i=branch.length-1;i>=0;i--){let entry=branch[i];if(entry.type!=="custom"||entry.customType!==VIRTUAL_MODEL_STATE_ENTRY)continue;let data=entry.data;if(data?.provider===provider&&data.modelId===modelId)return data.state}}function createVirtualModel(definition){let levels=definition.thinkingLevels??["off"],thinkingLevelMap={};for(let level of THINKING_LEVELS)thinkingLevelMap[level]=levels.includes(level)?level:null;return{id:definition.id,name:definition.name,api:VIRTUAL_MODEL_API,provider:definition.provider,baseUrl:"",reasoning:levels.some(level=>level!=="off"),thinkingLevelMap,input:definition.input??["text","image"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:definition.contextWindow??0,maxTokens:definition.maxTokens??0}}function unroutedStream(model){return lazyStream(model,async()=>{throw new Error(`Virtual model ${model.provider}/${model.id} must be routed before streaming`)})}function withVirtualModels(providerId,provider,virtualModels){if(!provider)return{id:providerId,name:providerId,auth:{apiKey:{name:"Virtual model",resolve:async()=>({auth:{},source:"virtual"})}},getModels:()=>virtualModels,stream:unroutedStream,streamSimple:unroutedStream};let ids=new Set(virtualModels.map(model=>model.id)),physical=models=>models.filter(model=>!isVirtualModel(model)&&!(isModelType(model,"chat")&&ids.has(model.id))),virtual=models=>models.filter(model=>isVirtualModel(model)),{filterModels,filterAllModels}=provider;return{...provider,getModels:()=>[...physical(provider.getModels()),...virtualModels],getAllModels:()=>[...physical(provider.getAllModels?.()??provider.getModels()),...virtualModels],filterModels:(models,credential)=>{let real=physical(models);return[...filterModels?.(real,credential)??real,...virtual(models)]},filterAllModels:filterAllModels&&((models,credential)=>[...filterAllModels(physical(models),credential),...virtual(models)]),stream:(model,context,options)=>isVirtualModel(model)?unroutedStream(model):provider.stream(model,context,options),streamSimple:(model,context,options)=>isVirtualModel(model)?unroutedStream(model):provider.streamSimple(model,context,options)}}var ENVIRONMENT_CONTEXT_MESSAGE_TYPE="environment-context",CURRENT_DATE_ENV="SENPI_TEST_CURRENT_DATE";function pinnedCurrentDate(){let value=process.env[CURRENT_DATE_ENV];if(value===void 0||value==="")return;let parsed=new Date(`${value}T00:00:00.000Z`);if(!(/^\d{4}-\d{2}-\d{2}$/.test(value)&&!Number.isNaN(parsed.getTime())&&parsed.toISOString().startsWith(value)))throw new Error(`${CURRENT_DATE_ENV} must be a calendar date YYYY-MM-DD, got ${JSON.stringify(value)}`);return value}function resolveEnvironmentContext(cwd,now=new Date){return{cwd:cwd.replace(/\\/g,"/"),currentDate:pinnedCurrentDate()??now.toISOString().slice(0,10)}}function formatEnvironmentContext(context){return["<environment_context>",` <cwd>${context.cwd}</cwd>`,` <current_date>${context.currentDate}</current_date>`,"</environment_context>"].join(`
|
|
3
3
|
`)}function isEnvironmentContext(value){if(typeof value!="object"||value===null)return!1;let candidate=value;return typeof candidate.cwd=="string"&&typeof candidate.currentDate=="string"}function latestEnvironmentContext(messages){for(let index=messages.length-1;index>=0;index--){let message=messages[index];if(message.role==="custom"&&message.customType===ENVIRONMENT_CONTEXT_MESSAGE_TYPE&&isEnvironmentContext(message.details))return message.details}}function createEnvironmentContextMessage(context,timestamp=Date.now()){return{role:"custom",customType:ENVIRONMENT_CONTEXT_MESSAGE_TYPE,content:formatEnvironmentContext(context),display:!1,details:{cwd:context.cwd,currentDate:context.currentDate},timestamp}}function environmentContextMessageIfChanged(messages,current){let latest=latestEnvironmentContext(messages);if(!(latest?.cwd===current.cwd&&latest.currentDate===current.currentDate))return createEnvironmentContextMessage(current)}function contentBlocks(content){return typeof content=="string"?[{type:"text",text:content}]:content}function foldEnvironmentContextIntoNextUserMessage(messages,environmentMessages){let folded=[];for(let index=0;index<messages.length;index++){let message=messages[index],next=messages[index+1];if(environmentMessages.has(message)&&message.role==="user"&&next?.role==="user"&&!environmentMessages.has(next)){folded.push({...next,content:[...contentBlocks(message.content),...contentBlocks(next.content)]}),index++;continue}folded.push(message)}return folded}import{createHash}from"node:crypto";var IMAGE_ELISION_PLACEHOLDER="[Image elided: an older image was removed to keep the request within the provider's size limit. Re-read the source file if you need to view it again.]",IMAGE_ID_LENGTH=12,ID_SUFFIX=new RegExp(`^ \\(image ids?: ([0-9a-f]{${IMAGE_ID_LENGTH}}(?:, [0-9a-f]{${IMAGE_ID_LENGTH}})*)\\)$`);function imageContentId(data){return createHash("sha256").update(data).digest("hex").slice(0,IMAGE_ID_LENGTH)}function elisionPlaceholder(ids){let label=ids.length===1?"id":"ids";return{type:"text",text:`${IMAGE_ELISION_PLACEHOLDER} (image ${label}: ${ids.join(", ")})`}}function elidedImageIds(text){return text.startsWith(IMAGE_ELISION_PLACEHOLDER)?ID_SUFFIX.exec(text.slice(IMAGE_ELISION_PLACEHOLDER.length))?.[1]?.split(", "):void 0}function replaceElidedImages(content,isElided){let replaced=[],pending=[],flush=()=>{pending.length>0&&replaced.push(elisionPlaceholder(pending)),pending=[]};return content.forEach((block,blockIndex)=>{if(block.type==="image"&&isElided(blockIndex)){pending.push(imageContentId(block.data));return}flush(),replaced.push(block)}),flush(),replaced}var PROVIDER_IMAGE_REJECTION_PATTERN=/does not represent a valid image|image_parse_error|invalid_image|unsupported image|could not process image|unable to process input image|image_url'?\.?[^\n]*invalid base64|expected a base64-encoded data url|image was specified using the image\/[a-z]+ media type|unsupported media type for base64 image|invalid data url for image/i;function isProviderImageRejection(errorMessage){return errorMessage!==void 0&&PROVIDER_IMAGE_REJECTION_PATTERN.test(errorMessage)}function rejectedImagePlaceholder(source){return`[Image omitted: the provider rejected this image (${source}) as invalid, so it is no longer sent with the conversation.]`}function field(message,key){return key in message?message[key]:void 0}function contentBlocks2(message){let content=field(message,"content");return Array.isArray(content)?content:[]}function toolCallSource(block){let args=block.arguments;if(typeof args!="object"||args===null)return;let record=args;for(let key of["path","file_path","filePath"]){let value=record[key];if(typeof value=="string"&&value.trim().length>0)return value}}function imageSource(message,toolCallSources){if(message.role!=="toolResult")return"an attached image";let toolCallId=field(message,"toolCallId"),known=typeof toolCallId=="string"?toolCallSources.get(toolCallId):void 0;if(known)return known;let toolName=field(message,"toolName");return typeof toolName=="string"?`${toolName} tool result`:"a tool result"}function scanRejectedImages(messages){let toolCallSources=new Map,rejections=new Map,unconfirmed=[];return messages.forEach((message,messageIndex)=>{if(message.role==="assistant"){for(let block of contentBlocks2(message)){let source=block.type==="toolCall"?toolCallSource(block):void 0;source&&typeof block.id=="string"&&toolCallSources.set(block.id,source)}let stopReason=field(message,"stopReason"),errorMessage=field(message,"errorMessage");stopReason==="error"&&isProviderImageRejection(typeof errorMessage=="string"?errorMessage:void 0)?(unconfirmed.length>0&&rejections.set(messageIndex,unconfirmed),unconfirmed=[]):stopReason!=="error"&&stopReason!=="aborted"&&(unconfirmed=[]);return}message.role!=="user"&&message.role!=="toolResult"||contentBlocks2(message).forEach((block,blockIndex)=>{block.type==="image"&&unconfirmed.push({messageIndex,blockIndex,source:imageSource(message,toolCallSources)})})}),rejections}function rejectedImageSources(messages,failedTurn){let failedIndex=messages.lastIndexOf(failedTurn);return(scanRejectedImages(messages).get(failedIndex)??[]).map(image=>image.source)}function omitProviderRejectedImages(messages){let rejected=new Map;for(let images of scanRejectedImages(messages).values())for(let image of images){let blocks=rejected.get(image.messageIndex)??new Map;blocks.set(image.blockIndex,image.source),rejected.set(image.messageIndex,blocks)}return rejected.size===0?messages:messages.map((message,messageIndex)=>{let blocks=rejected.get(messageIndex);if(!blocks)return message;let content=contentBlocks2(message).map((block,blockIndex)=>{let source=blocks.get(blockIndex);return source===void 0?block:{type:"text",text:rejectedImagePlaceholder(source)}});return{...message,content}})}var COMPACTION_SUMMARY_PREFIX=`The conversation history before this point was compacted into the following summary:
|
|
4
4
|
|
|
5
5
|
<summary>
|
|
@@ -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{OPEN_AFTER_QUEUED_DEADLINE_MS,PROMPT_ACK_MAX_WAIT_MS,PROMPT_AFTER_QUEUED_DEADLINE_MS,PROMPT_COMPACTION_DEADLINE_MS,REQUEST_DEADLINE_MS,RpcRequestTimeoutError,armRequestDeadline,connectRpcClientSocket,openStalledMessage,promptStalledMessage,requestDeadlineMs}from"./chunk-H33A33M4.js";import{RPC_ERROR_SESSION_NOT_ATTACHED,RPC_ERROR_UNKNOWN_COMMAND,clientMessageIdentity}from"./chunk-SJI6UB23.js";import{DETACH_CONNECTION_CAPABILITY}from"./chunk-
|
|
2
|
+
import{OPEN_AFTER_QUEUED_DEADLINE_MS,PROMPT_ACK_MAX_WAIT_MS,PROMPT_AFTER_QUEUED_DEADLINE_MS,PROMPT_COMPACTION_DEADLINE_MS,REQUEST_DEADLINE_MS,RpcRequestTimeoutError,armRequestDeadline,connectRpcClientSocket,openStalledMessage,promptStalledMessage,requestDeadlineMs}from"./chunk-H33A33M4.js";import{RPC_ERROR_SESSION_NOT_ATTACHED,RPC_ERROR_UNKNOWN_COMMAND,clientMessageIdentity}from"./chunk-SJI6UB23.js";import{DETACH_CONNECTION_CAPABILITY}from"./chunk-622VYTRI.js";import{ORIGIN_HOST_INSTANCE_FIELD,originHostInstance}from"./chunk-DBQBJTMF.js";import{attachJsonlLineReader,serializeJsonLine}from"./chunk-SF4MQDKZ.js";import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{fuzzyFilter}from"./chunk-TMXRR3N7.js";import{RecoveryRepairController}from"./chunk-EYSV6A7S.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}
|
|
@@ -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{Text,truncateToWidth,visibleWidth}from"./chunk-TMXRR3N7.js";import{rotateLogIfNeeded}from"./chunk-LPYBKMPT.js";import{getShellConfig}from"./chunk-DSWDJ7HT.js";import{adoptedEngineTrust,engineTrustAction}from"./chunk-EVTTLPIY.js";import{redactSecrets}from"./chunk-BPNSOZ2C.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId,isStaleExtensionContextError}from"./chunk-IHES3JES.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-SODMQEHO.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,SecretOutputRedactor,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,encodeKeys,loadPty,safeRegExp}from"./chunk-AOTHPTMU.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)}
|
|
2
|
+
import{Text,truncateToWidth,visibleWidth}from"./chunk-TMXRR3N7.js";import{rotateLogIfNeeded}from"./chunk-LPYBKMPT.js";import{getShellConfig}from"./chunk-WQ4RBPMS.js";import{adoptedEngineTrust,engineTrustAction}from"./chunk-EVTTLPIY.js";import{redactSecrets}from"./chunk-BPNSOZ2C.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId,isStaleExtensionContextError}from"./chunk-IHES3JES.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-SODMQEHO.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,SecretOutputRedactor,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,encodeKeys,loadPty,safeRegExp}from"./chunk-AOTHPTMU.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
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
|
|
@@ -41,11 +41,11 @@ ${marker}`,body:truncation.content,marker,truncated:!0,truncation}}function spli
|
|
|
41
41
|
`)){if(afterNotice&&index===cursor)parts.push(modelOnlyText(notice));else if(index>cursor&&text[index-1]===`
|
|
42
42
|
`)parts.push({type:"text",text:text.slice(cursor,index-1)},modelOnlyText(notice));else continue;cursor=end<text.length?end+1:end,afterNotice=end<text.length}}return parts.length===0?[{type:"text",text}]:((cursor<text.length||text[text.length-1]===`
|
|
43
43
|
`)&&parts.push({type:"text",text:text.slice(cursor)}),parts)}function withTerminalContext(callback,retire){try{return callback()}catch(error){if(!isStaleExtensionContextError(error))throw error;retire();return}}async function spawnCommandSession(ctx,request){let shell=getShellConfig(ctx.shellPath),useStdin=shell.commandTransport==="stdin",args=useStdin?[...shell.args]:[...shell.args,request.command],launch=ctx.launchBarrier?.wrap(shell.shell,args)??{command:shell.shell,args},created=await ctx.manager.create(shell.shell,{command:launch.command,args:[...launch.args],cwd:request.cwd??ctx.cwd,env:{...ctx.getEnv(),...request.envOverrides},cols:request.cols,rows:request.rows,timeoutMs:request.timeoutMs,redactSecretsInOutput:ctx.redactSecretsInOutput});if(ctx.launchBarrier!==void 0){let session=created.runtime.session;try{await ctx.launchBarrier.release({pid:session.pid,write:data=>session.write(data),onExit:listener=>session.onExit(()=>listener(session.exitResult?.exitCode??null))})}catch(error){throw await ctx.manager.stop(created.id),error}}return useStdin&&created.runtime.session.write(`${request.command}
|
|
44
|
-
`),created}function describeExit(runtime){let exit=runtime.exitResult;return exit?exit.timedOut?"timed_out":exit.cancelled?"killed":exit.exitCode===0?"completed":exit.exitCode!==null?`exited_${exit.exitCode}`:exit.signal?`signal_${exit.signal}`:"exited":null}var NON_INTERACTIVE_MODES=new Set(["print","json"]),TERMINAL_NOTIFICATION_CUSTOM_TYPE="senpi-terminal:notification",NOTICE_TAIL_MAX_CHARS=2e3;function getTerminalNotificationDelivery(deps,customType=TERMINAL_NOTIFICATION_CUSTOM_TYPE){let mode=deps.getMode();if(mode==="off")return;let ctx=deps.getContext();if(!(!ctx||NON_INTERACTIVE_MODES.has(ctx.mode)||!ctx.model))return{send:(content,options)=>deps.sendMessage({customType,content,display:!1,...options?.details===void 0?{}:{details:options.details}},{triggerTurn:!0,deliverAs:mode==="wake"||options?.forceWake===!0?"steer":"followUp"})}}function buildNotice(id,runtime,trustText){let status=describeExit(runtime)??"exited",code=runtime.exitResult?.exitCode,codeText=code==null?"":` (exit code ${code})`,tail=sanitizeTerminalOutput(runtime.fullOutput()).trimEnd(),tailSection="";if(tail.length>0){let truncated=tail.length>NOTICE_TAIL_MAX_CHARS,shown=truncated?tail.slice(tail.length-NOTICE_TAIL_MAX_CHARS):tail,note=truncated?`
|
|
44
|
+
`),created}function describeExit(runtime){let exit=runtime.exitResult;return exit?exit.timedOut?"timed_out":exit.cancelled?"killed":exit.exitCode===0?"completed":exit.exitCode!==null?`exited_${exit.exitCode}`:exit.signal?`signal_${exit.signal}`:"exited":null}var NON_INTERACTIVE_MODES=new Set(["print","json"]),TERMINAL_NOTIFICATION_CUSTOM_TYPE="senpi-terminal:notification",NOTICE_TAIL_MAX_CHARS=2e3;function getTerminalNotificationDelivery(deps,customType=TERMINAL_NOTIFICATION_CUSTOM_TYPE){let mode=deps.getMode();if(mode==="off")return;let ctx=deps.getContext();if(!(!ctx||NON_INTERACTIVE_MODES.has(ctx.mode)||!ctx.model))return{send:(content,options)=>deps.sendMessage({customType,content,display:!1,...options?.details===void 0?{}:{details:options.details}},{triggerTurn:!0,deliverAs:mode==="wake"||options?.forceWake===!0?"steer":"followUp"})}}function minutes(count){return`${count} minute${count===1?"":"s"}`}function killCall(id){return`kill_bash({ bash_id: "${id}" })`}function describeBackgroundAge(event){let label=event.command===void 0||event.command===event.description?event.description:`${event.description}: ${event.command}`,session=`Background terminal session ${event.id} (${label})`;if(event.kind==="reaped")return`${session} was stopped automatically after ${minutes(event.autoReapMinutes??event.ageMinutes)} (auto-reap).`;if(event.kind==="reap_failed")return`${session} is still running: auto-reap at ${minutes(event.autoReapMinutes??event.ageMinutes)} failed (${event.reason??"unknown reason"}) and will not retry; stop it with ${killCall(event.id)} if it is no longer needed.`;let reap=event.autoReapMinutes===null?"Nothing stops it automatically":`Auto-reap stops it at ${minutes(event.autoReapMinutes)}`;return`${session} has been running for ${minutes(event.ageMinutes)}. ${reap}; stop it now with ${killCall(event.id)} if it is no longer needed.`}function buildNotice(id,runtime,trustText){let reaped=runtime.autoReapedAfterMinutes,reapText=reaped===void 0?"":` It was stopped automatically after ${minutes(reaped)} (auto-reap: the auto_reap_minutes parameter or the terminal.backgroundAutoReapMinutes setting).`,status=describeExit(runtime)??"exited",code=runtime.exitResult?.exitCode,codeText=code==null?"":` (exit code ${code})`,tail=sanitizeTerminalOutput(runtime.fullOutput()).trimEnd(),tailSection="";if(tail.length>0){let truncated=tail.length>NOTICE_TAIL_MAX_CHARS,shown=truncated?tail.slice(tail.length-NOTICE_TAIL_MAX_CHARS):tail,note=truncated?`
|
|
45
45
|
[Final output truncated to the last ${NOTICE_TAIL_MAX_CHARS} chars; the full history is still peekable.]`:"";tailSection=`
|
|
46
46
|
Final output:
|
|
47
47
|
${shown}${note}`}let trustSection=trustText===void 0?"":`
|
|
48
|
-
${trustText}`;return`<system-reminder>Background terminal session ${id} finished: ${status}${codeText}.${tailSection}${trustSection}</system-reminder>`}var TerminalNotifier=class{constructor(deps){this.notified=new Set,this.retired=!1,this.deps=deps}notifyCompletion(id,runtime){this.retired||this.notified.has(id)||withTerminalContext(()=>this.deliverCompletion(id,runtime),()=>{this.retired=!0,this.notified.clear()})}deliverCompletion(id,runtime){let delivery=getTerminalNotificationDelivery(this.deps);if(!delivery)return;this.notified.add(id);let annotation=annotateShellTrust({exitCode:runtime.exitResult?.exitCode??null,output:runtime.fullOutput()});delivery.send(buildNotice(id,runtime,annotation?.text),annotation===void 0?void 0:{details:{trust:annotation.trust}})}};function stallThresholdMs(timeoutSeconds){return typeof timeoutSeconds!="number"||!Number.isFinite(timeoutSeconds)||timeoutSeconds<=0?3e4:Math.max(1,Math.min(3e4,Math.trunc(timeoutSeconds*1e3)))}function queueEntryLabel(event){let toolCallId=event.toolCallId;return typeof toolCallId=="string"?`${event.type}:${toolCallId}`:event.type}function watchForStall(thresholdMs,onStall){let startedAt=Date.now(),timer=setTimeout(()=>onStall(Date.now()-startedAt),thresholdMs);return timer.unref?.(),{stop:()=>clearTimeout(timer)}}var PendingQueueLedger=class{constructor(){this.nextId=0,this.entries=new Map}track(label,run){let id=this.nextId++;this.entries.set(id,{label,enqueuedAt:Date.now()});let release=()=>{this.entries.delete(id)};return(...args)=>{let result;try{result=run(...args)}catch(error){throw release(),error}return result instanceof Promise?result.then(release,release):release(),result}}snapshot(){let head=this.entries.values().next().value;return head===void 0?{queueDepth:0}:{queueDepth:this.entries.size,queueHead:head.label,ageMs:Date.now()-head.enqueuedAt}}};function resolveTerminalId(manager,id){return manager.resolveId?.(id)??id}function textResult(text,extra){return{content:[{type:"text",text}],details:extra?.details,isError:extra?.isError}}function errorResult(text){return{content:[{type:"text",text}],details:void 0,isError:!0}}function noticedResult(text,notices,extra){return{content:splitModelOnlyNotices(text,notices),details:extra?.details,isError:extra?.isError}}function createForegroundDetachGate(options){let cancelled=!1,committed=!1,timer,resolveDetached,detached=new Promise(resolve=>{resolveDetached=resolve}),clearDeadline=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)},linearize=()=>{if(cancelled||committed||options.runtime.exited||options.signal?.aborted)return;let exitedAtGate=!1,unsubscribeExit=options.runtime.session.onExit(()=>{committed||(exitedAtGate=!0)});if(cancelled||options.runtime.exited||exitedAtGate||options.signal?.aborted){unsubscribeExit();return}committed=!0,options.removeAbortListener(),unsubscribeExit(),resolveDetached()};return timer=setTimeout(()=>queueMicrotask(linearize),options.delayMs),{detached,cancel(){cancelled=!0,clearDeadline()}}}function resolveForegroundWindowSeconds(env){let parsed=Number.parseFloat(env.PI_BASH_FOREGROUND_SECONDS??"");return!Number.isFinite(parsed)||parsed<=0?60:parsed}var SHELL_WRAPPER=/^(?:env\s+(?:[\w.]+=[^\s]*\s+)*)?(?:\/(?:usr\/)?bin\/)?(?:ba|z|da|k)?sh\s+-[a-z]*c\s+/i,POWER_MANAGEMENT=/\b(?:pmset|systemsetup|caffeinate|displaysleep|disksleep)\b/,SLEEP_CALL=/(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+(\d+(?:\.\d+)?)/g,PURE=/^sleep\s+\d+(?:\.\d+)?$/,LEADING=/^\(?\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*(?:[;&|]|$)/,LOOP=/\b(?:while|until|for)\b[\s\S]*?(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+\d/,TRAILING=/[;&|]\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*\)?\s*$/;function unwrap(command){let current=command.trim();for(let depth=0;depth<3;depth+=1){let stripped=current.replace(SHELL_WRAPPER,"");if(stripped===current)break;current=stripped.trim();let quote=current[0];(quote==="'"||quote==='"')&¤t.endsWith(quote)&¤t.length>1&&(current=current.slice(1,-1).trim())}return current}function longestSleepSeconds(command){SLEEP_CALL.lastIndex=0;let longest;for(let match of command.matchAll(SLEEP_CALL)){let seconds=Number.parseFloat(match[1]??"");Number.isFinite(seconds)&&(longest===void 0||seconds>longest)&&(longest=seconds)}return longest}function classifySleepWait(command){if(POWER_MANAGEMENT.test(command))return;let unwrapped=unwrap(command),seconds=longestSleepSeconds(unwrapped);if(seconds!==void 0){if(LOOP.test(unwrapped))return seconds>=2?{kind:"sleep-wait",rule:"R3",seconds}:void 0;if(!(seconds<10)){if(PURE.test(unwrapped))return{kind:"sleep-wait",rule:"R1",seconds};if(LEADING.test(unwrapped))return{kind:"sleep-wait",rule:"R2",seconds};if(TRAILING.test(unwrapped))return{kind:"sleep-wait",rule:"R4",seconds}}}}var ptyBashSchema=typebox_exports.Object({command:typebox_exports.String({description:"Shell command to execute in a PTY-backed session."}),timeout:typebox_exports.Optional(typebox_exports.Number({description:"Process kill deadline in seconds (default 1800). Foreground blocking stops at the ~60s window: a command still running then auto-detaches to a live background session instead of being killed. Ignored for run_in_background sessions (they live until exit or kill_bash)."})),description:typebox_exports.Optional(typebox_exports.String({description:"Short human-readable label for this command."})),run_in_background:typebox_exports.Optional(typebox_exports.Boolean({description:"Run as a persistent background session: returns a bash_id immediately (read with bash_output, steer with bash_input, stop with kill_bash). A plain & job dies with the call's PTY hangup (native backend), and nohup at best leaves an untracked orphan (no bash_id, no log) that the call's timeout still group-kills. This flag is the only reliable way a job outlives the call."})),cols:typebox_exports.Optional(typebox_exports.Number({description:"PTY width in columns (default 120)."})),rows:typebox_exports.Optional(typebox_exports.Number({description:"PTY height in rows (default 40)."}))});function resolveDimension(value,fallback){return value===void 0||!Number.isFinite(value)||value<1?fallback:Math.trunc(value)}function delay(ms){return new Promise(resolve=>setTimeout(resolve,ms))}var MAX_TIMEOUT_MS=2147483647,BASH_UPDATE_THROTTLE_MS=100;function createThrottledEmitter(emit,throttleMs=BASH_UPDATE_THROTTLE_MS){let timer,dirty=!1,lastEmissionAt,emitIfDirty=()=>{dirty&&(dirty=!1,lastEmissionAt=Date.now(),emit())},clearTimer=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)};return{schedule(){if(dirty=!0,timer!==void 0)return;let elapsed=lastEmissionAt===void 0?throttleMs:Date.now()-lastEmissionAt;if(elapsed>=throttleMs){emitIfDirty();return}timer=setTimeout(()=>{timer=void 0,emitIfDirty()},throttleMs-elapsed)},flush(){clearTimer(),emitIfDirty()},dispose(){clearTimer(),dirty=!1,lastEmissionAt=void 0}}}var defaultSessionLogger;async function spawnReportingStall(ctx,request,toolCallId,execCtx){let thresholdMs=stallThresholdMs(request.timeoutMs===void 0?void 0:request.timeoutMs/1e3),watch2=watchForStall(thresholdMs,elapsedMs=>{let logger=ctx.sessionLogger??(defaultSessionLogger??=createSessionLogger(getAgentDir())),sessionId=(execCtx??ctx.getSessionContext?.())?.sessionManager?.getSessionId();logger.warn("bash_spawn_stalled",{toolCallId,toolName:TERMINAL_BASH_TOOL,...sessionId===void 0?{}:{sessionId},thresholdMs,elapsedMs})});try{return await spawnCommandSession(sessionSpawnContext(ctx),request)}finally{watch2.stop()}}function sessionSpawnContext(ctx){return{...ctx,getEnv:()=>({...ctx.getEnv(),PI_SESSION_CWD:void 0,PI_GOAL_STORE_FILE:void 0,OMO_BROWSER_ENGINE:void 0})}}function sessionEnvOverrides(ctx,execCtx){let session=execCtx??ctx.getSessionContext?.();if(!session?.sessionManager)return{};let env={...session.sessionEnv};env.PI_SESSION_ID=session.sessionManager.getSessionId(),session.cwd&&(env.PI_SESSION_CWD=session.cwd),session.goalStoreFile&&(env.PI_GOAL_STORE_FILE=session.goalStoreFile);let sessionFile=session.sessionManager.getSessionFile();return sessionFile&&(env.PI_SESSION_FILE=sessionFile),session.model&&(env.PI_PROVIDER=session.model.provider,env.PI_MODEL=session.model.id),session.thinkingLevel&&(env.PI_REASONING_LEVEL=session.thinkingLevel),session.browserEngine&&(env.OMO_BROWSER_ENGINE=session.browserEngine),env}function raceExitWithKillGrace(runtime,signal,timeoutMs){return new Promise((resolve,reject)=>{let settled=!1,abortGraceTimer,timeoutGraceTimer,armAbortGrace,settle=finish=>{settled||(settled=!0,abortGraceTimer&&clearTimeout(abortGraceTimer),timeoutGraceTimer&&clearTimeout(timeoutGraceTimer),signal&&armAbortGrace&&signal.removeEventListener("abort",armAbortGrace),finish())};if(runtime.session.waitExit().then(()=>settle(()=>resolve("exited")),error=>settle(()=>reject(error instanceof Error?error:new Error(String(error))))),timeoutMs!==void 0){let timeoutGraceDeadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;timeoutGraceDeadlineMs<=MAX_TIMEOUT_MS&&(timeoutGraceTimer=setTimeout(()=>settle(()=>resolve("timeout_grace")),timeoutGraceDeadlineMs))}signal&&(armAbortGrace=()=>{abortGraceTimer??=setTimeout(()=>settle(()=>resolve("abort_grace")),KILLED_SESSION_EXIT_GRACE_MS)},signal.aborted?armAbortGrace():signal.addEventListener("abort",armAbortGrace,{once:!0}))})}function resolveAutoDetachDelayMs(ctx,input,sleepWait){if(ctx.timeoutAction==="kill")return;let windowSeconds=sleepWait?Math.min(5,resolveForegroundWindowSeconds(process.env)):resolveForegroundWindowSeconds(process.env);if(!((input.timeout!==void 0&&Number.isFinite(input.timeout)?input.timeout:1/0)<=windowSeconds))return Math.max(0,Math.trunc(windowSeconds*1e3))}function scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt){if(timeoutMs===void 0)return;let deadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;if(!Number.isFinite(deadlineMs)||deadlineMs>MAX_TIMEOUT_MS||runtime.exited)return;let remainingMs=Math.max(0,deadlineMs-(Date.now()-startedAt)),timer,unsubscribeExit,clearSweep=()=>{timer!==void 0&&clearTimeout(timer),timer=void 0,unsubscribeExit?.(),unsubscribeExit=void 0};if(unsubscribeExit=runtime.session.onExit(clearSweep),runtime.exited){clearSweep();return}timer=setTimeout(()=>{clearSweep(),runtime.exited||ctx.manager.stop(id).catch(()=>{})},remainingMs)}async function runForeground(ctx,input,cols,rows,signal,cwd,onUpdate,toolCallId,execCtx){if(signal?.aborted)return errorResult("Command aborted");let timeoutMs=input.timeout!==void 0?Math.trunc(input.timeout*1e3):void 0,{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,timeoutMs,cwd,envOverrides:{...sessionEnvOverrides(ctx,execCtx),...FOREGROUND_ENV_OVERRIDES}},toolCallId,execCtx),startedAt=Date.now(),activity=`running ${input.command.slice(0,80)}`,updateEmitter=onUpdate?createThrottledEmitter(()=>{let text=formatTerminalToolOutput(runtime.fullOutput()).body.slice(-2e3);onUpdate?.({content:[{type:"text",text}],details:{progress:{activity,startedAt}}})}):void 0;onUpdate?.({content:[],details:void 0});let unsubscribeOutput=onUpdate?runtime.onOutput(()=>updateEmitter?.schedule()):void 0,sleepWait=classifySleepWait(input.command),detachDelayMs=resolveAutoDetachDelayMs(ctx,input,sleepWait),outcome;if(detachDelayMs===void 0){let onAbort=()=>runtime.session.kill("SIGKILL");signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));try{outcome=await raceExitWithKillGrace(runtime,signal,timeoutMs)}finally{signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}else{let abortGate=new AbortController,onAbort=()=>{runtime.session.kill("SIGKILL"),abortGate.abort()};signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));let detachGate=createForegroundDetachGate({runtime,signal,delayMs:detachDelayMs,removeAbortListener:()=>signal?.removeEventListener("abort",onAbort)});try{outcome=await Promise.race([raceExitWithKillGrace(runtime,abortGate.signal,timeoutMs),detachGate.detached.then(()=>"detached")])}finally{detachGate.cancel(),signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}if(outcome==="detached"){scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt),ctx.onBackgroundStart?.(id,input.description??input.command,startedAt,input.command),ctx.onBackgroundExit&&runtime.session.onExit(()=>ctx.onBackgroundExit?.(id,runtime));let delta=runtime.readDelta(),partialOutput=formatTerminalToolOutput(delta.text).text||"(no output yet)",timeoutNote=input.timeout!==void 0&&Number.isFinite(input.timeout)?`not killed; the original ${input.timeout}s timeout still applies`:"not killed; it will run until exit or kill_bash",guidance=sleepWait?`This command is a wait (${sleepWait.seconds}s sleep), so it detached immediately; the wait continues in the background. Do nothing and end your turn: completion will be reported automatically with exit status and output tail. Do NOT poll bash_output({ bash_id: "${id}" }) for it. When you are waiting for a pattern in a command's output, launch it with monitor({ command, filter }) instead so matching lines arrive as events. Use kill_bash({ bash_id: "${id}" }) to stop this session.`:`Continue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`;return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).
|
|
48
|
+
${trustText}`;return`<system-reminder>Background terminal session ${id} finished: ${status}${codeText}.${reapText}${tailSection}${trustSection}</system-reminder>`}var TerminalNotifier=class{constructor(deps){this.notified=new Set,this.retired=!1,this.deps=deps}notifyCompletion(id,runtime){this.retired||this.notified.has(id)||withTerminalContext(()=>this.deliverCompletion(id,runtime),()=>this.retire())}notifyAge(event){this.retired||this.notified.has(event.id)||withTerminalContext(()=>getTerminalNotificationDelivery(this.deps)?.send(`<system-reminder>${describeBackgroundAge(event)}</system-reminder>`,{details:{backgroundAge:event}}),()=>this.retire())}retire(){this.retired=!0,this.notified.clear()}deliverCompletion(id,runtime){let delivery=getTerminalNotificationDelivery(this.deps);if(!delivery)return;this.notified.add(id);let annotation=annotateShellTrust({exitCode:runtime.exitResult?.exitCode??null,output:runtime.fullOutput()});delivery.send(buildNotice(id,runtime,annotation?.text),annotation===void 0?void 0:{details:{trust:annotation.trust}})}};function stallThresholdMs(timeoutSeconds){return typeof timeoutSeconds!="number"||!Number.isFinite(timeoutSeconds)||timeoutSeconds<=0?3e4:Math.max(1,Math.min(3e4,Math.trunc(timeoutSeconds*1e3)))}function queueEntryLabel(event){let toolCallId=event.toolCallId;return typeof toolCallId=="string"?`${event.type}:${toolCallId}`:event.type}function watchForStall(thresholdMs,onStall){let startedAt=Date.now(),timer=setTimeout(()=>onStall(Date.now()-startedAt),thresholdMs);return timer.unref?.(),{stop:()=>clearTimeout(timer)}}var PendingQueueLedger=class{constructor(){this.nextId=0,this.entries=new Map}track(label,run){let id=this.nextId++;this.entries.set(id,{label,enqueuedAt:Date.now()});let release=()=>{this.entries.delete(id)};return(...args)=>{let result;try{result=run(...args)}catch(error){throw release(),error}return result instanceof Promise?result.then(release,release):release(),result}}snapshot(){let head=this.entries.values().next().value;return head===void 0?{queueDepth:0}:{queueDepth:this.entries.size,queueHead:head.label,ageMs:Date.now()-head.enqueuedAt}}};function resolveTerminalId(manager,id){return manager.resolveId?.(id)??id}function textResult(text,extra){return{content:[{type:"text",text}],details:extra?.details,isError:extra?.isError}}function errorResult(text){return{content:[{type:"text",text}],details:void 0,isError:!0}}function noticedResult(text,notices,extra){return{content:splitModelOnlyNotices(text,notices),details:extra?.details,isError:extra?.isError}}var MINUTE_MS=6e4,MAX_TIMER_MS=2147483647;function resolveAutoReapMinutes(requested,configured){let value=requested??configured;if(value===void 0||!Number.isFinite(value))return;let minutes2=Math.trunc(value);return minutes2>=1?minutes2:void 0}function backgroundStart(input,configuredMinutes,startedAtMs){return{description:input.description??input.command,command:input.command,startedAtMs,autoReapMinutes:resolveAutoReapMinutes(input.auto_reap_minutes,configuredMinutes)}}function reapedView(runtime,minutes2){return{exitResult:runtime.exitResult,autoReapedAfterMinutes:minutes2,fullOutput:()=>runtime.fullOutput()}}function trackBackgroundSession(ctx,id,runtime,start){ctx.onBackgroundStart?.(id,start.description,start.startedAtMs,start.command,start.autoReapMinutes);let minutes2=start.autoReapMinutes,reapedAfterMinutes,reaping,timer,reap=async age=>{let failure=await ctx.manager.stop(id).then(stopped=>stopped?runtime.exited?void 0:"the session was still running after the stop (TERM, then KILL)":`the terminal manager has no session ${id} to stop`,error=>error instanceof Error?error.message:String(error));if(failure===void 0){reapedAfterMinutes=age;return}(ctx.sessionLogger??createSessionLogger(getAgentDir())).warn("bash_auto_reap_failed",{bash_id:id,autoReapMinutes:age,error:failure}),runtime.exited||ctx.onBackgroundReapFailed?.(id,age,failure)},arm=deadlineMs=>{timer=setTimeout(()=>{if(timer=void 0,!(runtime.exited||minutes2===void 0)){if(Date.now()<deadlineMs){arm(deadlineMs);return}reaping=Promise.resolve().then(()=>reap(minutes2))}},Math.min(Math.max(0,deadlineMs-Date.now()),MAX_TIMER_MS)),timer.unref?.()};minutes2!==void 0&&!runtime.exited&&arm(start.startedAtMs+minutes2*MINUTE_MS),!(minutes2===void 0&&!ctx.onBackgroundExit)&&runtime.session.onExit(()=>{timer!==void 0&&clearTimeout(timer),timer=void 0;let report=()=>ctx.onBackgroundExit?.(id,reapedAfterMinutes===void 0?runtime:reapedView(runtime,reapedAfterMinutes));reaping===void 0?report():reaping.then(report)})}function createForegroundDetachGate(options){let cancelled=!1,committed=!1,timer,resolveDetached,detached=new Promise(resolve=>{resolveDetached=resolve}),clearDeadline=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)},linearize=()=>{if(cancelled||committed||options.runtime.exited||options.signal?.aborted)return;let exitedAtGate=!1,unsubscribeExit=options.runtime.session.onExit(()=>{committed||(exitedAtGate=!0)});if(cancelled||options.runtime.exited||exitedAtGate||options.signal?.aborted){unsubscribeExit();return}committed=!0,options.removeAbortListener(),unsubscribeExit(),resolveDetached()};return timer=setTimeout(()=>queueMicrotask(linearize),options.delayMs),{detached,cancel(){cancelled=!0,clearDeadline()}}}function resolveForegroundWindowSeconds(env){let parsed=Number.parseFloat(env.PI_BASH_FOREGROUND_SECONDS??"");return!Number.isFinite(parsed)||parsed<=0?60:parsed}var SHELL_WRAPPER=/^(?:env\s+(?:[\w.]+=[^\s]*\s+)*)?(?:\/(?:usr\/)?bin\/)?(?:ba|z|da|k)?sh\s+-[a-z]*c\s+/i,POWER_MANAGEMENT=/\b(?:pmset|systemsetup|caffeinate|displaysleep|disksleep)\b/,SLEEP_CALL=/(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+(\d+(?:\.\d+)?)/g,PURE=/^sleep\s+\d+(?:\.\d+)?$/,LEADING=/^\(?\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*(?:[;&|]|$)/,LOOP=/\b(?:while|until|for)\b[\s\S]*?(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+\d/,TRAILING=/[;&|]\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*\)?\s*$/;function unwrap(command){let current=command.trim();for(let depth=0;depth<3;depth+=1){let stripped=current.replace(SHELL_WRAPPER,"");if(stripped===current)break;current=stripped.trim();let quote=current[0];(quote==="'"||quote==='"')&¤t.endsWith(quote)&¤t.length>1&&(current=current.slice(1,-1).trim())}return current}function longestSleepSeconds(command){SLEEP_CALL.lastIndex=0;let longest;for(let match of command.matchAll(SLEEP_CALL)){let seconds=Number.parseFloat(match[1]??"");Number.isFinite(seconds)&&(longest===void 0||seconds>longest)&&(longest=seconds)}return longest}function classifySleepWait(command){if(POWER_MANAGEMENT.test(command))return;let unwrapped=unwrap(command),seconds=longestSleepSeconds(unwrapped);if(seconds!==void 0){if(LOOP.test(unwrapped))return seconds>=2?{kind:"sleep-wait",rule:"R3",seconds}:void 0;if(!(seconds<10)){if(PURE.test(unwrapped))return{kind:"sleep-wait",rule:"R1",seconds};if(LEADING.test(unwrapped))return{kind:"sleep-wait",rule:"R2",seconds};if(TRAILING.test(unwrapped))return{kind:"sleep-wait",rule:"R4",seconds}}}}var ptyBashSchema=typebox_exports.Object({command:typebox_exports.String({description:"Shell command to execute in a PTY-backed session."}),timeout:typebox_exports.Optional(typebox_exports.Number({description:"Process kill deadline in seconds (default 1800). Foreground blocking stops at the ~60s window: a command still running then auto-detaches to a live background session instead of being killed. Ignored for run_in_background sessions (they live until exit or kill_bash)."})),description:typebox_exports.Optional(typebox_exports.String({description:"Short human-readable label for this command."})),run_in_background:typebox_exports.Optional(typebox_exports.Boolean({description:"Run as a persistent background session: returns a bash_id immediately (read with bash_output, steer with bash_input, stop with kill_bash). A plain & job dies with the call's PTY hangup (native backend), and nohup at best leaves an untracked orphan (no bash_id, no log) that the call's timeout still group-kills. This flag is the only reliable way a job outlives the call."})),auto_reap_minutes:typebox_exports.Optional(typebox_exports.Number({description:"Background sessions only: stop this session (TERM, then KILL to its process group) once it has run this many minutes. Defaults to the terminal.backgroundAutoReapMinutes setting, which is off; 0 turns it off for this call."})),cols:typebox_exports.Optional(typebox_exports.Number({description:"PTY width in columns (default 120)."})),rows:typebox_exports.Optional(typebox_exports.Number({description:"PTY height in rows (default 40)."}))});function resolveDimension(value,fallback){return value===void 0||!Number.isFinite(value)||value<1?fallback:Math.trunc(value)}function delay(ms){return new Promise(resolve=>setTimeout(resolve,ms))}var MAX_TIMEOUT_MS=2147483647,BASH_UPDATE_THROTTLE_MS=100;function createThrottledEmitter(emit,throttleMs=BASH_UPDATE_THROTTLE_MS){let timer,dirty=!1,lastEmissionAt,emitIfDirty=()=>{dirty&&(dirty=!1,lastEmissionAt=Date.now(),emit())},clearTimer=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)};return{schedule(){if(dirty=!0,timer!==void 0)return;let elapsed=lastEmissionAt===void 0?throttleMs:Date.now()-lastEmissionAt;if(elapsed>=throttleMs){emitIfDirty();return}timer=setTimeout(()=>{timer=void 0,emitIfDirty()},throttleMs-elapsed)},flush(){clearTimer(),emitIfDirty()},dispose(){clearTimer(),dirty=!1,lastEmissionAt=void 0}}}var defaultSessionLogger;async function spawnReportingStall(ctx,request,toolCallId,execCtx){let thresholdMs=stallThresholdMs(request.timeoutMs===void 0?void 0:request.timeoutMs/1e3),watch2=watchForStall(thresholdMs,elapsedMs=>{let logger=ctx.sessionLogger??(defaultSessionLogger??=createSessionLogger(getAgentDir())),sessionId=(execCtx??ctx.getSessionContext?.())?.sessionManager?.getSessionId();logger.warn("bash_spawn_stalled",{toolCallId,toolName:TERMINAL_BASH_TOOL,...sessionId===void 0?{}:{sessionId},thresholdMs,elapsedMs})});try{return await spawnCommandSession(sessionSpawnContext(ctx),request)}finally{watch2.stop()}}function sessionSpawnContext(ctx){return{...ctx,getEnv:()=>({...ctx.getEnv(),PI_SESSION_CWD:void 0,PI_GOAL_STORE_FILE:void 0,OMO_BROWSER_ENGINE:void 0})}}function sessionEnvOverrides(ctx,execCtx){let session=execCtx??ctx.getSessionContext?.();if(!session?.sessionManager)return{};let env={...session.sessionEnv};env.PI_SESSION_ID=session.sessionManager.getSessionId(),session.cwd&&(env.PI_SESSION_CWD=session.cwd),session.goalStoreFile&&(env.PI_GOAL_STORE_FILE=session.goalStoreFile);let sessionFile=session.sessionManager.getSessionFile();return sessionFile&&(env.PI_SESSION_FILE=sessionFile),session.model&&(env.PI_PROVIDER=session.model.provider,env.PI_MODEL=session.model.id),session.thinkingLevel&&(env.PI_REASONING_LEVEL=session.thinkingLevel),session.browserEngine&&(env.OMO_BROWSER_ENGINE=session.browserEngine),env}function raceExitWithKillGrace(runtime,signal,timeoutMs){return new Promise((resolve,reject)=>{let settled=!1,abortGraceTimer,timeoutGraceTimer,armAbortGrace,settle=finish=>{settled||(settled=!0,abortGraceTimer&&clearTimeout(abortGraceTimer),timeoutGraceTimer&&clearTimeout(timeoutGraceTimer),signal&&armAbortGrace&&signal.removeEventListener("abort",armAbortGrace),finish())};if(runtime.session.waitExit().then(()=>settle(()=>resolve("exited")),error=>settle(()=>reject(error instanceof Error?error:new Error(String(error))))),timeoutMs!==void 0){let timeoutGraceDeadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;timeoutGraceDeadlineMs<=MAX_TIMEOUT_MS&&(timeoutGraceTimer=setTimeout(()=>settle(()=>resolve("timeout_grace")),timeoutGraceDeadlineMs))}signal&&(armAbortGrace=()=>{abortGraceTimer??=setTimeout(()=>settle(()=>resolve("abort_grace")),KILLED_SESSION_EXIT_GRACE_MS)},signal.aborted?armAbortGrace():signal.addEventListener("abort",armAbortGrace,{once:!0}))})}function resolveAutoDetachDelayMs(ctx,input,sleepWait){if(ctx.timeoutAction==="kill")return;let windowSeconds=sleepWait?Math.min(5,resolveForegroundWindowSeconds(process.env)):resolveForegroundWindowSeconds(process.env);if(!((input.timeout!==void 0&&Number.isFinite(input.timeout)?input.timeout:1/0)<=windowSeconds))return Math.max(0,Math.trunc(windowSeconds*1e3))}function scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt){if(timeoutMs===void 0)return;let deadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;if(!Number.isFinite(deadlineMs)||deadlineMs>MAX_TIMEOUT_MS||runtime.exited)return;let remainingMs=Math.max(0,deadlineMs-(Date.now()-startedAt)),timer,unsubscribeExit,clearSweep=()=>{timer!==void 0&&clearTimeout(timer),timer=void 0,unsubscribeExit?.(),unsubscribeExit=void 0};if(unsubscribeExit=runtime.session.onExit(clearSweep),runtime.exited){clearSweep();return}timer=setTimeout(()=>{clearSweep(),runtime.exited||ctx.manager.stop(id).catch(()=>{})},remainingMs)}async function runForeground(ctx,input,cols,rows,signal,cwd,onUpdate,toolCallId,execCtx){if(signal?.aborted)return errorResult("Command aborted");let timeoutMs=input.timeout!==void 0?Math.trunc(input.timeout*1e3):void 0,{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,timeoutMs,cwd,envOverrides:{...sessionEnvOverrides(ctx,execCtx),...FOREGROUND_ENV_OVERRIDES}},toolCallId,execCtx),startedAt=Date.now(),activity=`running ${input.command.slice(0,80)}`,updateEmitter=onUpdate?createThrottledEmitter(()=>{let text=formatTerminalToolOutput(runtime.fullOutput()).body.slice(-2e3);onUpdate?.({content:[{type:"text",text}],details:{progress:{activity,startedAt}}})}):void 0;onUpdate?.({content:[],details:void 0});let unsubscribeOutput=onUpdate?runtime.onOutput(()=>updateEmitter?.schedule()):void 0,sleepWait=classifySleepWait(input.command),detachDelayMs=resolveAutoDetachDelayMs(ctx,input,sleepWait),outcome;if(detachDelayMs===void 0){let onAbort=()=>runtime.session.kill("SIGKILL");signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));try{outcome=await raceExitWithKillGrace(runtime,signal,timeoutMs)}finally{signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}else{let abortGate=new AbortController,onAbort=()=>{runtime.session.kill("SIGKILL"),abortGate.abort()};signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));let detachGate=createForegroundDetachGate({runtime,signal,delayMs:detachDelayMs,removeAbortListener:()=>signal?.removeEventListener("abort",onAbort)});try{outcome=await Promise.race([raceExitWithKillGrace(runtime,abortGate.signal,timeoutMs),detachGate.detached.then(()=>"detached")])}finally{detachGate.cancel(),signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}if(outcome==="detached"){scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt),trackBackgroundSession(ctx,id,runtime,backgroundStart(input,ctx.backgroundAutoReapMinutes,startedAt));let delta=runtime.readDelta(),partialOutput=formatTerminalToolOutput(delta.text).text||"(no output yet)",timeoutNote=input.timeout!==void 0&&Number.isFinite(input.timeout)?`not killed; the original ${input.timeout}s timeout still applies`:"not killed; it will run until exit or kill_bash",guidance=sleepWait?`This command is a wait (${sleepWait.seconds}s sleep), so it detached immediately; the wait continues in the background. Do nothing and end your turn: completion will be reported automatically with exit status and output tail. Do NOT poll bash_output({ bash_id: "${id}" }) for it. When you are waiting for a pattern in a command's output, launch it with monitor({ command, filter }) instead so matching lines arrive as events. Use kill_bash({ bash_id: "${id}" }) to stop this session.`:`Continue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`;return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).
|
|
49
49
|
|
|
50
50
|
Partial output:
|
|
51
51
|
${partialOutput}
|
|
@@ -58,7 +58,7 @@ ${guidance}`,{details:{bash_id:id,background:!0,auto_detached:!0,...sleepWait?{s
|
|
|
58
58
|
|
|
59
59
|
`:""}Command exited with code ${exit.exitCode}`,annotation=annotateShellTrust({exitCode:exit.exitCode,output:runtime.fullOutput()});return annotation===void 0?errorResult(text):textResult(annotation.text===void 0?text:`${text}
|
|
60
60
|
|
|
61
|
-
${annotation.text}`,{details:{trust:annotation.trust},isError:!0})}return noticedResult(output||"(no output)",[formatted.marker],{details:{status,...formatted.truncated?{truncation:formatted.truncation}:{}}})}async function runBackground(ctx,input,cols,rows,cwd,toolCallId,execCtx){let{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,cwd,envOverrides:sessionEnvOverrides(ctx,execCtx)},toolCallId,execCtx);ctx
|
|
61
|
+
${annotation.text}`,{details:{trust:annotation.trust},isError:!0})}return noticedResult(output||"(no output)",[formatted.marker],{details:{status,...formatted.truncated?{truncation:formatted.truncation}:{}}})}async function runBackground(ctx,input,cols,rows,cwd,toolCallId,execCtx){let{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,cwd,envOverrides:sessionEnvOverrides(ctx,execCtx)},toolCallId,execCtx);trackBackgroundSession(ctx,id,runtime,backgroundStart(input,ctx.backgroundAutoReapMinutes,Date.now())),await Promise.race([delay(BACKGROUND_START_GRACE_MS),runtime.session.waitExit()]);let early=formatTerminalToolOutput(runtime.readDelta().text).text,header=`Command running in background with ID: ${id}`,backendNote=runtime.backend==="pipe-fallback"?`
|
|
62
62
|
(native PTY unavailable: running via pipe fallback; bash_input/bash_resize are limited.)`:"",earlyBlock=early?`
|
|
63
63
|
|
|
64
64
|
${early}`:"";return textResult(`${header}${backendNote}${earlyBlock}`,{details:{bash_id:id,background:!0}})}function createPtyBashTool(ctx){return{name:TERMINAL_BASH_TOOL,exposure:"eval",label:"bash",description:"Execute a shell command in a persistent PTY-backed session. Set run_in_background:true for long-lived or interactive sessions; steer them with bash_input, snapshot with bash_output, tear down with kill_bash. To wait on observable state (a build finishing, a server coming up, a log line), never run sleep or poll loops: subscribe with the monitor tool instead. Foreground blocking stops at the ~60s window and a still-running command auto-detaches to a live background session; `timeout` is the process kill deadline in seconds.",promptSnippet:"Run shell commands; run_in_background:true for long-lived/interactive PTY sessions",promptGuidelines:["PI_* env vars = current model + session details."],fullPromptGuidelines:["You can inspect PI_* environment variables for current model and session details."],parameters:ptyBashSchema,async execute(toolCallId,input,signal,onUpdate,execCtx){let cols=resolveDimension(input.cols,ctx.defaultCols||DEFAULT_COLS),rows=resolveDimension(input.rows,ctx.defaultRows||DEFAULT_ROWS),cwd=execCtx?.cwd;return input.run_in_background?runBackground(ctx,input,cols,rows,cwd,toolCallId,execCtx):runForeground(ctx,input,cols,rows,signal,cwd,onUpdate,toolCallId,execCtx)}}}var bashInputSchema=typebox_exports.Object({bash_id:typebox_exports.String({description:"Session id returned by a run_in_background bash call."}),input:typebox_exports.Optional(typebox_exports.String({description:"Literal text to write to the session's stdin."})),keys:typebox_exports.Optional(typebox_exports.Array(typebox_exports.String(),{description:"Named keys to send, e.g. ['ctrl+c'], ['enter'], ['up']. Sent after `input` when both are given."})),submit:typebox_exports.Optional(typebox_exports.Boolean({description:"Append Enter (\\r) after `input`. Default true when `input` is a non-empty string."}))});function createBashInputTool(ctx){return{name:TERMINAL_INPUT_TOOL,label:"bash_input",description:"Write stdin or named keys (ctrl+c, enter, up, ...) to a live background bash session: e.g. drive a REPL or send SIGINT. This executes arbitrary shell input and is permission-gated like bash.",exposure:"search",allowLazyActivation:!0,searchKeywords:["stdin","keys","ctrl+c","interrupt","repl","send input"],parameters:bashInputSchema,async execute(_toolCallId,input,_signal){let sessionId=resolveTerminalId(ctx.manager,input.bash_id),runtime=ctx.manager.get(sessionId);if(!runtime)return errorResult(`No terminal session found with id: ${input.bash_id}`);if(runtime.exited)return errorResult(`Session ${input.bash_id} is not running; cannot send input.`);let notes=[];if(typeof input.input=="string"){let submit=input.submit??input.input.length>0,result=runtime.session.write(submit?`${input.input}\r`:input.input);if(!result.ok)return errorResult(`Failed to write input: ${result.note}`);notes.push(submit?"wrote input + Enter":"wrote input")}if(input.keys&&input.keys.length>0){let{data,unknown}=encodeKeys(input.keys);if(data.length>0){let result=runtime.session.write(data);if(!result.ok)return errorResult(`Failed to send keys: ${result.note}`);notes.push(`sent ${input.keys.length-unknown.length} key(s)`)}unknown.length>0&¬es.push(`ignored unknown keys: ${unknown.join(", ")}`)}return notes.length===0?errorResult("Nothing to send: provide `input` and/or `keys`."):(ctx.onSessionInput?.(sessionId),textResult(`Sent to ${input.bash_id}: ${notes.join("; ")}.`))}}}var PLAIN_LINE_STYLE={fg:(_token,text)=>text};function jobWidgetLineStyle(theme,env=process.env){return env.NO_COLOR?PLAIN_LINE_STYLE:{fg:(token2,text)=>theme.fg(token2,text)}}var SPARK_LEVELS="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588",ELLIPSIS="\u2026",SGR_RESET="\x1B[0m",MIN_TITLE_COLUMNS=8,GAP=" ";function sparkGlyphs(values,min,max,columns){let span=max-min,top=SPARK_LEVELS.length-1;return values.slice(-columns).map(value=>{let level=span>0?Math.round((value-min)/span*top):Math.ceil(top/2);return SPARK_LEVELS[Math.min(top,Math.max(0,level))]}).join("")}function sparkColumns(width){return width>=100?16:width>=60?12:8}function meterCells(width){return width>=60?10:6}function plain(segments){return segments.map(segment=>segment.text).join("")}function styled(segments,style){return segments.filter(segment=>segment.text.length>0).map(segment=>segment.token?style.fg(segment.token,segment.text):segment.text).join("")}function cutPlain(text,columns){return truncateToWidth(text,columns,ELLIPSIS).replaceAll(SGR_RESET,"")}function trendToken(tone){return tone==="success"?"success":tone==="error"?"error":"muted"}function oneLine(text){return text.replace(/\s+/g," ").trim()}function metricSegments(view,withHeadlineLabel,extra){let segments=[],headline=view.headline;return headline&&(headline.label&&withHeadlineLabel&&segments.push({text:`${oneLine(headline.label)} `,token:"muted"}),segments.push({text:oneLine(headline.text)}),headline.trend&&segments.push({text:` ${headline.trend.text}`,token:trendToken(headline.trend.tone)})),extra&&(segments.length>0&&segments.push({text:" \xB7 ",token:"muted"}),segments.push({text:extra})),segments}function viewParts(entry,view,width){if(entry.state==="pending"){let lines=view.lines??0,metrics=[{text:`reading output \xB7 ${lines} ${lines===1?"line":"lines"}`,token:"muted"}];return{chart:[],metrics:()=>metrics}}if(entry.state==="fallback"){let metrics=view.stage?[{text:oneLine(view.stage),token:"muted"}]:[];return{chart:[],metrics:()=>metrics}}let primary=view.blocks[0],chartToken=entry.state==="done"?"muted":"accent";if(primary?.kind==="spark"&&primary.values.length>0)return{label:primary.label,chart:[{text:sparkGlyphs(primary.values,primary.min,primary.max,sparkColumns(width)),token:chartToken}],metrics:withHeadlineLabel=>metricSegments(view,withHeadlineLabel,primary.last)};if(primary?.kind==="meter"){let cells=meterCells(width),filled=Math.round(Math.min(1,Math.max(0,primary.value))*cells);return{label:primary.label,chart:[{text:"[",token:"muted"},{text:"\u2588".repeat(filled),token:chartToken},{text:"\u2591".repeat(cells-filled),token:"muted"},{text:"]",token:"muted"}],count:{text:oneLine(primary.text)},metrics:withHeadlineLabel=>metricSegments(view,withHeadlineLabel)}}return{chart:[],metrics:withHeadlineLabel=>metricSegments(view,withHeadlineLabel)}}function idToken(entry){return entry.state==="live"?"accent":entry.state==="done"?"success":"muted"}function formatJobWidgetLine(entry,width,style,options={}){let view=entry.view;if(entry.state==="skipped"||view===void 0||width<=0)return;let parts=viewParts(entry,view,width),title=oneLine(view.title),titleWidth=visibleWidth(title),compose=shape=>{let pieces=[];if(options.showId!==!1&&pieces.push([{text:entry.id,token:idToken(entry)}]),shape.title.length>0){let label=shape.blockLabel&&parts.label?` \xB7 ${oneLine(parts.label)}`:"";pieces.push([{text:shape.title},...label?[{text:label,token:"muted"}]:[]])}let bar=shape.chart?parts.chart:[],chart=[...bar,...parts.count?[...bar.length>0?[{text:" "}]:[],parts.count]:[]];chart.length>0&&pieces.push(chart);let metrics=parts.metrics(shape.headlineLabel);return metrics.length>0&&pieces.push(metrics),pieces.flatMap((piece,index)=>index===0?piece:[{text:shape.gap},...piece])},fits=segments=>visibleWidth(plain(segments))<=width,shrunk=(shape,minTitle)=>{let without=compose({...shape,title:"",blockLabel:!1}),room=width-visibleWidth(plain(without))-visibleWidth(shape.gap);if(room>=Math.min(minTitle,titleWidth)){let cut=titleWidth<=room?title:cutPlain(title,room);if(cut.length>0&&cut!==ELLIPSIS){let candidate=compose({...shape,title:cut,blockLabel:!1});if(fits(candidate))return candidate}}return minTitle===0&&fits(without)?without:void 0};for(let blockLabel of[!0,!1]){let candidate=compose({title,blockLabel,chart:!0,headlineLabel:!0,gap:GAP});if(fits(candidate))return styled(candidate,style)}for(let headlineLabel of[!0,!1])for(let chart of[!0,!1]){let candidate=shrunk({chart,headlineLabel,gap:GAP},MIN_TITLE_COLUMNS);if(candidate)return styled(candidate,style)}for(let gap of[GAP," "]){let candidate=shrunk({chart:!1,headlineLabel:!1,gap},0);if(candidate)return styled(candidate,style)}let hasNumbers=parts.count!==void 0||parts.metrics(!1).length>0,narrow=compose({title:hasNumbers?"":title,blockLabel:!1,chart:!1,headlineLabel:!1,gap:" "});return style===PLAIN_LINE_STYLE?cutPlain(plain(narrow),width):truncateToWidth(styled(narrow,style),width,ELLIPSIS)}var OUTPUT_PREVIEW_LINES=8;function jobWidgetOf(details){let entry=details?.jobWidget;return typeof entry?.view?.title=="string"&&Array.isArray(entry.view.blocks)?entry:void 0}var BashOutputResultComponent=class{#text="";#isPartial=!1;#expanded=!1;#jobWidget;#style;setResult(result,options,style){this.#jobWidget=jobWidgetOf(result.details),this.#style=style,this.#text=result.content.filter(content=>content.type==="text"&&!isModelOnlyText(content)).map(content=>content.type==="text"?content.text:"").join(`
|
|
@@ -70,4 +70,4 @@ ${early}`:"";return textResult(`${header}${backendNote}${earlyBlock}`,{details:{
|
|
|
70
70
|
`:"";if(input.view==="screen")return textResult(`${prefix}${statusLine(runtime)}
|
|
71
71
|
${screenView(runtime)}`,extra);let delta=runtime.readDelta(),formatted=formatTerminalToolOutput(applyFilter(delta.text,input.filter)),droppedNotice=delta.droppedChars>0?`[${delta.droppedChars} earlier chars dropped]`:void 0,dropped=droppedNotice===void 0?"":`${droppedNotice}
|
|
72
72
|
`;return noticedResult(`${prefix}${statusLine(runtime)}
|
|
73
|
-
${dropped}${formatted.text||"(no new output)"}`,[droppedNotice,formatted.marker],extra)},renderCall:renderBashOutputCall,renderResult:renderBashOutputResult}}var bashResizeSchema=typebox_exports.Object({bash_id:typebox_exports.String({description:"Session id returned by a run_in_background bash call."}),cols:typebox_exports.Number({description:"New PTY width in columns."}),rows:typebox_exports.Number({description:"New PTY height in rows."})});function valid(value){return Number.isFinite(value)&&value>=1}function createBashResizeTool(ctx){return{name:TERMINAL_RESIZE_TOOL,label:"bash_resize",description:"Resize a live background bash session's PTY (cols x rows) so full-screen TUIs reflow. No-ops with a note under the pipe fallback.",exposure:"search",allowLazyActivation:!0,searchKeywords:["resize","pty size","cols","rows","terminal size"],parameters:bashResizeSchema,async execute(_toolCallId,input,_signal){let sessionId=resolveTerminalId(ctx.manager,input.bash_id),runtime=ctx.manager.get(sessionId);if(!runtime)return errorResult(`No terminal session found with id: ${input.bash_id}`);if(runtime.exited)return errorResult(`Session ${input.bash_id} is not running; cannot resize.`);if(!valid(input.cols)||!valid(input.rows))return errorResult("cols and rows must be finite integers >= 1.");let cols=Math.trunc(input.cols),rows=Math.trunc(input.rows),result=runtime.session.resize(cols,rows);return runtime.resizeScreen(cols,rows),result.ok?textResult(`Resized ${input.bash_id} to ${cols}x${rows}.`):textResult(`Resize note for ${input.bash_id}: ${result.note}`)}}}import{mkdir as mkdir4,rm as rm5}from"node:fs/promises";import{isAbsolute as isAbsolute2,join as join6}from"node:path";function terminalStateDir(ctx){if(ctx!==void 0&&NON_INTERACTIVE_MODES.has(ctx.mode))return;let sessionDir=ctx?.sessionManager?.getSessionDir?.();if(!(sessionDir===void 0||sessionDir.length===0||!isAbsolute2(sessionDir)))return join6(sessionDir,"extensions","terminal")}function monitorStateDir(terminalDir,monitorId){return join6(terminalDir,"state",monitorId)}async function ensureMonitorStateDir(terminalDir,monitorId){let dir=monitorStateDir(terminalDir,monitorId);return await mkdir4(dir,{recursive:!0,mode:448}),dir}async function removeMonitorStateDir(terminalDir,monitorId){await rm5(monitorStateDir(terminalDir,monitorId),{recursive:!0,force:!0})}var killBashSchema=typebox_exports.Object({bash_id:typebox_exports.Optional(typebox_exports.String({description:"Session id to tree-kill."})),all:typebox_exports.Optional(typebox_exports.Boolean({description:"Tree-kill every live background session."}))});function createKillBashTool(ctx){return{name:TERMINAL_KILL_TOOL,label:"kill_bash",description:"Terminate a background bash session (or all of them) and its process tree cleanly.",promptSnippet:"Tree-kill a background bash session (or all) with no orphans",parameters:killBashSchema,async execute(_toolCallId,input,_signal){let terminalDir=terminalStateDir(ctx.getSessionContext?.()),dropStateDir=async monitorId2=>{terminalDir!==void 0&&monitorId2!==void 0&&await removeMonitorStateDir(terminalDir,monitorId2)};if(input.all){let terminalCount=ctx.manager.size,monitorIds=(ctx.monitorRegistry?.snapshot()??[]).map(entry=>entry.monitorId),fileCount=await ctx.monitorRegistry?.stopAllFiles()??0,rpcCount=ctx.monitorRegistry?.stopAllRpc()??0;await ctx.manager.teardown();for(let monitorId2 of monitorIds)await dropStateDir(monitorId2);return textResult(`Killed ${terminalCount+fileCount+rpcCount} session(s).`)}if(!input.bash_id)return errorResult("Provide `bash_id` or set `all:true`.");let sessionId=resolveTerminalId(ctx.manager,input.bash_id),monitorId=input.bash_id.startsWith("mon_")?input.bash_id:ctx.manager.monitorIdOf?.(sessionId);return await ctx.monitorRegistry?.stopFile(sessionId)||ctx.monitorRegistry?.stopRpc(sessionId)?(await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):ctx.manager.get(sessionId)?(await ctx.manager.stop(sessionId),await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):errorResult(`No terminal session found with id: ${input.bash_id}`)}}}var TERMINAL_CHILD_JOB_KINDS={bash:"terminal.bash",output:"terminal.output",input:"terminal.input",resize:"terminal.resize",kill:"terminal.kill"};function childTerminalIdScope(generation){return`c${generation}`}var CHILD_SESSION_ID=/_c(\d+)_\d+$/;function isChildSessionId(id){return CHILD_SESSION_ID.test(id)}function childGenerationOf(id){let generation=CHILD_SESSION_ID.exec(id)?.[1];return generation===void 0?void 0:Number(generation)}function parseBackgroundWake(value){if(typeof value!="object"||value===null)return;let event=Reflect.get(value,"event"),id=Reflect.get(value,"id");if(!(typeof id!="string"||!isChildSessionId(id))){if(event==="background_start"){let description=Reflect.get(value,"description"),startedAtMs=Reflect.get(value,"startedAtMs");return typeof description!="string"||typeof startedAtMs!="number"?void 0:{event,id,description,startedAtMs}}if(event==="background_exit"){let output=Reflect.get(value,"output"),exit=Reflect.get(value,"exit");return typeof output!="string"||exit!==null&&typeof exit!="object"?void 0:{event,id,exit,output}}}}function exitView(exit,output){return{exitResult:exit,fullOutput:()=>output}}function bashIdOf(value){if(typeof value!="object"||value===null)return;let id=value.bash_id;return typeof id=="string"?id:void 0}function lostSessionResult(id,generation){return{content:[{type:"text",text:`bash_id ${id} is lost: the session's tool child (generation ${generation}) exited, which ended this session and every process it started. Start a new session with bash.`}],details:{bash_id:id,lost:!0,generation}}}function terminalChildJob(ctx,kind){return{kind,...kind===TERMINAL_CHILD_JOB_KINDS.bash?backgroundRelay(ctx):{},...kind===TERMINAL_CHILD_JOB_KINDS.bash?{}:{placement:params=>{let id=bashIdOf(params);return id===void 0?kind===TERMINAL_CHILD_JOB_KINDS.kill?"both":"child":isChildSessionId(id)?"child":"server"}},result:(params,value,generation)=>{if(kind===TERMINAL_CHILD_JOB_KINDS.bash)return value;let id=bashIdOf(params),startedOn=id===void 0?void 0:childGenerationOf(id);return id===void 0||startedOn===void 0||startedOn===generation?value:lostSessionResult(id,startedOn)},args:(params,toolCallId,execCtx)=>{let env={};for(let[name,value]of Object.entries(ctx.getEnv()))typeof value=="string"&&(env[name]=value);return{params,toolCallId,cwd:execCtx.cwd??ctx.cwd,env:{...env,...sessionEnvOverrides(ctx,execCtx)},...ctx.shellPath===void 0?{}:{shellPath:ctx.shellPath},defaultCols:ctx.defaultCols,defaultRows:ctx.defaultRows,redactSecretsInOutput:ctx.redactSecretsInOutput===!0,...ctx.timeoutAction===void 0?{}:{timeoutAction:ctx.timeoutAction}}}}}function backgroundRelay(ctx){let running=new Map;return{wake:(value,generation)=>{let wake=parseBackgroundWake(value);if(wake!==void 0){if(wake.event==="background_start"){running.set(wake.id,generation),ctx.onBackgroundStart?.(wake.id,wake.description,wake.startedAtMs);return}running.delete(wake.id),ctx.onBackgroundExit?.(wake.id,exitView(wake.exit,wake.output))}},childExited:generation=>{for(let[id,startedOn]of running)startedOn===generation&&(running.delete(id),ctx.onBackgroundExit?.(id,exitView({exitCode:null,signal:null,timedOut:!1,cancelled:!0},`The session's tool child (generation ${generation}) exited, which ended this session and every process it started.`)))}}}export{ToolChildJobError,HostCallAdmission,PayloadRefWriter,PayloadRefReader,packPayload,unpackPayload,proofIsOrdered,TEST_CONTROL_DIR_ENV,readTestControls,WindowsJobError,WindowsJob,loadKernel32Job,generationLedgerPath,DescendantsLedger,LaunchLog,sweepGroups,defaultGroupProbes,recordGenerationChild,sweepStaleGenerations,TOOL_CHILD_GENERATION_ENV,TOOL_CHILD_PROTOCOL_VERSION,runToolChild,goShimScript,controlFd,withControlPipe,MODULE_JOB_KIND,TOOL_CHILD_MODULE_ROOTS_ENV,createModuleJobHandler,TerminalManager,annotateShellTrust,withTerminalContext,modelOnlyText,isModelOnlyText,DEFAULT_MAX_LINES,DEFAULT_MAX_BYTES,formatSize,truncateHead,truncateTail,truncateLine,sanitizeTerminalOutput,spawnCommandSession,describeExit,NOTICE_TAIL_MAX_CHARS,getTerminalNotificationDelivery,TerminalNotifier,createSessionLogger,queueEntryLabel,watchForStall,PendingQueueLedger,resolveTerminalId,textResult,errorResult,resolveForegroundWindowSeconds,createPtyBashTool,createBashInputTool,secretOutputObfuscator,truncateText,JOB_WIDGET_AGGS,JOB_WIDGET_TONES,onJobWidgetSessionChange,openJobWidgetSession,resendJobWidgetState,parkJobWidgetSession,closeJobWidgetSession,registerJobWidgetSource,getJobWidgetState,setJobWidgetAuthorResolver,jobWidgetHostResolver,truncateToVisualLines,jobWidgetLineStyle,cutPlain,formatJobWidgetLine,renderMonitorCall,createBashOutputTool,createBashResizeTool,terminalStateDir,ensureMonitorStateDir,removeMonitorStateDir,createKillBashTool,TERMINAL_CHILD_JOB_KINDS,childTerminalIdScope,terminalChildJob};
|
|
73
|
+
${dropped}${formatted.text||"(no new output)"}`,[droppedNotice,formatted.marker],extra)},renderCall:renderBashOutputCall,renderResult:renderBashOutputResult}}var bashResizeSchema=typebox_exports.Object({bash_id:typebox_exports.String({description:"Session id returned by a run_in_background bash call."}),cols:typebox_exports.Number({description:"New PTY width in columns."}),rows:typebox_exports.Number({description:"New PTY height in rows."})});function valid(value){return Number.isFinite(value)&&value>=1}function createBashResizeTool(ctx){return{name:TERMINAL_RESIZE_TOOL,label:"bash_resize",description:"Resize a live background bash session's PTY (cols x rows) so full-screen TUIs reflow. No-ops with a note under the pipe fallback.",exposure:"search",allowLazyActivation:!0,searchKeywords:["resize","pty size","cols","rows","terminal size"],parameters:bashResizeSchema,async execute(_toolCallId,input,_signal){let sessionId=resolveTerminalId(ctx.manager,input.bash_id),runtime=ctx.manager.get(sessionId);if(!runtime)return errorResult(`No terminal session found with id: ${input.bash_id}`);if(runtime.exited)return errorResult(`Session ${input.bash_id} is not running; cannot resize.`);if(!valid(input.cols)||!valid(input.rows))return errorResult("cols and rows must be finite integers >= 1.");let cols=Math.trunc(input.cols),rows=Math.trunc(input.rows),result=runtime.session.resize(cols,rows);return runtime.resizeScreen(cols,rows),result.ok?textResult(`Resized ${input.bash_id} to ${cols}x${rows}.`):textResult(`Resize note for ${input.bash_id}: ${result.note}`)}}}import{mkdir as mkdir4,rm as rm5}from"node:fs/promises";import{isAbsolute as isAbsolute2,join as join6}from"node:path";function terminalStateDir(ctx){if(ctx!==void 0&&NON_INTERACTIVE_MODES.has(ctx.mode))return;let sessionDir=ctx?.sessionManager?.getSessionDir?.();if(!(sessionDir===void 0||sessionDir.length===0||!isAbsolute2(sessionDir)))return join6(sessionDir,"extensions","terminal")}function monitorStateDir(terminalDir,monitorId){return join6(terminalDir,"state",monitorId)}async function ensureMonitorStateDir(terminalDir,monitorId){let dir=monitorStateDir(terminalDir,monitorId);return await mkdir4(dir,{recursive:!0,mode:448}),dir}async function removeMonitorStateDir(terminalDir,monitorId){await rm5(monitorStateDir(terminalDir,monitorId),{recursive:!0,force:!0})}var killBashSchema=typebox_exports.Object({bash_id:typebox_exports.Optional(typebox_exports.String({description:"Session id to tree-kill."})),all:typebox_exports.Optional(typebox_exports.Boolean({description:"Tree-kill every live background session."}))});function createKillBashTool(ctx){return{name:TERMINAL_KILL_TOOL,label:"kill_bash",description:"Terminate a background bash session (or all of them) and its process tree cleanly.",promptSnippet:"Tree-kill a background bash session (or all) with no orphans",parameters:killBashSchema,async execute(_toolCallId,input,_signal){let terminalDir=terminalStateDir(ctx.getSessionContext?.()),dropStateDir=async monitorId2=>{terminalDir!==void 0&&monitorId2!==void 0&&await removeMonitorStateDir(terminalDir,monitorId2)};if(input.all){let terminalCount=ctx.manager.size,monitorIds=(ctx.monitorRegistry?.snapshot()??[]).map(entry=>entry.monitorId),fileCount=await ctx.monitorRegistry?.stopAllFiles()??0,rpcCount=ctx.monitorRegistry?.stopAllRpc()??0;await ctx.manager.teardown();for(let monitorId2 of monitorIds)await dropStateDir(monitorId2);return textResult(`Killed ${terminalCount+fileCount+rpcCount} session(s).`)}if(!input.bash_id)return errorResult("Provide `bash_id` or set `all:true`.");let sessionId=resolveTerminalId(ctx.manager,input.bash_id),monitorId=input.bash_id.startsWith("mon_")?input.bash_id:ctx.manager.monitorIdOf?.(sessionId);return await ctx.monitorRegistry?.stopFile(sessionId)||ctx.monitorRegistry?.stopRpc(sessionId)?(await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):ctx.manager.get(sessionId)?(await ctx.manager.stop(sessionId),await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):errorResult(`No terminal session found with id: ${input.bash_id}`)}}}var TERMINAL_CHILD_JOB_KINDS={bash:"terminal.bash",output:"terminal.output",input:"terminal.input",resize:"terminal.resize",kill:"terminal.kill"};function childTerminalIdScope(generation){return`c${generation}`}var CHILD_SESSION_ID=/_c(\d+)_\d+$/;function isChildSessionId(id){return CHILD_SESSION_ID.test(id)}function childGenerationOf(id){let generation=CHILD_SESSION_ID.exec(id)?.[1];return generation===void 0?void 0:Number(generation)}function optionalMinutes(value){return typeof value=="number"&&Number.isFinite(value)&&value>=1?Math.trunc(value):void 0}function parseBackgroundWake(value){if(typeof value!="object"||value===null)return;let event=Reflect.get(value,"event"),id=Reflect.get(value,"id");if(!(typeof id!="string"||!isChildSessionId(id))){if(event==="background_start"){let description=Reflect.get(value,"description"),startedAtMs=Reflect.get(value,"startedAtMs");if(typeof description!="string"||typeof startedAtMs!="number")return;let command=Reflect.get(value,"command"),autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes"));return{event,id,description,startedAtMs,...typeof command=="string"?{command}:{},...autoReapMinutes===void 0?{}:{autoReapMinutes}}}if(event==="background_reap_failed"){let autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes")),reason=Reflect.get(value,"reason");return autoReapMinutes===void 0||typeof reason!="string"?void 0:{event,id,autoReapMinutes,reason}}if(event==="background_exit"){let output=Reflect.get(value,"output"),exit=Reflect.get(value,"exit");if(typeof output!="string"||exit!==null&&typeof exit!="object")return;let autoReapedAfterMinutes=optionalMinutes(Reflect.get(value,"autoReapedAfterMinutes"));return{event,id,exit,output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}}}function exitView(exit,output,autoReapedAfterMinutes){return{exitResult:exit,fullOutput:()=>output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}function bashIdOf(value){if(typeof value!="object"||value===null)return;let id=value.bash_id;return typeof id=="string"?id:void 0}function lostSessionResult(id,generation){return{content:[{type:"text",text:`bash_id ${id} is lost: the session's tool child (generation ${generation}) exited, which ended this session and every process it started. Start a new session with bash.`}],details:{bash_id:id,lost:!0,generation}}}function terminalChildJob(ctx,kind){return{kind,...kind===TERMINAL_CHILD_JOB_KINDS.bash?backgroundRelay(ctx):{},...kind===TERMINAL_CHILD_JOB_KINDS.bash?{}:{placement:params=>{let id=bashIdOf(params);return id===void 0?kind===TERMINAL_CHILD_JOB_KINDS.kill?"both":"child":isChildSessionId(id)?"child":"server"}},result:(params,value,generation)=>{if(kind===TERMINAL_CHILD_JOB_KINDS.bash)return value;let id=bashIdOf(params),startedOn=id===void 0?void 0:childGenerationOf(id);return id===void 0||startedOn===void 0||startedOn===generation?value:lostSessionResult(id,startedOn)},args:(params,toolCallId,execCtx)=>{let env={};for(let[name,value]of Object.entries(ctx.getEnv()))typeof value=="string"&&(env[name]=value);return{params,toolCallId,cwd:execCtx.cwd??ctx.cwd,env:{...env,...sessionEnvOverrides(ctx,execCtx)},...ctx.shellPath===void 0?{}:{shellPath:ctx.shellPath},defaultCols:ctx.defaultCols,defaultRows:ctx.defaultRows,redactSecretsInOutput:ctx.redactSecretsInOutput===!0,...ctx.timeoutAction===void 0?{}:{timeoutAction:ctx.timeoutAction},...ctx.backgroundAutoReapMinutes===void 0?{}:{backgroundAutoReapMinutes:ctx.backgroundAutoReapMinutes}}}}}function backgroundRelay(ctx){let running=new Map;return{wake:(value,generation)=>{let wake=parseBackgroundWake(value);if(wake!==void 0){if(wake.event==="background_start"){running.set(wake.id,generation),ctx.onBackgroundStart?.(wake.id,wake.description,wake.startedAtMs,wake.command,wake.autoReapMinutes);return}if(wake.event==="background_reap_failed"){ctx.onBackgroundReapFailed?.(wake.id,wake.autoReapMinutes,wake.reason);return}running.delete(wake.id),ctx.onBackgroundExit?.(wake.id,exitView(wake.exit,wake.output,wake.autoReapedAfterMinutes))}},childExited:generation=>{for(let[id,startedOn]of running)startedOn===generation&&(running.delete(id),ctx.onBackgroundExit?.(id,exitView({exitCode:null,signal:null,timedOut:!1,cancelled:!0},`The session's tool child (generation ${generation}) exited, which ended this session and every process it started.`)))}}}export{ToolChildJobError,HostCallAdmission,PayloadRefWriter,PayloadRefReader,packPayload,unpackPayload,proofIsOrdered,TEST_CONTROL_DIR_ENV,readTestControls,WindowsJobError,WindowsJob,loadKernel32Job,generationLedgerPath,DescendantsLedger,LaunchLog,sweepGroups,defaultGroupProbes,recordGenerationChild,sweepStaleGenerations,TOOL_CHILD_GENERATION_ENV,TOOL_CHILD_PROTOCOL_VERSION,runToolChild,goShimScript,controlFd,withControlPipe,MODULE_JOB_KIND,TOOL_CHILD_MODULE_ROOTS_ENV,createModuleJobHandler,TerminalManager,annotateShellTrust,withTerminalContext,modelOnlyText,isModelOnlyText,DEFAULT_MAX_LINES,DEFAULT_MAX_BYTES,formatSize,truncateHead,truncateTail,truncateLine,sanitizeTerminalOutput,spawnCommandSession,describeExit,NOTICE_TAIL_MAX_CHARS,getTerminalNotificationDelivery,describeBackgroundAge,TerminalNotifier,createSessionLogger,queueEntryLabel,watchForStall,PendingQueueLedger,resolveTerminalId,textResult,errorResult,resolveForegroundWindowSeconds,createPtyBashTool,createBashInputTool,secretOutputObfuscator,truncateText,JOB_WIDGET_AGGS,JOB_WIDGET_TONES,onJobWidgetSessionChange,openJobWidgetSession,resendJobWidgetState,parkJobWidgetSession,closeJobWidgetSession,registerJobWidgetSource,getJobWidgetState,setJobWidgetAuthorResolver,jobWidgetHostResolver,truncateToVisualLines,jobWidgetLineStyle,cutPlain,formatJobWidgetLine,renderMonitorCall,createBashOutputTool,createBashResizeTool,terminalStateDir,ensureMonitorStateDir,removeMonitorStateDir,createKillBashTool,TERMINAL_CHILD_JOB_KINDS,childTerminalIdScope,terminalChildJob};
|
|
@@ -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{BUILTIN_PATH_PREFIX}from"./chunk-QMRJYMNH.js";import{listHostEndpoints}from"./chunk-Y7Z7XPUF.js";import{parseArgs,resolveSessionRuntime}from"./chunk-54YTJCYZ.js";import{PROBE_REQUEST_ID,connectAndAsk,isRecord as isRecord2,readAnswer,requestOnSocket}from"./chunk-I5ASHSLZ.js";import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STOP_TIMEOUT_MS,DEFAULT_CHILD_STALLED_STOP_MAX_MS,acquireHostEnsureLock,activeStopProgress,childStalledStopMaxMs,claimOwnerIsLive,hostChildAlive,isGenerationId,logUnknownHostIdentity,noteEscalatedStop,provenOwner,readDrainWatch,readGenerationRegistration,readHostRegistration,readSessionPathClaims,readStopIntent,releaseGeneration,resolveHostPolicy,writeDrainRequest,writeStopIntent}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_LAYOUT,createHostDaemonPaths,generationPaths,hostDaemonDirectoryPaths,isRecord,parseJson,readFileOrUndefined,sameEndpoint,writeStateFile}from"./chunk-YI6KRJDC.js";import{OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-DBQBJTMF.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV}from"./chunk-RUGTHELO.js";import{BIND_SCRATCH_INFIX,BIND_SCRATCH_SOCKET,isBindScratchName}from"./chunk-5XHOHZIR.js";import{readSocketSecret,resolveSocketTransportAddress,socketSecretPath}from"./chunk-HW6AAS3R.js";import{APP_NAME,VERSION,getAgentDir,isBunBinary}from"./chunk-SODMQEHO.js";import{ProcessIdentityUnreadableError,parseDaemonPidFile,processIsLive,processMatchesPidFile,processStartTimeMs,readProcessStartTime}from"./chunk-O5RYI3IW.js";var CALVER=/^(\d+)\.(\d+)\.(\d+)(?:-(\d+))?/;function engineBuildIdentityFrom(build){let match=CALVER.exec(build.version),epoch=Number.isSafeInteger(build.epoch)&&build.epoch!==void 0&&build.epoch>0?build.epoch:0,sha7=build.sha7??"";return{text:epoch===0?build.version:`${build.version}+${epoch}${sha7===""?"":`.${sha7}`}`,ordinal:[match?Number(match[1]):0,match?Number(match[2]):0,match?Number(match[3]):0,match?.[4]?Number(match[4]):0,epoch],scheme:epoch===0?"nodef":"epoch"}}var BUILT=engineBuildIdentityFrom({version:VERSION,epoch:typeof SENPI_BUILD_EPOCH=="number"?SENPI_BUILD_EPOCH:0,sha7:typeof SENPI_BUILD_SHA7=="string"?SENPI_BUILD_SHA7:""});function engineBuildIdentity(){return BUILT}function compareEngineOrdinal(a,b){for(let index=0;index<4;index++)if(a.ordinal[index]!==b.ordinal[index])return a.ordinal[index]>b.ordinal[index]?1:-1;return a.scheme!=="epoch"||b.scheme!=="epoch"||a.ordinal[4]===b.ordinal[4]?0:a.ordinal[4]>b.ordinal[4]?1:-1}import*as crypto from"node:crypto";var CUSTOM_UNSUPPORTED_CAPABILITY="custom_unsupported",EXTENSION_EVENTS_CAPABILITY="extension_events",EVAL_CELLS_CAPABILITY="eval_cells",AUTO_TITLE_SESSIONS_CAPABILITY="auto_title_sessions",CONTINUE_FROM_LEAF_CAPABILITY="continue_from_leaf",SESSION_HELD_CAPABILITY="session_held",RESUME_SESSION_CAPABILITY="resume_session",ATTENDED_CAPABILITY="attended",MEDIA_PLACEHOLDERS_CAPABILITY="media_placeholders",COMPACT_EVENTS_CAPABILITY="compact_events",QUESTION_CAPABILITY="question",TOOL_BARRIER_CAPABILITY="tool_barrier",SESSION_RELOCATION_CAPABILITY="session_relocation",RETAIN_ON_DISCONNECT_CAPABILITY="retain_on_disconnect",DELEGATED_CONNECTION_CAPABILITY="delegated_connection_v1",DELEGATION_ROLES_CAPABILITY="delegation_roles_v1",RAISER_NOTICE_CAPABILITY="raiser_notice_v1",DETACH_CONNECTION_CAPABILITY="detach_connection",INTERACTIVE_USER_CAPABILITY="interactive_user",OBSERVE_READS_CAPABILITY="observe_reads",ENTRIES_TAIL_CAPABILITY="entries_tail",TUI_OBSERVER_CAPABILITY="tui_observer",TASK_PARENT_CAPABILITY="task_parent",SESSION_CONTEXT_CAPABILITY="session_context",SESSION_KIND_CAPABILITY="session_kind",SESSION_STATUS_CAPABILITY="session_status",AUTO_TITLE_PER_SESSION_CAPABILITY="auto_title_per_session",WARM_CAPABILITY="warm",DURABLE_SESSION_ID_CAPABILITY="durable_session_id",HAND_SELECTION_CAPABILITY="hand_selection",MOVED_PATH_GUARD_CAPABILITY="moved_path_guard",PROMPT_SURFACE_CAPABILITY="prompt_surface",BROWSER_ENGINE_CAPABILITY="browser_engine",SESSION_ENV_CAPABILITY="session_env",RETRY_FALLBACK_PROFILE_CAPABILITY="retry_fallback_profile",RETRY_FALLBACK_COMMAND_CAPABILITY="retry_fallback_command",PROMPT_SURFACE_CHAT_CAPABILITY="prompt_surface_chat",RPC_CLIENT_CAPABILITIES_ENV="SENPI_RPC_CLIENT_CAPABILITIES";function parseClientCapabilities(value){return value?value.split(",").map(part=>part.trim()).filter(part=>part.length>0):[]}var DEFAULT_CUSTOM_EXTENSION_LABEL="custom UI component";function buildCustomUnsupportedRequest(capabilities,extensionName){if(!capabilities?.includes(CUSTOM_UNSUPPORTED_CAPABILITY))return;let name=extensionName.trim()||DEFAULT_CUSTOM_EXTENSION_LABEL;return{type:"extension_ui_request",id:crypto.randomUUID(),method:"custom_unsupported",extensionName:name}}var AUTH_KEY_VERIFY_CAPABILITY="auth_key_verify",PROVIDER_ACCOUNT_TEST_CAPABILITY="provider_account_test",ACCOUNT_RESET_CAPABILITY="account_reset",QUEUED_MESSAGE_REVISION_CAPABILITY="queued_message_revision";import{createHash}from"node:crypto";import{existsSync}from"node:fs";import{readdir,readFile,realpath,stat}from"node:fs/promises";import{basename,dirname,join,relative,sep}from"node:path";import{fileURLToPath}from"node:url";var RUNTIME_IDENTITY_HANDOVER_CAPABILITY="runtime_identity_handover",RUNTIME_BUILD_ID=/^sha256:[0-9a-f]{64}$/,EXCLUDED_FILE=/\.(?:d\.[cm]?ts|map)$/,EXCLUDED_NAMES=new Set(["node_modules","runtime-manifest.json","runtime-snapshot.json"]),READ_CONCURRENCY=32;function parseRuntimeBuildId(value){return typeof value=="string"&&RUNTIME_BUILD_ID.test(value)?value:void 0}async function computeRuntimeBuildId(input){let source=input.source??loadedRuntimeSource(),plugins=await Promise.all(input.profile.extensions.map(path=>extensionDigest(path))),manifest={schema:1,flavour:source.flavour,platform:input.platform??process.platform,arch:input.arch??process.arch,engine:input.engine??engineBuildIdentity().text,runtime:await treeDigest(source.root),plugins:plugins.sort(),profile:{multi_session:input.profile.multi_session,session_runtime:input.profile.session_runtime}};return`sha256:${sha256(JSON.stringify(manifest))}`}function loadedRuntimeSource(){if(isBunBinary)return{flavour:"compiled",root:process.execPath};let moduleDir=dirname(fileURLToPath(import.meta.url)),packageRoot=nearestPackageRoot(moduleDir),[top,next]=relative(packageRoot,moduleDir).split(sep);return top==="dist"?{flavour:"packaged",root:join(packageRoot,next==="bundle"?join("dist","bundle"):"dist")}:{flavour:"dev",root:join(packageRoot,top??"")}}function nearestPackageRoot(start){for(let dir=start;;dir=dirname(dir)){if(existsSync(join(dir,"package.json")))return dir;if(dirname(dir)===dir)return start}}function extensionDigest(path){let name=basename(path);return name.startsWith(BUILTIN_PATH_PREFIX)?Promise.resolve(sha256(name)):treeDigest(path)}async function treeDigest(root){let files=[];(await stat(root)).isFile()?files.push(["",root]):await collect(await realpath(root),"",files,new Set);let digests=await mapLimited(files,READ_CONCURRENCY,async([path,file])=>[path,sha256(await readFile(file))]);return digests.sort(([a],[b])=>a<b?-1:a>b?1:0),sha256(JSON.stringify(digests))}async function collect(dir,prefix,files,seen){if(seen.has(dir))return;seen.add(dir);let entries=(await readdir(dir,{withFileTypes:!0})).sort((a,b)=>a.name<b.name?-1:a.name>b.name?1:0);for(let entry of entries){if(entry.name.startsWith(".")||EXCLUDED_NAMES.has(entry.name))continue;let path=join(dir,entry.name),name=prefix===""?entry.name:`${prefix}/${entry.name}`,kind=entry.isSymbolicLink()?await stat(path).catch(()=>{}):entry;kind!==void 0&&(kind.isDirectory()?await collect(await realpath(path),name,files,seen):kind.isFile()&&!EXCLUDED_FILE.test(entry.name)&&files.push([name,path]))}}async function mapLimited(items,limit,map){let results=new Array(items.length),next=0,worker=async()=>{for(let index=next++;index<items.length;index=next++)results[index]=await map(items[index])};return await Promise.all(Array.from({length:Math.min(limit,items.length)},worker)),results}function sha256(data){return createHash("sha256").update(data).digest("hex")}var STATES=["not_started","ready","unavailable"];function pathIdentityResolverStatus(resolver){let detail=resolver.unavailable;return detail!==void 0?{state:"unavailable",detail}:{state:resolver.snapshot===void 0?"not_started":"ready",detail:null}}function isState(value){return STATES.some(state=>state===value)}function parsePathIdentityResolverStatus(value){if(typeof value!="object"||value===null)return;let{state,detail}=value;if(isState(state))return{state,detail:typeof detail=="string"?detail:null}}function parseHostProtocolInfo(data){if(!isRecord3(data)||typeof data.serverVersion!="string"||!Array.isArray(data.capabilities)||!data.capabilities.every(entry=>typeof entry=="string"))return;let ordinal=parseOrdinal(data.engineOrdinal),launchProfile=parseLaunchProfile(data.launch_profile),runtimeBuildId=parseRuntimeBuildId(data.runtimeBuildId),pathIdentityResolver=parsePathIdentityResolverStatus(data.path_identity_resolver);return{protocolVersion:typeof data.protocolVersion=="number"?data.protocolVersion:0,serverVersion:data.serverVersion,capabilities:data.capabilities,...(data.lifecycle==="ready"||data.lifecycle==="stopping")&&{lifecycle:data.lifecycle},...typeof data.instanceId=="string"&&{instanceId:data.instanceId},...typeof data.generation=="number"&&Number.isSafeInteger(data.generation)&&{generation:data.generation},...typeof data.engineVersion=="string"&&{engineVersion:data.engineVersion},...ordinal&&{engineOrdinal:ordinal},...launchProfile&&{launch_profile:launchProfile},...typeof data.memory_pressure=="boolean"&&{memory_pressure:data.memory_pressure},...pathIdentityResolver!==void 0&&{path_identity_resolver:pathIdentityResolver},...runtimeBuildId!==void 0&&{runtimeBuildId},...typeof data.agentDir=="string"&&data.agentDir!==""&&{agentDir:data.agentDir},...isRecord3(data.handover)&&{handover:data.handover}}}function parseOrdinal(value){if(!(!Array.isArray(value)||value.length!==5||!value.every(part=>typeof part=="number")))return[value[0],value[1],value[2],value[3],value[4]]}function parseLaunchProfile(value){if(!isRecord3(value)||typeof value.profile_id!="string"||!isRecord3(value.core))return;let{extensions,multi_session,session_runtime}=value.core;if(!(!Array.isArray(extensions)||!extensions.every(entry=>typeof entry=="string"))&&typeof multi_session=="boolean"&&!(session_runtime!=="in-process"&&session_runtime!=="worker"))return{profile_id:value.profile_id,core:{extensions,multi_session,session_runtime}}}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function describeHostHolder(holder){let engine=holder.engineVersion===null?"an unrecorded engine":`engine ${holder.engineVersion}`,profile=holder.launchProfileId===null?"":`, launch profile ${holder.launchProfileId}`,writer=holder.writerPid===null||holder.writerPid===holder.pid?"":`, started by pid ${holder.writerPid}`;return`pid ${holder.pid}, ${engine}${profile}${writer}`}var HOST_PROTOCOL_VERSION=1,GENERATION_HANDOFF_CAPABILITY="generation_handoff",ENDPOINT_OWNER_FENCE_CAPABILITY="endpoint_owner_fence",REQUIRED_HOST_CAPABILITIES=["multi_session",EXTENSION_EVENTS_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY],HostEnsureRefusedError=class extends Error{constructor(socket,reason,host,detail,holder){let heldBy=holder?` (held by ${describeHostHolder(holder)})`:"";super(`RPC socket ${socket} refused: ${reason} - ${refusalDetail(reason,host)}${detail?`: ${detail}`:""}${heldBy}`),this.name="HostEnsureRefusedError",this.socket=socket,this.reason=reason,this.detail=detail,this.holder=holder}};function refusalDetail(reason,host){switch(reason){case"protocol":return`the running host speaks protocol version ${host?.protocolVersion??"unknown"}, this build speaks ${HOST_PROTOCOL_VERSION}`;case"capability":{let missing=REQUIRED_HOST_CAPABILITIES.filter(capability=>!host?.capabilities.includes(capability));return`the running host is missing ${JSON.stringify(missing)}; it owns the socket, so no second host is started`}case"foreign_writer":return"another process registered the host on this socket; it accepts connections but did not answer as a host, and this one may not signal it - stop that host explicitly (host stop --force), then ensure again";case"legacy_host":return"a host from before the per-socket daemon directory is still running; it is drained and replaced only while it holds no session, and no second host is started beside it";case"host_busy":return"its socket accepts connections but did not answer inside the probe budget: a live host under load, which is never ended to make room for a replacement";case"host_stopping":return"this generation is stopping; wait for its exit before launching a successor";case"endpoint_occupied":return"another process accepts connections on this socket but does not answer as a host, and no host registration names it; it is never removed while it listens, so quit the process holding it and ensure again";case"host_stalled":return"nothing reaches its socket, but its process is alive and its own loop-lag watchdog measured a recent stall: a stalled host is still serving its sessions, so it is neither stopped nor replaced";default:return assertNever(reason)}}function decideHostAction(client,host,policy){if(host===void 0)return{action:"start",reason:client.startedByUs?"restart_own_host":"no_host",upgradeable:!1};if(host.lifecycle==="stopping")return{action:"refuse",reason:"host_stopping",upgradeable:!1};if(host.protocolVersion!==client.protocolVersion)return{action:"refuse",reason:"protocol",upgradeable:!1};if(!client.requiredCapabilities.every(capability=>host.capabilities.includes(capability)))return policy==="fallback"?{action:"fallback",reason:"capability",upgradeable:!1}:{action:"refuse",reason:"capability",upgradeable:!1};let upgradeable=client.platform!=="win32"&&host.capabilities.includes(GENERATION_HANDOFF_CAPABILITY);if(policy==="fallback"&&host.engineVersion!==client.identity.text)return{action:"fallback",reason:"engine_mismatch",upgradeable};let warning=profileWarning(client,host);return client.platform==="win32"?{action:"reuse",reason:"win32_attach_only",upgradeable:!1,...warning&&{warning}}:upgradeable?policy==="upgrade"&&client.launchProfile&&host.launch_profile&&supersedes(client,host)?{action:"handoff",reason:sameRelease(client.identity.ordinal,host.engineOrdinal)?"profile":"newer_engine",upgradeable:!0}:{action:"reuse",reason:"compatible",upgradeable,...warning&&{warning}}:{action:"reuse",reason:"handoff_unsupported",upgradeable:!1,...warning&&{warning}}}function supersedes(client,host){if(host.engineOrdinal===void 0)return!1;let hostIdentity={text:host.engineVersion??"",ordinal:host.engineOrdinal,scheme:host.engineOrdinal[4]>0?"epoch":"nodef"};return compareEngineOrdinal(client.identity,hostIdentity)<=0?!1:covers(client.launchProfile,host.launch_profile)}function profileWarning(client,host){if(client.launchProfile===void 0||host.launch_profile===void 0)return"profile_mismatch_attached";if(client.launchProfile.profile_id===host.launch_profile.profile_id)return;let clientCoversHost=covers(client.launchProfile,host.launch_profile);if(!(clientCoversHost&&covers(host.launch_profile,client.launchProfile)))return clientCoversHost?"profile_mismatch_attached":"profile_narrower_attached"}function extensionRole(extension){let segments=extension.split(/[\\/]+/),pluginAt=segments.lastIndexOf("plugin");return pluginAt<0?extension:segments.slice(pluginAt).join("/")}function covers(candidate,running){if(candidate===void 0||running===void 0)return!1;let candidateRoles=new Set(candidate.core.extensions.map(extensionRole));return running.core.extensions.every(extension=>candidateRoles.has(extensionRole(extension)))}function sameRelease(candidate,running){return running!==void 0&&candidate.slice(0,4).every((part,index)=>part===running[index])}function assertNever(value){throw new Error(`unreachable host decision: ${JSON.stringify(value)}`)}import{createHash as createHash3,randomUUID as randomUUID2}from"node:crypto";import{resolve}from"node:path";import{createHash as createHash2}from"node:crypto";var RPC_METHOD_CLASSES_VERSION=1,DYNAMIC="dynamic",ENTRY_AUTHORSHIP={message:"user_role_only",thinking_level_change:"engine",configuration_update:"engine",model_change:"engine",model_change_rejected:"engine",usage:"engine",compaction:"engine",branch_summary:"engine",custom:"engine",custom_message:"engine",context_edit:"engine",label:"engine",session_info:"engine"},USER_ROLE="user";function appendEntryClass(record){let entry=Reflect.get(record,"entry");if(typeof entry!="object"||entry===null)return"device_admin";let entryType=Reflect.get(entry,"type");if(typeof entryType!="string"||!Object.hasOwn(ENTRY_AUTHORSHIP,entryType)||ENTRY_AUTHORSHIP[entryType]!=="user_role_only")return"device_admin";let message=Reflect.get(entry,"message");return typeof message!="object"||message===null?"device_admin":Reflect.get(message,"role")===USER_ROLE?"drive":"device_admin"}function namesAny(record,fields){return fields.some(field=>Object.hasOwn(record,field)&&Reflect.get(record,field)!==void 0)}function openSessionClass(record){return namesAny(record,["sessionPath","cwd","permissionPreset","browserEngine","env"])?"device_admin":"thread"}function thinkingLevelClass(record){return Reflect.get(record,"scope")==="turn"?"drive":"device_admin"}function setModelClass(record){return Reflect.get(record,"scope")==="session"?"drive":"device_admin"}function effectStatusClass(record){return namesAny(record,["sessionPath"])?"device_admin":"observe"}function promptClass(record){let message=Reflect.get(record,"message");return typeof message!="string"?"device_admin":Reflect.get(record,"expandPromptTemplates")===!1?"drive":message.startsWith("/")?"device_admin":"drive"}function idleStartClass(record){if(Reflect.get(record,"whenIdle")!=="start")return"drive";let message=Reflect.get(record,"message");return typeof message!="string"||message.startsWith("/")?"device_admin":"drive"}function newSessionClass(record){return namesAny(record,["parentSession"])?"device_admin":"thread"}var RPC_METHOD_CLASS={get_protocol_info:"observe",get_subscription_limits:"observe",list_sessions:"observe",list_hands:"observe",get_state:"observe",get_snapshot:"observe",get_entries:"observe",get_messages:"observe",get_tree:"observe",get_fork_messages:"observe",get_last_assistant_text:"observe",get_session_stats:"observe",get_effect_status:{classify:effectStatusClass,version:1},get_pending_inputs:"observe",get_follow_up_messages:"observe",get_steering_messages:"observe",get_commands:"observe",get_loaded_surfaces:"observe",get_project_trust:"observe",get_available_models:"observe",get_available_thinking_levels:"observe",get_model_thinking_level:"observe",get_fast_mode:"observe",get_media:"observe",memory_report:"observe","eval_cells.list":"observe","eval_cells.peek":"observe",prompt:{classify:promptClass,version:1},steer:{classify:idleStartClass,version:1},follow_up:{classify:idleStartClass,version:1},abort:"drive",interrupt:"drive",abort_retry:"drive",abort_compaction:"drive",abort_branch_summary:"drive",compact:"drive",clear_queue:"drive",dequeue_message:"drive",edit_queued_message:"drive",hold_input:"drive",withdraw_held_input:"drive",append_user_message:"drive",edit_user_message:"drive",continue_from_leaf:"drive",navigate_tree:"drive",set_label:"drive",set_session_name:"drive",set_thinking_level:{classify:thinkingLevelClass,version:1},set_model:{classify:setModelClass,version:1},set_auto_compaction:"drive",set_permission_preset:"device_admin",set_retry_fallback:"drive",pause_for_run:"drive",resume_for_run:"drive",wake:"drive",release_tool_barrier:"drive",request_self_settle:"drive","eval_cells.stop":"drive",append_session_entry:{classify:appendEntryClass,version:1},extension_ui_response:"answer",extension_ui_progress:"answer",new_session:{classify:newSessionClass,version:1},open_session:{classify:openSessionClass,version:2},resume_session:"thread",fork:"thread",clone:"thread",close_session:"thread",unload_session:"thread",set_session_context:"thread",attach_session:"thread",select_hand:"device_admin",bash:"device_admin",abort_bash:"device_admin",record_bash_result:"device_admin",cleanup_bash_output:"device_admin",extension_request:"device_admin",reload:"device_admin",check_reload_veto:"device_admin",resolve_path:"device_admin",login_start:"device_admin",login_cancel:"device_admin",login_api_key:"device_admin",logout:"device_admin",verify_api_key:"device_admin",get_auth_providers:"device_admin",get_provider_accounts:"device_admin",account_order:"device_admin",account_pin:"device_admin",account_remove:"device_admin",account_reset:"device_admin",test_provider_account:"device_admin",set_favorite_models:"device_admin",set_scoped_models:"device_admin",cycle_model:"device_admin",cycle_thinking_level:"device_admin",set_fast_mode:"device_admin",set_steering_mode:"device_admin",set_follow_up_mode:"device_admin",set_auto_retry:"device_admin",set_project_trust:"device_admin",get_project_settings:"device_admin",set_project_setting:"device_admin",edit_assistant_message:"device_admin",send_custom_message:"device_admin",switch_session:"device_admin",import_jsonl:"device_admin",export_html:"device_admin",export_jsonl:"device_admin",set_client_info:"connection_local",subscribe_sessions:"connection_local",unsubscribe_sessions:"connection_local",record_user_activity:"connection_local",detach_connection:"connection_local",release_session:"connection_local",warm:"connection_local",host_response:"connection_local",release_attachment:"connection_local",reclaim_session:"connection_local",move_session:"connection_local",get_recovery_page:"connection_local",release_recovery:"connection_local",cancel_attempt:"connection_local",reset_stream:"connection_local"};function classifyRpcMethod(record){if(!(typeof record!="object"||record===null||Array.isArray(record)))try{let type=Reflect.get(record,"type");if(typeof type!="string"||!Object.hasOwn(RPC_METHOD_CLASS,type))return;let entry=RPC_METHOD_CLASS[type];return typeof entry=="string"?entry:entry.classify(record)}catch{return}}function rpcMethodClassesDigest(table){let lines=Object.entries(table).map(([type,methodClass])=>`${type}=${methodClass}
|
|
2
|
+
import{BUILTIN_PATH_PREFIX}from"./chunk-QMRJYMNH.js";import{listHostEndpoints}from"./chunk-Y7Z7XPUF.js";import{parseArgs,resolveSessionRuntime}from"./chunk-54YTJCYZ.js";import{PROBE_REQUEST_ID,connectAndAsk,isRecord as isRecord2,readAnswer,requestOnSocket}from"./chunk-I5ASHSLZ.js";import{CHILD_KILL_EXIT_TIMEOUT_MS,CHILD_STOP_TIMEOUT_MS,DEFAULT_CHILD_STALLED_STOP_MAX_MS,acquireHostEnsureLock,activeStopProgress,childStalledStopMaxMs,claimOwnerIsLive,hostChildAlive,isGenerationId,logUnknownHostIdentity,noteEscalatedStop,provenOwner,readDrainWatch,readGenerationRegistration,readHostRegistration,readSessionPathClaims,readStopIntent,releaseGeneration,resolveHostPolicy,writeDrainRequest,writeStopIntent}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_LAYOUT,createHostDaemonPaths,generationPaths,hostDaemonDirectoryPaths,isRecord,parseJson,readFileOrUndefined,sameEndpoint,writeStateFile}from"./chunk-YI6KRJDC.js";import{OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-DBQBJTMF.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV}from"./chunk-RUGTHELO.js";import{BIND_SCRATCH_INFIX,BIND_SCRATCH_SOCKET,isBindScratchName}from"./chunk-5XHOHZIR.js";import{readSocketSecret,resolveSocketTransportAddress,socketSecretPath}from"./chunk-HW6AAS3R.js";import{APP_NAME,VERSION,getAgentDir,isBunBinary}from"./chunk-SODMQEHO.js";import{ProcessIdentityUnreadableError,parseDaemonPidFile,processIsLive,processMatchesPidFile,processStartTimeMs,readProcessStartTime}from"./chunk-O5RYI3IW.js";var CALVER=/^(\d+)\.(\d+)\.(\d+)(?:-(\d+))?/;function engineBuildIdentityFrom(build){let match=CALVER.exec(build.version),epoch=Number.isSafeInteger(build.epoch)&&build.epoch!==void 0&&build.epoch>0?build.epoch:0,sha7=build.sha7??"";return{text:epoch===0?build.version:`${build.version}+${epoch}${sha7===""?"":`.${sha7}`}`,ordinal:[match?Number(match[1]):0,match?Number(match[2]):0,match?Number(match[3]):0,match?.[4]?Number(match[4]):0,epoch],scheme:epoch===0?"nodef":"epoch"}}var BUILT=engineBuildIdentityFrom({version:VERSION,epoch:typeof SENPI_BUILD_EPOCH=="number"?SENPI_BUILD_EPOCH:0,sha7:typeof SENPI_BUILD_SHA7=="string"?SENPI_BUILD_SHA7:""});function engineBuildIdentity(){return BUILT}function compareEngineOrdinal(a,b){for(let index=0;index<4;index++)if(a.ordinal[index]!==b.ordinal[index])return a.ordinal[index]>b.ordinal[index]?1:-1;return a.scheme!=="epoch"||b.scheme!=="epoch"||a.ordinal[4]===b.ordinal[4]?0:a.ordinal[4]>b.ordinal[4]?1:-1}import*as crypto from"node:crypto";var CUSTOM_UNSUPPORTED_CAPABILITY="custom_unsupported",EXTENSION_EVENTS_CAPABILITY="extension_events",EVAL_CELLS_CAPABILITY="eval_cells",AUTO_TITLE_SESSIONS_CAPABILITY="auto_title_sessions",CONTINUE_FROM_LEAF_CAPABILITY="continue_from_leaf",SESSION_HELD_CAPABILITY="session_held",RESUME_SESSION_CAPABILITY="resume_session",ATTENDED_CAPABILITY="attended",MEDIA_PLACEHOLDERS_CAPABILITY="media_placeholders",COMPACT_EVENTS_CAPABILITY="compact_events",QUESTION_CAPABILITY="question",TOOL_BARRIER_CAPABILITY="tool_barrier",SESSION_RELOCATION_CAPABILITY="session_relocation",RETAIN_ON_DISCONNECT_CAPABILITY="retain_on_disconnect",DELEGATED_CONNECTION_CAPABILITY="delegated_connection_v1",DELEGATION_ROLES_CAPABILITY="delegation_roles_v1",RAISER_NOTICE_CAPABILITY="raiser_notice_v1",DETACH_CONNECTION_CAPABILITY="detach_connection",INTERACTIVE_USER_CAPABILITY="interactive_user",OBSERVE_READS_CAPABILITY="observe_reads",ENTRIES_TAIL_CAPABILITY="entries_tail",TUI_OBSERVER_CAPABILITY="tui_observer",TASK_PARENT_CAPABILITY="task_parent",SESSION_CONTEXT_CAPABILITY="session_context",SESSION_KIND_CAPABILITY="session_kind",SESSION_STATUS_CAPABILITY="session_status",AUTO_TITLE_PER_SESSION_CAPABILITY="auto_title_per_session",WARM_CAPABILITY="warm",DURABLE_SESSION_ID_CAPABILITY="durable_session_id",HAND_SELECTION_CAPABILITY="hand_selection",MOVED_PATH_GUARD_CAPABILITY="moved_path_guard",PROMPT_SURFACE_CAPABILITY="prompt_surface",BROWSER_ENGINE_CAPABILITY="browser_engine",SESSION_ENV_CAPABILITY="session_env",RETRY_FALLBACK_PROFILE_CAPABILITY="retry_fallback_profile",RETRY_FALLBACK_COMMAND_CAPABILITY="retry_fallback_command",PROMPT_SURFACE_CHAT_CAPABILITY="prompt_surface_chat",RPC_CLIENT_CAPABILITIES_ENV="SENPI_RPC_CLIENT_CAPABILITIES";function parseClientCapabilities(value){return value?value.split(",").map(part=>part.trim()).filter(part=>part.length>0):[]}var DEFAULT_CUSTOM_EXTENSION_LABEL="custom UI component";function buildCustomUnsupportedRequest(capabilities,extensionName){if(!capabilities?.includes(CUSTOM_UNSUPPORTED_CAPABILITY))return;let name=extensionName.trim()||DEFAULT_CUSTOM_EXTENSION_LABEL;return{type:"extension_ui_request",id:crypto.randomUUID(),method:"custom_unsupported",extensionName:name}}var AUTH_KEY_VERIFY_CAPABILITY="auth_key_verify",PROVIDER_ACCOUNT_TEST_CAPABILITY="provider_account_test",ACCOUNT_RESET_CAPABILITY="account_reset",QUEUED_MESSAGE_REVISION_CAPABILITY="queued_message_revision";import{createHash}from"node:crypto";import{existsSync}from"node:fs";import{readdir,readFile,realpath,stat}from"node:fs/promises";import{basename,dirname,join,relative,sep}from"node:path";import{fileURLToPath}from"node:url";var RUNTIME_IDENTITY_HANDOVER_CAPABILITY="runtime_identity_handover",RUNTIME_BUILD_ID=/^sha256:[0-9a-f]{64}$/,EXCLUDED_FILE=/\.(?:d\.[cm]?ts|map)$/,EXCLUDED_NAMES=new Set(["node_modules","runtime-manifest.json","runtime-snapshot.json"]),READ_CONCURRENCY=32;function parseRuntimeBuildId(value){return typeof value=="string"&&RUNTIME_BUILD_ID.test(value)?value:void 0}async function computeRuntimeBuildId(input){let source=input.source??loadedRuntimeSource(),plugins=await Promise.all(input.profile.extensions.map(path=>extensionDigest(path))),manifest={schema:1,flavour:source.flavour,platform:input.platform??process.platform,arch:input.arch??process.arch,engine:input.engine??engineBuildIdentity().text,runtime:await treeDigest(source.root),plugins:plugins.sort(),profile:{multi_session:input.profile.multi_session,session_runtime:input.profile.session_runtime}};return`sha256:${sha256(JSON.stringify(manifest))}`}function loadedRuntimeSource(){if(isBunBinary)return{flavour:"compiled",root:process.execPath};let moduleDir=dirname(fileURLToPath(import.meta.url)),packageRoot=nearestPackageRoot(moduleDir),[top,next]=relative(packageRoot,moduleDir).split(sep);return top==="dist"?{flavour:"packaged",root:join(packageRoot,next==="bundle"?join("dist","bundle"):"dist")}:{flavour:"dev",root:join(packageRoot,top??"")}}function nearestPackageRoot(start){for(let dir=start;;dir=dirname(dir)){if(existsSync(join(dir,"package.json")))return dir;if(dirname(dir)===dir)return start}}function extensionDigest(path){let name=basename(path);return name.startsWith(BUILTIN_PATH_PREFIX)?Promise.resolve(sha256(name)):treeDigest(path)}async function treeDigest(root){let files=[];(await stat(root)).isFile()?files.push(["",root]):await collect(await realpath(root),"",files,new Set);let digests=await mapLimited(files,READ_CONCURRENCY,async([path,file])=>[path,sha256(await readFile(file))]);return digests.sort(([a],[b])=>a<b?-1:a>b?1:0),sha256(JSON.stringify(digests))}async function collect(dir,prefix,files,seen){if(seen.has(dir))return;seen.add(dir);let entries=(await readdir(dir,{withFileTypes:!0})).sort((a,b)=>a.name<b.name?-1:a.name>b.name?1:0);for(let entry of entries){if(entry.name.startsWith(".")||EXCLUDED_NAMES.has(entry.name))continue;let path=join(dir,entry.name),name=prefix===""?entry.name:`${prefix}/${entry.name}`,kind=entry.isSymbolicLink()?await stat(path).catch(()=>{}):entry;kind!==void 0&&(kind.isDirectory()?await collect(await realpath(path),name,files,seen):kind.isFile()&&!EXCLUDED_FILE.test(entry.name)&&files.push([name,path]))}}async function mapLimited(items,limit,map){let results=new Array(items.length),next=0,worker=async()=>{for(let index=next++;index<items.length;index=next++)results[index]=await map(items[index])};return await Promise.all(Array.from({length:Math.min(limit,items.length)},worker)),results}function sha256(data){return createHash("sha256").update(data).digest("hex")}var STATES=["not_started","ready","unavailable"];function pathIdentityResolverStatus(resolver){let detail=resolver.unavailable;return detail!==void 0?{state:"unavailable",detail}:{state:resolver.snapshot===void 0?"not_started":"ready",detail:null}}function isState(value){return STATES.some(state=>state===value)}function parsePathIdentityResolverStatus(value){if(typeof value!="object"||value===null)return;let{state,detail}=value;if(isState(state))return{state,detail:typeof detail=="string"?detail:null}}function parseHostProtocolInfo(data){if(!isRecord3(data)||typeof data.serverVersion!="string"||!Array.isArray(data.capabilities)||!data.capabilities.every(entry=>typeof entry=="string"))return;let ordinal=parseOrdinal(data.engineOrdinal),launchProfile=parseLaunchProfile(data.launch_profile),runtimeBuildId=parseRuntimeBuildId(data.runtimeBuildId),pathIdentityResolver=parsePathIdentityResolverStatus(data.path_identity_resolver);return{protocolVersion:typeof data.protocolVersion=="number"?data.protocolVersion:0,serverVersion:data.serverVersion,capabilities:data.capabilities,...(data.lifecycle==="ready"||data.lifecycle==="stopping")&&{lifecycle:data.lifecycle},...typeof data.instanceId=="string"&&{instanceId:data.instanceId},...typeof data.generation=="number"&&Number.isSafeInteger(data.generation)&&{generation:data.generation},...typeof data.engineVersion=="string"&&{engineVersion:data.engineVersion},...ordinal&&{engineOrdinal:ordinal},...launchProfile&&{launch_profile:launchProfile},...typeof data.memory_pressure=="boolean"&&{memory_pressure:data.memory_pressure},...pathIdentityResolver!==void 0&&{path_identity_resolver:pathIdentityResolver},...runtimeBuildId!==void 0&&{runtimeBuildId},...typeof data.agentDir=="string"&&data.agentDir!==""&&{agentDir:data.agentDir},...isRecord3(data.handover)&&{handover:data.handover}}}function parseOrdinal(value){if(!(!Array.isArray(value)||value.length!==5||!value.every(part=>typeof part=="number")))return[value[0],value[1],value[2],value[3],value[4]]}function parseLaunchProfile(value){if(!isRecord3(value)||typeof value.profile_id!="string"||!isRecord3(value.core))return;let{extensions,multi_session,session_runtime}=value.core;if(!(!Array.isArray(extensions)||!extensions.every(entry=>typeof entry=="string"))&&typeof multi_session=="boolean"&&!(session_runtime!=="in-process"&&session_runtime!=="worker"))return{profile_id:value.profile_id,core:{extensions,multi_session,session_runtime}}}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function describeHostHolder(holder){let engine=holder.engineVersion===null?"an unrecorded engine":`engine ${holder.engineVersion}`,profile=holder.launchProfileId===null?"":`, launch profile ${holder.launchProfileId}`,writer=holder.writerPid===null||holder.writerPid===holder.pid?"":`, started by pid ${holder.writerPid}`;return`pid ${holder.pid}, ${engine}${profile}${writer}`}var HOST_PROTOCOL_VERSION=1,GENERATION_HANDOFF_CAPABILITY="generation_handoff",ENDPOINT_OWNER_FENCE_CAPABILITY="endpoint_owner_fence",REQUIRED_HOST_CAPABILITIES=["multi_session",EXTENSION_EVENTS_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY],HostEnsureRefusedError=class extends Error{constructor(socket,reason,host,detail,holder){let heldBy=holder?` (held by ${describeHostHolder(holder)})`:"";super(`RPC socket ${socket} refused: ${reason} - ${refusalDetail(reason,host)}${detail?`: ${detail}`:""}${heldBy}`),this.name="HostEnsureRefusedError",this.socket=socket,this.reason=reason,this.detail=detail,this.holder=holder}};function refusalDetail(reason,host){switch(reason){case"protocol":return`the running host speaks protocol version ${host?.protocolVersion??"unknown"}, this build speaks ${HOST_PROTOCOL_VERSION}`;case"capability":{let missing=REQUIRED_HOST_CAPABILITIES.filter(capability=>!host?.capabilities.includes(capability));return`the running host is missing ${JSON.stringify(missing)}; it owns the socket, so no second host is started`}case"foreign_writer":return"another process registered the host on this socket; it accepts connections but did not answer as a host, and this one may not signal it - stop that host explicitly (host stop --force), then ensure again";case"legacy_host":return"a host from before the per-socket daemon directory is still running; it is drained and replaced only while it holds no session, and no second host is started beside it";case"host_busy":return"its socket accepts connections but did not answer inside the probe budget: a live host under load, which is never ended to make room for a replacement";case"host_stopping":return"this generation is stopping; wait for its exit before launching a successor";case"endpoint_occupied":return"another process accepts connections on this socket but does not answer as a host, and no host registration names it; it is never removed while it listens, so quit the process holding it and ensure again";case"host_stalled":return"nothing reaches its socket, but its process is alive and its own loop-lag watchdog measured a recent stall: a stalled host is still serving its sessions, so it is neither stopped nor replaced";default:return assertNever(reason)}}function decideHostAction(client,host,policy){if(host===void 0)return{action:"start",reason:client.startedByUs?"restart_own_host":"no_host",upgradeable:!1};if(host.lifecycle==="stopping")return{action:"refuse",reason:"host_stopping",upgradeable:!1};if(host.protocolVersion!==client.protocolVersion)return{action:"refuse",reason:"protocol",upgradeable:!1};if(!client.requiredCapabilities.every(capability=>host.capabilities.includes(capability)))return policy==="fallback"?{action:"fallback",reason:"capability",upgradeable:!1}:{action:"refuse",reason:"capability",upgradeable:!1};let upgradeable=client.platform!=="win32"&&host.capabilities.includes(GENERATION_HANDOFF_CAPABILITY);if(policy==="fallback"&&host.engineVersion!==client.identity.text)return{action:"fallback",reason:"engine_mismatch",upgradeable};let warning=profileWarning(client,host);return client.platform==="win32"?{action:"reuse",reason:"win32_attach_only",upgradeable:!1,...warning&&{warning}}:upgradeable?policy==="upgrade"&&client.launchProfile&&host.launch_profile&&supersedes(client,host)?{action:"handoff",reason:sameRelease(client.identity.ordinal,host.engineOrdinal)?"profile":"newer_engine",upgradeable:!0}:{action:"reuse",reason:"compatible",upgradeable,...warning&&{warning}}:{action:"reuse",reason:"handoff_unsupported",upgradeable:!1,...warning&&{warning}}}function supersedes(client,host){if(host.engineOrdinal===void 0)return!1;let hostIdentity={text:host.engineVersion??"",ordinal:host.engineOrdinal,scheme:host.engineOrdinal[4]>0?"epoch":"nodef"};return compareEngineOrdinal(client.identity,hostIdentity)<=0?!1:covers(client.launchProfile,host.launch_profile)}function profileWarning(client,host){if(client.launchProfile===void 0||host.launch_profile===void 0)return"profile_mismatch_attached";if(client.launchProfile.profile_id===host.launch_profile.profile_id)return;let clientCoversHost=covers(client.launchProfile,host.launch_profile);if(!(clientCoversHost&&covers(host.launch_profile,client.launchProfile)))return clientCoversHost?"profile_mismatch_attached":"profile_narrower_attached"}function extensionRole(extension){let segments=extension.split(/[\\/]+/),pluginAt=segments.lastIndexOf("plugin");return pluginAt<0?extension:segments.slice(pluginAt).join("/")}function covers(candidate,running){if(candidate===void 0||running===void 0)return!1;let candidateRoles=new Set(candidate.core.extensions.map(extensionRole));return running.core.extensions.every(extension=>candidateRoles.has(extensionRole(extension)))}function sameRelease(candidate,running){return running!==void 0&&candidate.slice(0,4).every((part,index)=>part===running[index])}function assertNever(value){throw new Error(`unreachable host decision: ${JSON.stringify(value)}`)}import{createHash as createHash3,randomUUID as randomUUID2}from"node:crypto";import{resolve}from"node:path";import{createHash as createHash2}from"node:crypto";var RPC_METHOD_CLASSES_VERSION=1,DYNAMIC="dynamic",ENTRY_AUTHORSHIP={message:"user_role_only",thinking_level_change:"engine",configuration_update:"engine",model_change:"engine",model_change_rejected:"engine",usage:"engine",compaction:"engine",branch_summary:"engine",custom:"engine",custom_message:"engine",context_edit:"engine",label:"engine",session_info:"engine"},USER_ROLE="user";function appendEntryClass(record){let entry=Reflect.get(record,"entry");if(typeof entry!="object"||entry===null)return"device_admin";let entryType=Reflect.get(entry,"type");if(typeof entryType!="string"||!Object.hasOwn(ENTRY_AUTHORSHIP,entryType)||ENTRY_AUTHORSHIP[entryType]!=="user_role_only")return"device_admin";let message=Reflect.get(entry,"message");return typeof message!="object"||message===null?"device_admin":Reflect.get(message,"role")===USER_ROLE?"drive":"device_admin"}function namesAny(record,fields){return fields.some(field=>Object.hasOwn(record,field)&&Reflect.get(record,field)!==void 0)}function openSessionClass(record){return namesAny(record,["sessionPath","cwd","permissionPreset","browserEngine","env"])?"device_admin":"thread"}function thinkingLevelClass(record){return Reflect.get(record,"scope")==="turn"?"drive":"device_admin"}function setModelClass(record){return Reflect.get(record,"scope")==="session"?"drive":"device_admin"}function effectStatusClass(record){return namesAny(record,["sessionPath"])?"device_admin":"observe"}function promptClass(record){let message=Reflect.get(record,"message");return typeof message!="string"?"device_admin":Reflect.get(record,"expandPromptTemplates")===!1?"drive":message.startsWith("/")?"device_admin":"drive"}function idleStartClass(record){if(Reflect.get(record,"whenIdle")!=="start")return"drive";let message=Reflect.get(record,"message");return typeof message!="string"||message.startsWith("/")?"device_admin":"drive"}function newSessionClass(record){return namesAny(record,["parentSession"])?"device_admin":"thread"}var RPC_METHOD_CLASS={get_protocol_info:"observe",get_subscription_limits:"observe",list_sessions:"observe",list_hands:"observe",get_state:"observe",get_snapshot:"observe",get_entries:"observe",get_messages:"observe",get_tree:"observe",get_fork_messages:"observe",get_last_assistant_text:"observe",get_session_stats:"observe",get_effect_status:{classify:effectStatusClass,version:1},get_pending_inputs:"observe",get_follow_up_messages:"observe",get_steering_messages:"observe",get_commands:"observe",get_loaded_surfaces:"observe",get_project_trust:"observe",get_available_models:"observe",get_available_thinking_levels:"observe",get_model_thinking_level:"observe",get_fast_mode:"observe",get_media:"observe",memory_report:"observe","eval_cells.list":"observe","eval_cells.peek":"observe",prompt:{classify:promptClass,version:1},steer:{classify:idleStartClass,version:1},follow_up:{classify:idleStartClass,version:1},abort:"drive",interrupt:"drive",abort_retry:"drive",abort_compaction:"drive",abort_branch_summary:"drive",compact:"drive",clear_queue:"drive",dequeue_message:"drive",edit_queued_message:"drive",hold_input:"drive",withdraw_held_input:"drive",append_user_message:"drive",edit_user_message:"drive",continue_from_leaf:"drive",navigate_tree:"drive",set_label:"drive",set_session_name:"drive",set_thinking_level:{classify:thinkingLevelClass,version:1},set_model:{classify:setModelClass,version:1},set_auto_compaction:"drive",set_permission_preset:"device_admin",set_retry_fallback:"drive",pause_for_run:"drive",resume_for_run:"drive",wake:"drive",admit_external_message:"drive",release_tool_barrier:"drive",request_self_settle:"drive","eval_cells.stop":"drive",append_session_entry:{classify:appendEntryClass,version:1},extension_ui_response:"answer",extension_ui_progress:"answer",new_session:{classify:newSessionClass,version:1},open_session:{classify:openSessionClass,version:2},resume_session:"thread",fork:"thread",clone:"thread",close_session:"thread",unload_session:"thread",set_session_context:"thread",attach_session:"thread",select_hand:"device_admin",bash:"device_admin",abort_bash:"device_admin",record_bash_result:"device_admin",cleanup_bash_output:"device_admin",extension_request:"device_admin",reload:"device_admin",check_reload_veto:"device_admin",resolve_path:"device_admin",login_start:"device_admin",login_cancel:"device_admin",login_api_key:"device_admin",logout:"device_admin",verify_api_key:"device_admin",get_auth_providers:"device_admin",get_provider_accounts:"device_admin",account_order:"device_admin",account_pin:"device_admin",account_remove:"device_admin",account_reset:"device_admin",test_provider_account:"device_admin",set_favorite_models:"device_admin",set_scoped_models:"device_admin",cycle_model:"device_admin",cycle_thinking_level:"device_admin",set_fast_mode:"device_admin",set_steering_mode:"device_admin",set_follow_up_mode:"device_admin",set_auto_retry:"device_admin",set_project_trust:"device_admin",get_project_settings:"device_admin",set_project_setting:"device_admin",edit_assistant_message:"device_admin",send_custom_message:"device_admin",switch_session:"device_admin",import_jsonl:"device_admin",export_html:"device_admin",export_jsonl:"device_admin",set_client_info:"connection_local",subscribe_sessions:"connection_local",unsubscribe_sessions:"connection_local",record_user_activity:"connection_local",detach_connection:"connection_local",release_session:"connection_local",warm:"connection_local",host_response:"connection_local",release_attachment:"connection_local",reclaim_session:"connection_local",move_session:"connection_local",get_recovery_page:"connection_local",release_recovery:"connection_local",cancel_attempt:"connection_local",reset_stream:"connection_local"};function classifyRpcMethod(record){if(!(typeof record!="object"||record===null||Array.isArray(record)))try{let type=Reflect.get(record,"type");if(typeof type!="string"||!Object.hasOwn(RPC_METHOD_CLASS,type))return;let entry=RPC_METHOD_CLASS[type];return typeof entry=="string"?entry:entry.classify(record)}catch{return}}function rpcMethodClassesDigest(table){let lines=Object.entries(table).map(([type,methodClass])=>`${type}=${methodClass}
|
|
3
3
|
`).sort();return createHash2("sha256").update(lines.join("")).digest("hex")}function digestValue(entry){return typeof entry=="string"?entry:`${DYNAMIC}@${entry.version}`}var RPC_METHOD_CLASSES_DIGEST=rpcMethodClassesDigest(Object.fromEntries(Object.entries(RPC_METHOD_CLASS).map(([type,entry])=>[type,digestValue(entry)])));function describeRpcMethodClasses(){let classes={},dynamicVersions={};for(let[type,entry]of Object.entries(RPC_METHOD_CLASS))typeof entry=="string"?classes[type]=entry:(classes[type]=DYNAMIC,dynamicVersions[type]=entry.version);return{version:RPC_METHOD_CLASSES_VERSION,digest:RPC_METHOD_CLASSES_DIGEST,classes,dynamic_versions:dynamicVersions}}var INSTANCE_ID=resolveInstanceId(process.env[HOST_INSTANCE_ID_ENV]);function resolveInstanceId(value){return value!==void 0&&value.trim()!==""?value:randomUUID2()}function hostInstanceId(){return INSTANCE_ID}var cachedProfile;function hostGeneration(env){let value=env[HOST_GENERATION_ENV];return value!==void 0&&/^\d+$/.test(value)?Number(value):0}function hostLaunchProfile(argv,cwd){let parsed=parseArgs([...argv],{grokNeoEnabled:!1}),core={extensions:[...new Set((parsed.extensions??[]).map(path=>resolve(cwd,path)))].sort(),multi_session:parsed.multiSession===!0,session_runtime:resolveSessionRuntime(parsed)},canonical=JSON.stringify({extensions:core.extensions,multi_session:core.multi_session,session_runtime:core.session_runtime});return{profile_id:createHash3("sha256").update(canonical).digest("hex"),core}}function socketHostLaunchProfile(hostArgs,cwd){return hostLaunchProfile(["--mode","rpc","--multi-session","--listen","unix://",...hostArgs],cwd)}function protocolIdentity(agentDir=resolve(getAgentDir())){cachedProfile??=hostLaunchProfile(process.argv.slice(2),process.cwd());let build=engineBuildIdentity();return{instanceId:INSTANCE_ID,generation:hostGeneration(process.env),engineVersion:build.text,engineOrdinal:build.ordinal,launch_profile:cachedProfile,agentDir,method_classes:describeRpcMethodClasses()}}function holdAttachment(socket){return socket.removeAllListeners("data"),socket.resume(),socket.on("error",()=>socket.destroy()),socket.unref(),{release:()=>socket.destroy()}}var DEFAULT_PROBE_TIMEOUT_MS=1e4;function probeHost(options){return probeProtocolInfo(options.socket,options.timeoutMs??DEFAULT_PROBE_TIMEOUT_MS,options)}async function probeProtocolInfo(socketPath,timeoutMs,options={}){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info"},timeoutMs,options);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function observeProtocolInfo(socketPath,timeoutMs,options={}){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info",[OBSERVE_REQUEST_FIELD]:!0},timeoutMs,options);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function holdProtocolInfo(socketPath,timeoutMs,options={}){let outcome=await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs,!0,options),info=outcome.answer===void 0?void 0:parseHostProtocolInfo(outcome.answer);if(outcome.kept===void 0)return;let hold=holdAttachment(outcome.kept);if(info!==void 0)return{info,hold};hold.release()}async function probeSocketReachable(socketPath,timeoutMs,options={}){return(await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs,!1,options)).connected}async function probeSessionCount(socketPath,timeoutMs,options={}){return sessionCountOf(await requestOnSocket(socketPath,{type:"list_sessions",include_workers:!0},timeoutMs,options))}async function holdSessionCount(socketPath,timeoutMs,options={}){let outcome=await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"list_sessions",include_workers:!0},timeoutMs,!0,options),kept=outcome.kept;if(kept===void 0)return;let sessions=sessionCountOf(outcome.answer);if(sessions===void 0){kept.destroy();return}let asked=0;return{sessions,recount:recountTimeoutMs=>askAgain(kept,`${PROBE_REQUEST_ID}-recount-${++asked}`,recountTimeoutMs),close:()=>kept.destroy()}}function askAgain(socket,id,timeoutMs){return new Promise(resolveCount=>{let buffer="",finish=count=>{clearTimeout(timeout),socket.off("data",onData),socket.off("close",onClose),resolveCount(count)},onClose=()=>finish(void 0),onData=chunk=>{buffer+=chunk.toString("utf8");for(let newline=buffer.indexOf(`
|
|
4
4
|
`);newline!==-1;newline=buffer.indexOf(`
|
|
5
5
|
`)){let answer=readAnswer(buffer.slice(0,newline),id);if(buffer=buffer.slice(newline+1),answer!==void 0){finish(sessionCountOf(answer));return}}},timeout=setTimeout(()=>finish(void 0),timeoutMs);if(socket.destroyed){finish(void 0);return}socket.on("data",onData),socket.once("close",onClose),socket.write(`${JSON.stringify({id,type:"list_sessions",include_workers:!0})}
|