@code-yeongyu/senpi 2026.10.4 → 2026.10.5
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 +20 -0
- package/dist/bundle/chunks/{anthropic-messages-GE4OCV55.js → anthropic-messages-G5236QNK.js} +1 -1
- package/dist/bundle/chunks/{app-server-command-I2AKSC6I.js → app-server-command-3Q5G4CAF.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CS2GZBE.js → chunk-2WV426OJ.js} +2 -2
- package/dist/bundle/chunks/{chunk-INGR4HFB.js → chunk-ECDLITEY.js} +2 -2
- package/dist/bundle/chunks/{chunk-6O26XO2C.js → chunk-EEOKVSNF.js} +220 -252
- package/dist/bundle/chunks/{chunk-MNLBL232.js → chunk-JVSOW4QU.js} +1 -1
- package/dist/bundle/chunks/chunk-K3BXFPWZ.js +2 -0
- package/dist/bundle/chunks/{chunk-QOT4HXY2.js → chunk-UHRXXTFZ.js} +3 -3
- package/dist/bundle/chunks/chunk-UUAKEDVS.js +14 -0
- package/dist/bundle/chunks/{chunk-ZKLQIAG5.js → chunk-UXIQK5NQ.js} +1 -1
- package/dist/bundle/chunks/chunk-WTJU5B2C.js +51 -0
- package/dist/bundle/chunks/chunk-YSPHACIN.js +2 -0
- package/dist/bundle/chunks/{cli-main-BLXUYHLQ.js → cli-main-VZWSUHFB.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-TQWU6DPG.js → help-fast-path-SHZJ3QWQ.js} +1 -1
- package/dist/bundle/chunks/{host-command-JXNOYPAC.js → host-command-7JIGGOWR.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-CSVSUAS7.js → interactive-mode-JA7AHYYL.js} +1 -1
- package/dist/bundle/chunks/multi-session-host-34WOINP4.js +23 -0
- package/dist/bundle/chunks/{openai-completions-2DUKDEVN.js → openai-completions-VSH22FCN.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-WCB4HIPI.js → openai-responses-WLBHCFYL.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-Q5EQZL7I.js → package-manager-cli-2QLVGQSC.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-VZLJIEP5.js → rotation-stream-JUCEXHWU.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-6VMXY46C.js → rpc-mode-QEBSN2OH.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-K3RWX652.js → session-control-endpoint-UGQIP6ZN.js} +1 -1
- package/dist/bundle/chunks/{session-picker-IPG3MKRC.js → session-picker-HX4LOJZ7.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +251 -242
- package/dist/bundle/cli.js +1 -1
- 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-runtime.d.ts +5 -0
- package/dist/core/agent-session-runtime.js +5 -0
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session.d.ts +14 -0
- package/dist/core/agent-session.js +31 -0
- package/dist/core/browser-engine.d.ts +7 -0
- package/dist/core/browser-engine.js +7 -0
- package/dist/core/continue-from-leaf.d.ts +18 -0
- package/dist/core/continue-from-leaf.js +30 -0
- package/dist/core/extensions/builtin/gpt-apply-patch/line-endings.d.ts +28 -0
- package/dist/core/extensions/builtin/gpt-apply-patch/line-endings.js +76 -0
- package/dist/core/extensions/builtin/gpt-apply-patch/parser.js +21 -23
- package/dist/core/extensions/builtin/gpt-apply-patch/patch-replace.js +5 -16
- package/dist/core/extensions/builtin/gpt-apply-patch/streaming-parser.js +3 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/text.d.ts +8 -0
- package/dist/core/extensions/builtin/gpt-apply-patch/text.js +26 -3
- package/dist/core/extensions/builtin/gpt-apply-patch/types.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +1 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.js +8 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/types.d.ts +4 -0
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/sdk.d.ts +3 -0
- package/dist/core/sdk.js +1 -0
- package/dist/core/tools/bash.js +3 -0
- package/dist/main.js +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +11 -0
- package/dist/modes/interactive/components/session-selector.js +30 -5
- package/dist/modes/rpc/connection-handler.js +18 -1
- package/dist/modes/rpc/custom-capability.d.ts +9 -0
- package/dist/modes/rpc/custom-capability.js +9 -0
- package/dist/modes/rpc/host-daemon-env.js +2 -0
- package/dist/modes/rpc/host-idle-handover.js +1 -0
- package/dist/modes/rpc/media-placeholders.d.ts +23 -1
- package/dist/modes/rpc/media-placeholders.js +16 -13
- package/dist/modes/rpc/rpc-client.d.ts +8 -0
- package/dist/modes/rpc/rpc-client.js +8 -0
- package/dist/modes/rpc/rpc-input-validation.d.ts +6 -0
- package/dist/modes/rpc/rpc-input-validation.js +11 -0
- package/dist/modes/rpc/rpc-types.d.ts +19 -0
- package/dist/modes/rpc/session-command-router.js +11 -2
- package/dist/modes/rpc/session-event-writer.d.ts +4 -0
- package/dist/modes/rpc/session-event-writer.js +12 -1
- package/dist/modes/rpc/session-registry-attach.js +4 -0
- package/dist/modes/rpc/session-worker-client.d.ts +3 -0
- package/dist/modes/rpc/session-worker-client.js +6 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +5 -0
- package/dist/modes/rpc/session-worker.js +6 -0
- package/dist/modes/rpc/tool-media-store.d.ts +59 -0
- package/dist/modes/rpc/tool-media-store.js +190 -0
- package/dist/modes/rpc/worker-session-registry.js +8 -3
- package/docs/environment-variables.md +1 -0
- package/docs/rpc.md +62 -3
- package/package.json +7 -6
- package/dist/bundle/chunks/chunk-KMMECBM2.js +0 -15
- package/dist/bundle/chunks/chunk-LHYG7TK7.js +0 -2
- package/dist/bundle/chunks/chunk-LJWC5IVX.js +0 -2
- package/dist/bundle/chunks/chunk-PC3E2YS6.js +0 -9
- package/dist/bundle/chunks/multi-session-host-5AFJKSSM.js +0 -23
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,26 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.10.5] - 2026-10-03
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `open_session` accepts `browserEngine` (`connected`, `builtin` or `none`) and hosts advertise the `browser_engine` capability: the choice is per session, so that session's tool subprocesses and eval kernels see `OMO_BROWSER_ENGINE` and no other session does, a reattach moves or keeps it, and `BSK_HOME` / `BSK_BIN` pass through unchanged ([#2611](https://github.com/code-yeongyu/senpi/issues/2611)).
|
|
22
|
+
- A `media_placeholders` client now gets an `image_ref` placeholder whose `path` names the stored image (written before the placeholder is emitted under the session's `media/<durableSessionId>/` directory, private and read-only, deleted with the session), or an `unavailableReason` of `image_too_large`, `session_limit` or `storage_error`, so tool images other than `read` can be rendered from disk.
|
|
23
|
+
- An edited assistant response can be continued with no new prompt: the RPC `continue_from_leaf` command (advertised as the `continue_from_leaf` capability) starts a turn from the session leaf through a hidden nudge the transcript never shows, refusing with `streaming`, `nothing_to_continue`, or `leaf_not_assistant` (the conversation ends on a user message). `get_available_models` rows report `supportsAssistantPrefill` (false for every model today) ([#1930](https://github.com/code-yeongyu/senpi/issues/1930)).
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `nvidia` starts on a model its catalog still has: the v2026.10.4 catalog no longer lists `nvidia/nemotron-3-super-120b-a12b`, so an NVIDIA-only user without a saved model silently started on the catalog's first entry (`deepseek-ai/deepseek-v4.1-flash`) instead of the provider default. The default is now `nvidia/nemotron-3-ultra-550b-a55b`, and a release now stops when a catalog regeneration drops any bundled provider's default ([#2645](https://github.com/code-yeongyu/senpi/issues/2645)).
|
|
30
|
+
- `apply_patch` keeps each line's ending when it updates a file: CRLF and mixed-ending files are no longer rewritten to LF, inserted lines take the file's line ending, and context lines stay exactly as they were, so a one-line change is a one-line diff ([#2638](https://github.com/code-yeongyu/senpi/issues/2638)).
|
|
31
|
+
- `apply_patch` no longer drops a file section whose header is indented while reporting success: indented headers apply as in Codex, any other line between file sections rejects the patch before anything changes, and the permission system's per-file approval lists exactly the files the patch writes ([#2636](https://github.com/code-yeongyu/senpi/issues/2636)).
|
|
32
|
+
|
|
33
|
+
### Removed
|
|
34
|
+
|
|
15
35
|
## [2026.10.4] - 2026-10-03
|
|
16
36
|
|
|
17
37
|
### Breaking Changes
|
package/dist/bundle/chunks/{anthropic-messages-GE4OCV55.js → anthropic-messages-G5236QNK.js}
RENAMED
|
@@ -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{normalizeToolCallId}from"./chunk-D6PV4KQK.js";import{resolveCloudflareBaseUrl}from"./chunk-OZNCR6E6.js";import{anthropicProviderDiagnosticFromError,anthropicProviderDiagnosticFromSseData,awaitProviderTransport,formatGitHubCopilotToolLimitError,limitGitHubCopilotTools,recordGitHubCopilotToolLimit,withGitHubCopilotFailureNote}from"./chunk-U7CI2JGX.js";import{getPiUserAgent}from"./chunk-QTG7MY2X.js";import{combineAbortSignals}from"./chunk-SJ5DSOBX.js";import{ANTHROPIC_RESERVED_BODY_KEYS,adjustMaxTokensForThinking,buildBaseOptions,clampMaxTokensToContext}from"./chunk-4Q6OS7LB.js";import{retryProviderRequest}from"./chunk-KLBKUBDV.js";import{claudeCodeVersionTooOldHint,getClaudeCodeVersion,isClaudeCodeVersionTooOldError,recoverClaudeCodeVersion,resolveToolNameMatch}from"./chunk-JRGNL6WM.js";import{ANTHROPIC_FEDERATION_RULE_ID_ENV,ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,ANTHROPIC_ORGANIZATION_ID_ENV,ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,ANTHROPIC_WORKSPACE_ID_ENV,applyServerFallbackAbort,applyServerFallbackContinuation,parseServerFallbackReceipt,parseStickyFallbackReceipt,sanitizeAnthropicToolPairs}from"./chunk-RKJNJ3GI.js";import{resolveRootObjectSchema}from"./chunk-CWLCGRUS.js";import{getAnthropicCompat,isAnthropicApiBaseUrl}from"./chunk-6WCOSBI7.js";import{sendWithForcedToolChoiceFallback}from"./chunk-
|
|
2
|
+
import{normalizeToolCallId}from"./chunk-D6PV4KQK.js";import{resolveCloudflareBaseUrl}from"./chunk-OZNCR6E6.js";import{anthropicProviderDiagnosticFromError,anthropicProviderDiagnosticFromSseData,awaitProviderTransport,formatGitHubCopilotToolLimitError,limitGitHubCopilotTools,recordGitHubCopilotToolLimit,withGitHubCopilotFailureNote}from"./chunk-U7CI2JGX.js";import{getPiUserAgent}from"./chunk-QTG7MY2X.js";import{combineAbortSignals}from"./chunk-SJ5DSOBX.js";import{ANTHROPIC_RESERVED_BODY_KEYS,adjustMaxTokensForThinking,buildBaseOptions,clampMaxTokensToContext}from"./chunk-4Q6OS7LB.js";import{retryProviderRequest}from"./chunk-KLBKUBDV.js";import{claudeCodeVersionTooOldHint,getClaudeCodeVersion,isClaudeCodeVersionTooOldError,recoverClaudeCodeVersion,resolveToolNameMatch}from"./chunk-JRGNL6WM.js";import{ANTHROPIC_FEDERATION_RULE_ID_ENV,ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,ANTHROPIC_ORGANIZATION_ID_ENV,ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,ANTHROPIC_WORKSPACE_ID_ENV,applyServerFallbackAbort,applyServerFallbackContinuation,parseServerFallbackReceipt,parseStickyFallbackReceipt,sanitizeAnthropicToolPairs}from"./chunk-RKJNJ3GI.js";import{resolveRootObjectSchema}from"./chunk-CWLCGRUS.js";import{getAnthropicCompat,isAnthropicApiBaseUrl}from"./chunk-6WCOSBI7.js";import{sendWithForcedToolChoiceFallback}from"./chunk-YSPHACIN.js";import{buildCopilotDynamicHeaders,hasCopilotVisionInput}from"./chunk-KRNXUTZJ.js";import{readProviderDiagnostic}from"./chunk-YOPVJDSU.js";import{registerSessionResourceCleanup}from"./chunk-WHPDEDCC.js";import{splitDeferredTools}from"./chunk-HK46JMSC.js";import{getJsonSchemaToolParameters,isVideoMimeType,resolveJsonSchemaStrictSampling,transformMessages}from"./chunk-2WEI2XTZ.js";import{sanitizeSurrogates}from"./chunk-WDTJ6JKE.js";import{getProviderEnvValue}from"./chunk-5ROMKDLK.js";import{parseJsonWithRepair,parseStreamingJson}from"./chunk-3W47LTXQ.js";import{attachProviderDiagnostic}from"./chunk-45SZOLCU.js";import"./chunk-BBK6SSYT.js";import{appendRetryAfterMsMarker,extract429RetryAfterMs}from"./chunk-BPX6QWPD.js";import{calculateCost,getCurrentTools,getDeclaredTools,getInitialSystemMessage,getSystemMessageText,hasToolRedefinitions,normalizeContext,renderSystemMessageUpdate,resolveTranscript}from"./chunk-XL5KIYQF.js";import{AssistantMessageEventStream,appendAssistantMessageDiagnostic}from"./chunk-DMI55M2N.js";import{headersToRecord,providerHeadersToRecord}from"./chunk-PJ34QVL5.js";import{Anthropic}from"./chunk-PUTWVHNH.js";import"./chunk-IKOFCODM.js";var MAX_MESSAGE_CHARS=500,QUOTA_WORDING_PATTERN=/exceeded_current_quota_error|insufficient\s+balance|credits?_required|quota|billing/i,IMAGE_FORMAT_PATTERN=/unsupported image format|unsupported media type for base64 image|invalid data url for image/i;function sdkErrorClassName(error){if(!(error instanceof Error))return;let name=error.constructor?.name;return typeof name=="string"&&name.length>0?name:void 0}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function toShaped(error){return error instanceof Error?error:void 0}function numericStatus(shaped){let status=shaped?.status;return typeof status=="number"&&Number.isFinite(status)?status:void 0}function headerObject(shaped){return shaped?.headers instanceof Headers?shaped.headers:void 0}function nestedProviderCodes(body){if(!isRecord(body))return;let inner=body.error;if(!isRecord(inner))return;let codes=[];for(let key of["type","code"]){let value=inner[key];typeof value=="string"&&value.length>0&&codes.push(value)}return codes.length>0?codes:void 0}function parseLeadingJson(text){let candidate=text.slice(text.indexOf("{"),text.lastIndexOf("}")+1);if(!(!candidate.startsWith("{")||!candidate.endsWith("}")))try{return JSON.parse(candidate)}catch{return}}function quotaWording(shaped,bodyText){return[shaped?.message,bodyText].some(text=>typeof text=="string"&"A_WORDING_PATTERN.test(text))}function normalizeAnthropicRetryFailure(error,context){let message=error instanceof Error?error.message:String(error),shaped=toShaped(error),status=numericStatus(shaped),headers=headerObject(shaped),bodyText=context?.bodyText??message,kind,providerCodes;if(error instanceof Error&&error.name==="AbortError")kind="abort";else if(sdkErrorClassName(error)==="APIConnectionTimeoutError")kind="timeout";else if(sdkErrorClassName(error)==="APIConnectionError")kind="connection";else if(typeof message=="string"&&IMAGE_FORMAT_PATTERN.test(message))kind="image-format";else if(status!==void 0)kind=status===429&"aWording(shaped,bodyText)?"quota-exhausted":"http-status",providerCodes=nestedProviderCodes(shaped?.error);else{let parsed=parseLeadingJson(bodyText);providerCodes=nestedProviderCodes(parsed),kind=providerCodes!==void 0?"provider":"unknown"}let retryAfterMs=extract429RetryAfterMs({status,headers,bodyText}),shouldRetryHeader=headers?.get("x-should-retry"),shouldRetry=shouldRetryHeader==="true"?!0:shouldRetryHeader==="false"?!1:void 0;return{origin:"anthropic-messages",kind,message:message.slice(0,MAX_MESSAGE_CHARS),...status!==void 0?{statusCode:status}:{},...providerCodes!==void 0?{providerCodes}:{},...retryAfterMs!==void 0?{retryAfterMs}:{},...shouldRetry!==void 0?{shouldRetry}:{}}}function escapeXmlAttribute(value){return value.replaceAll("&","&").replaceAll('"',""").replaceAll("'","'").replaceAll("<","<").replaceAll(">",">")}function availableToolGuidance(availableToolNames){if(availableToolNames.length===0)return"To edit files, call only tools available in this request.";let listed=availableToolNames.slice(0,8).join(", "),omitted=availableToolNames.length-8,suffix=omitted>0?` (and ${omitted} more)`:"";return`To edit files, call your own tools: ${listed}${suffix}.`}function demotedToolCallText(name,availableToolNames,firstOccurrence){let escapedName=escapeXmlAttribute(name);return firstOccurrence?[`<unavailable-tool-call name="${escapedName}">`,"Transcript record, not an action available to you. An earlier model in this session",`called "${escapedName}"; that tool does not exist for you and its input is omitted.`,availableToolGuidance(availableToolNames),"</unavailable-tool-call>"].join(`
|
|
3
3
|
`):`<unavailable-tool-call name="${escapedName}"/>`}function demotedToolResultText(name,content){let escapedName=escapeXmlAttribute(name),safeContent=content.replace(/<\/unavailable-tool-result/gi,match=>`<${match.slice(1)}`);return`<unavailable-tool-result name="${escapedName}">${safeContent}</unavailable-tool-result>`}function isRecord2(value){return typeof value=="object"&&value!==null}function collectAvailableToolNames(tools){let defined=new Set;if(Array.isArray(tools))for(let tool of tools)isRecord2(tool)&&typeof tool.name=="string"&&defined.add(tool.name);return defined}function isNativeToolSearchResultBlock(block){return isRecord2(block)&&block.type==="tool_search_tool_result"&&typeof block.tool_use_id=="string"&&isRecord2(block.content)&&Array.isArray(block.content.tool_references)}function demoteUnavailableToolReferences(params){let messages=params.messages;if(!Array.isArray(messages)||messages.length===0)return params;let available=collectAvailableToolNames(params.tools),resolve=name=>resolveToolNameMatch(name,available),demotedCallNames=new Map,renamedCallNames=new Map;for(let message of messages)if(!(message.role!=="assistant"||!Array.isArray(message.content)))for(let block of message.content){if(!isRecord2(block)||block.type!=="tool_use"||typeof block.name!="string")continue;let resolved=resolve(block.name);resolved===void 0?demotedCallNames.set(block.id,block.name):resolved!==block.name&&renamedCallNames.set(block.id,resolved)}let changed=!1,availableToolNames=[...available],seenDemotedCallNames=new Set,rewrittenMessages=[];for(let message of messages){if(!Array.isArray(message.content)){rewrittenMessages.push(message);continue}let messageChanged=!1,droppedSearchUseIds=new Set,droppedSearchNames=new Map;if(message.role==="assistant")for(let block of message.content){if(!isNativeToolSearchResultBlock(block))continue;let names=block.content.tool_references.filter(item=>isRecord2(item)&&item.type==="tool_reference").map(item=>typeof item.tool_name=="string"?item.tool_name:"");names.length>0&&names.every(name=>resolve(name)===void 0)&&(droppedSearchUseIds.add(block.tool_use_id),droppedSearchNames.set(block.tool_use_id,names))}let content=[];for(let block of message.content){if(message.role==="assistant"&&isRecord2(block)&&block.type==="tool_use"){let demotedName=demotedCallNames.get(block.id);if(demotedName!==void 0){messageChanged=!0;let firstOccurrence=!seenDemotedCallNames.has(demotedName);seenDemotedCallNames.add(demotedName),content.push({type:"text",text:demotedToolCallText(demotedName,availableToolNames,firstOccurrence)});continue}let renamedName=renamedCallNames.get(block.id);if(renamedName!==void 0){messageChanged=!0,content.push({...block,name:renamedName});continue}}if(message.role==="assistant"&&isRecord2(block)&&block.type==="server_tool_use"&&typeof block.id=="string"&&droppedSearchUseIds.has(block.id)){messageChanged=!0;continue}if(message.role==="assistant"&&isNativeToolSearchResultBlock(block)){let omitted=droppedSearchNames.get(block.tool_use_id);if(omitted!==void 0){messageChanged=!0,content.push({type:"text",text:`Tool reference unavailable: ${[...new Set(omitted)].join(", ")}`});continue}let rewritten=rewriteToolReferenceItems(block.content.tool_references,resolve);if(rewritten!==void 0){messageChanged=!0,content.push({...block,content:{...block.content,tool_references:rewritten.kept}});continue}}if(isRecord2(block)&&block.type==="tool_result"){let demotedName=demotedCallNames.get(block.tool_use_id);if(demotedName!==void 0){messageChanged=!0,content.push({type:"text",text:demotedToolResultText(demotedName,toolResultText(block.content))});continue}if(Array.isArray(block.content)){let rewritten=rewriteToolReferenceItems(block.content,resolve);if(rewritten!==void 0){messageChanged=!0;let nextContent=rewritten.kept.length>0?rewritten.kept:[{type:"text",text:`Tool reference unavailable: ${[...new Set(rewritten.omitted)].join(", ")}`}];content.push({...block,content:nextContent});continue}}}content.push(block)}if(content.length===0){changed=!0;continue}if(messageChanged){changed=!0,rewrittenMessages.push({...message,content});continue}rewrittenMessages.push(message)}return changed?{...params,messages:rewrittenMessages}:params}function demoteToolReferenceReplay(params){let messages=params.messages;if(!Array.isArray(messages)||messages.length===0)return params;let searchUseIds=new Set;for(let message of messages)if(!(message.role!=="assistant"||!Array.isArray(message.content)))for(let block of message.content)isRecord2(block)&&block.type==="tool_search_tool_result"&&typeof block.tool_use_id=="string"&&searchUseIds.add(block.tool_use_id);let changed=!1,demotedNames=new Set,rewrittenMessages=[];for(let message of messages){if(!Array.isArray(message.content)){rewrittenMessages.push(message);continue}let messageChanged=!1,content=[];for(let block of message.content){if(message.role==="assistant"&&isRecord2(block)){if(block.type==="server_tool_use"&&typeof block.id=="string"&&searchUseIds.has(block.id)){messageChanged=!0;continue}if(block.type==="tool_search_tool_result"){messageChanged=!0;let names=isNativeToolSearchResultBlock(block)?toolReferenceNames(block.content.tool_references):[];for(let name of names)demotedNames.add(name);content.push({type:"text",text:names.length>0?`Tool search found: ${names.join(", ")}`:"Tool search found no tools."});continue}}if(isRecord2(block)&&block.type==="tool_result"&&Array.isArray(block.content)){let names=toolReferenceNames(block.content);if(names.length>0){messageChanged=!0;for(let name of names)demotedNames.add(name);let kept=block.content.filter(item=>!(isRecord2(item)&&item.type==="tool_reference"));content.push({...block,content:[...kept,{type:"text",text:`Tools loaded: ${names.join(", ")}`}]});continue}}content.push(block)}if(!messageChanged){rewrittenMessages.push(message);continue}changed=!0,content.length>0&&rewrittenMessages.push({...message,content})}return changed?{...params,messages:rewrittenMessages,...residentTools(params.tools,demotedNames)}:params}function residentTools(tools,names){if(!Array.isArray(tools)||names.size===0)return{};let changed=!1,rewritten=tools.map(tool=>{if(!isRecord2(tool)||tool.defer_loading!==!0||typeof tool.name!="string"||!names.has(tool.name))return tool;changed=!0;let{defer_loading:_deferLoading,...resident}=tool;return resident});return changed?{tools:rewritten}:{}}function toolReferenceNames(items){let names=new Set;for(let item of items)isRecord2(item)&&item.type==="tool_reference"&&typeof item.tool_name=="string"&&names.add(item.tool_name);return[...names]}function rewriteToolReferenceItems(items,resolve){let kept=[],omitted=[],rewritten=!1;for(let item of items){if(!isRecord2(item)||item.type!=="tool_reference"||typeof item.tool_name!="string"){kept.push(item);continue}let resolved=resolve(item.tool_name);if(resolved===void 0){omitted.push(item.tool_name),rewritten=!0;continue}if(resolved!==item.tool_name){kept.push({...item,tool_name:resolved}),rewritten=!0;continue}kept.push(item)}return rewritten?{kept,omitted}:void 0}function toolResultText(content){if(typeof content=="string")return content;if(Array.isArray(content)){let parts=[];for(let item of content)isRecord2(item)&&(item.type==="text"&&typeof item.text=="string"?parts.push(item.text):typeof item.type=="string"&&parts.push(`[${item.type}]`));if(parts.length>0)return parts.join(`
|
|
4
4
|
`)}return"Tool output unavailable."}function resolveCacheRetention(cacheRetention,env,fallback="short"){return cacheRetention||(getProviderEnvValue("PI_CACHE_RETENTION",env)==="long"?"long":typeof process<"u"&&process.env.PI_CACHE_RETENTION!==void 0?"short":fallback)}function getCacheControl(model,cacheRetention,env){let retention=resolveCacheRetention(cacheRetention,env,"short");if(retention==="none")return{retention};let ttl=retention==="long"&&isAnthropicApiBaseUrl(model.baseUrl)&&getAnthropicCompat(model).supportsLongCacheRetention?"1h":void 0;return{retention,cacheControl:{type:"ephemeral",...ttl&&{ttl}}}}var claudeCodeVersion="2.1.288",claudeCodeTools=["Read","Write","Edit","Bash","Grep","Glob","AskUserQuestion","EnterPlanMode","ExitPlanMode","KillShell","NotebookEdit","Skill","Task","TaskOutput","TodoWrite","WebFetch","WebSearch"],ccToolLookup=new Map(claudeCodeTools.map(t=>[t.toLowerCase(),t])),ccToolAliases=new Map([["ask_user_question","AskUserQuestion"]]),toClaudeCodeName=name=>ccToolAliases.get(name)??ccToolLookup.get(name.toLowerCase())??name,fromClaudeCodeName=(name,tools)=>{if(tools&&tools.length>0){let alias=[...ccToolAliases].find(([,wireName])=>wireName===name);if(alias&&tools.some(tool=>tool.name===alias[0]))return alias[0];let lowerName=name.toLowerCase(),matchedTool=tools.find(tool=>tool.name.toLowerCase()===lowerName);if(matchedTool)return matchedTool.name}return name};function convertContentBlocks(content){if(!content.some(c=>c.type==="image"))return sanitizeSurrogates(content.map(c=>c.text).join(`
|
|
5
5
|
`));let blocks=content.map(block=>block.type==="text"?{type:"text",text:sanitizeSurrogates(block.text)}:isVideoMimeType(block.mimeType)?{type:"video",source:{type:"base64",media_type:block.mimeType,data:block.data}}:{type:"image",source:{type:"base64",media_type:block.mimeType,data:block.data}});return blocks.some(b=>b.type==="text")||blocks.unshift({type:"text",text:"(see attached image)"}),blocks}var FINE_GRAINED_TOOL_STREAMING_BETA="fine-grained-tool-streaming-2025-05-14",INTERLEAVED_THINKING_BETA="interleaved-thinking-2025-05-14",COMPUTER_USE_BETA_PREFIX="computer-use-",NATIVE_COMPUTER_TOOL_TYPE="computer_20250124",ADAPTIVE_THINKING_MODEL_MARKERS=["opus-4-6","opus-4-7","opus-4-8","opus-5","sonnet-4-6","sonnet-5","fable-5","mythos-5"],NATIVE_XHIGH_EFFORT_MODEL_MARKERS=["opus-4-7","opus-4-8","opus-5","sonnet-5","fable-5","mythos-5"],DISABLED_THINKING_REJECTING_MODEL_MARKERS=["fable-5","mythos-5","opus-5-5","opus-5.5","sonnet-5-5","sonnet-5.5"],UNSUPPORTED_NATIVE_COMPUTER_TOOL_MODEL_MARKERS=["opus-4-6","opus-4.6","opus-4-7","opus-4.7","opus-4-8","opus-4.8"],SERVER_SIDE_FALLBACK_BETA="server-side-fallback-2026-07-01";function shouldUseServerSideFallbackBeta(model){return(model.compat?.allowedFallbackModels?.length??0)>0}var MID_CONVERSATION_OUTPUT_CONFIG_BETA="mid-conversation-output-config-2026-07-01",THINKING_BINDING_CONTROLS_BETA="thinking-binding-controls-2026-08-01",MID_CONVERSATION_TOOL_CHANGES_BETA="mid-conversation-tool-changes-2026-07-01",DEFERRED_TOOL_PLACEHOLDER={name:"__pi_deferred_placeholder__",description:"Reserved placeholder. Never available. Never call this.",input_schema:{type:"object",properties:{},required:[]},defer_loading:!0};function supportsMidConvoSystemMessages(model){return model.compat?.supportsMidConvoSystemMessages??!1}function supportsMidConvoToolChanges(model){return model.compat?.supportsMidConvoToolChanges??!1}var unsignedThinkingTextReplayFallbacks=new Set,toolReferenceReplayFallbacks=new Set;registerSessionResourceCleanup(sessionId=>{if(sessionId===void 0){unsignedThinkingTextReplayFallbacks.clear(),toolReferenceReplayFallbacks.clear();return}let prefix=`${sessionId}\0`;for(let fallbacks of[unsignedThinkingTextReplayFallbacks,toolReferenceReplayFallbacks])for(let key of fallbacks)key.startsWith(prefix)&&fallbacks.delete(key)});function unsignedThinkingFallbackKey(model,sessionId){return sessionId===void 0?void 0:`${sessionId}\0${model.baseUrl}\0${model.id}`}function isInvalidUnsignedThinkingSignatureError(error){return typeof error=="object"&&error!==null&&"status"in error&&error.status===400&&error instanceof Error&&/Invalid signature in thinking block/i.test(error.message)}function isToolReferenceNotFoundError(error){return error instanceof Error&&"status"in error&&error.status===400&&/Tool reference '[^']*' not found in available tools/i.test(error.message)}function mergeHeaders(...headerSources){let merged={};for(let headers of headerSources)headers&&Object.assign(merged,headers);return merged}function mergeClientHeaders(_model,...headerSources){return mergeHeaders({"User-Agent":getPiUserAgent()},...headerSources)}function hasHeader(headers,name){if(!headers)return!1;let expected=name.toLowerCase();for(let[key,value]of Object.entries(headers))if(key.toLowerCase()===expected&&value!==null&&value.trim().length>0)return!0;return!1}function hasRequestAuth(apiKey,headers){return!!apiKey||hasHeader(headers,"authorization")||hasHeader(headers,"x-api-key")||hasHeader(headers,"cf-aig-authorization")}function assertRequestAuth(provider,apiKey,headers){if(!hasRequestAuth(apiKey,headers))throw new Error(`No API key for provider: ${provider}`)}var PiAnthropic=class extends Anthropic{_shouldResolveDefaultCredentials(){return!1}};function getAnthropicFederation(model,apiKey,headers,env){if(model.provider!=="anthropic"||hasRequestAuth(apiKey,headers))return;let federationRuleId=getProviderEnvValue(ANTHROPIC_FEDERATION_RULE_ID_ENV,env),organizationId=getProviderEnvValue(ANTHROPIC_ORGANIZATION_ID_ENV,env),identityTokenFile=getProviderEnvValue(ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,env);if(!(!federationRuleId||!organizationId||!identityTokenFile))return{organization_id:organizationId,workspace_id:getProviderEnvValue(ANTHROPIC_WORKSPACE_ID_ENV,env),authentication:{type:"oidc_federation",federation_rule_id:federationRuleId,service_account_id:getProviderEnvValue(ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,env),identity_token:{source:"file",path:identityTokenFile}}}}var federationClient;function isRecord3(value){return typeof value=="object"&&value!==null}var REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES=new Set(["server_tool_use","web_search_tool_result","web_fetch_tool_result","code_execution_tool_result","bash_code_execution_tool_result","text_editor_code_execution_tool_result","tool_search_tool_result","container_upload"]);function isReplayableAnthropicProviderNativeBlock(raw){return isRecord3(raw)&&typeof raw.type=="string"&&REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES.has(raw.type)}function isSameAnthropicModel(message,model){return message.provider===model.provider&&message.api===model.api&&message.model===model.id}function isAnthropicFallbackMarkerBlock(block){return block.type==="providerNative"&&block.subtype==="fallback"&&isRecord3(block.raw)&&block.raw.type==="fallback"}function lastAnthropicFallbackBoundary(content){let boundary=-1;for(let index=0;index<content.length;index++)isAnthropicFallbackMarkerBlock(content[index])&&(boundary=index);return boundary}function isAnthropicServerToolUseBlock(raw){return isRecord3(raw)&&raw.type==="server_tool_use"&&typeof raw.id=="string"}function isProviderNativeToolUseBlock(raw){return isRecord3(raw)&&(raw.type==="server_tool_use"||raw.type==="mcp_tool_use")}function isAnthropicWebSearchReplayBlock(raw){return isRecord3(raw)?raw.type==="web_search_tool_result"?!0:raw.type==="server_tool_use"&&raw.name==="web_search":!1}function userMessageClosesServerTurn(message){return typeof message.content=="string"?message.content.trim().length>0:message.content.some(block=>block.type==="text"&&block.text.trim().length>0||block.type==="image")}function collectProviderNativeToolPairing(messages,model,deferredToolNames,normalizeToolName,discardedFallbackToolCallIds){let resolvedUseIds=new Set,validResultIds=new Set,pendingUseIds=new Set,loadedReferenceNames=new Set;for(let message of messages){if(message.role==="assistant"){let priorUseIds=pendingUseIds;if(pendingUseIds=new Set,!isSameAnthropicModel(message,model))continue;for(let block of message.content){if(block.type!=="providerNative"||!isRecord3(block.raw))continue;let raw=block.raw;typeof raw.type!="string"||!REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES.has(raw.type)||isProviderNativeToolUseBlock(raw)&&typeof raw.id=="string"&&pendingUseIds.add(raw.id)}for(let block of message.content){if(block.type!=="providerNative"||!isRecord3(block.raw))continue;let raw=block.raw;if(typeof raw.type!="string"||!REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES.has(raw.type))continue;let toolUseId=raw.tool_use_id;typeof toolUseId=="string"&&(priorUseIds.has(toolUseId)||pendingUseIds.has(toolUseId))&&(resolvedUseIds.add(toolUseId),validResultIds.add(toolUseId))}continue}if(message.role==="toolResult"){if(discardedFallbackToolCallIds.has(message.toolCallId))continue;let emitsReferences=!1;for(let name of message.addedToolNames??[]){let normalizedName=normalizeToolName(name);!deferredToolNames.has(normalizedName)||loadedReferenceNames.has(normalizedName)||(loadedReferenceNames.add(normalizedName),emitsReferences=!0)}emitsReferences&&(pendingUseIds=new Set);continue}message.role==="user"&&userMessageClosesServerTurn(message)&&(pendingUseIds=new Set)}return{resolvedUseIds,liveUseIds:pendingUseIds,validResultIds}}function isUnpairedProviderNativeToolBlock(raw,pairing){if(!isRecord3(raw))return!1;if(isProviderNativeToolUseBlock(raw))return typeof raw.id!="string"||!(pairing.resolvedUseIds.has(raw.id)||pairing.liveUseIds.has(raw.id));let toolUseId=raw.tool_use_id;return typeof toolUseId=="string"&&!pairing.validResultIds.has(toolUseId)}function pairedServerToolUseIdsBeforeBoundary(content,boundary){let paired=new Set;for(let index=0;index<boundary;index++){let block=content[index];if(block.type!=="providerNative"||!isRecord3(block.raw))continue;let toolUseId=block.raw.tool_use_id;typeof toolUseId=="string"&&paired.add(toolUseId)}return paired}function collectDiscardedFallbackToolCallIds(messages,model){let discarded=new Set;for(let message of messages){if(message.role!=="assistant"||!isSameAnthropicModel(message,model))continue;let boundary=lastAnthropicFallbackBoundary(message.content);if(!(boundary<0))for(let index=0;index<boundary;index++){let block=message.content[index];block.type==="toolCall"&&discarded.add(block.id)}}return discarded}function stringRecord(value){if(!isRecord3(value))return;let entries=Object.entries(value);if(!entries.some(([,item])=>typeof item!="string"))return Object.fromEntries(entries)}function isForcedAnthropicToolChoice(toolChoice){return isRecord3(toolChoice)&&(toolChoice.type==="any"||toolChoice.type==="tool")}function extractPayloadRequestMetadata(params){let payload=params,headers=stringRecord(payload.headers);if(!("headers"in payload)&&!("extra_body"in payload))return headers?{params,headers}:{params};let stripped={...payload};return delete stripped.headers,delete stripped.extra_body,headers?{params:stripped,headers}:{params:stripped}}function removeAnthropicBetaHeaders(headers,shouldRemoveBeta){if(!headers)return{changed:!1};let nextHeaders={},changed=!1;for(let[key,value]of Object.entries(headers)){if(key.toLowerCase()!=="anthropic-beta"||value===null){nextHeaders[key]=value;continue}let betas=value.split(",").map(beta=>beta.trim()).filter(beta=>beta.length>0),supportedBetas=betas.filter(beta=>!shouldRemoveBeta(beta));changed=changed||supportedBetas.length!==betas.length,supportedBetas.length>0&&(nextHeaders[key]=supportedBetas.join(", "))}return changed?{changed:!0,headers:Object.keys(nextHeaders).length>0?nextHeaders:void 0}:{changed:!1,headers}}function removeComputerUseBetaHeader(headers){return removeAnthropicBetaHeaders(headers,beta=>beta.startsWith(COMPUTER_USE_BETA_PREFIX))}function sanitizeAdaptiveThinkingHeaders(model,headers){if(!supportsAdaptiveThinking(model))return headers;let headerSanitization=removeAnthropicBetaHeaders(headers,beta=>beta===INTERLEAVED_THINKING_BETA);return headerSanitization.changed?headerSanitization.headers??{}:headers}function rejectsNativeComputerTool(model,toolType){return model.provider==="cloudflare-ai-gateway"&&model.baseUrl.includes("anthropic")?toolType.startsWith("computer_"):matchesModelMarker(model,UNSUPPORTED_NATIVE_COMPUTER_TOOL_MODEL_MARKERS)&&toolType===NATIVE_COMPUTER_TOOL_TYPE}function rejectsComputerUseBeta(model){return model.provider==="cloudflare-ai-gateway"&&model.baseUrl.includes("anthropic")||matchesModelMarker(model,UNSUPPORTED_NATIVE_COMPUTER_TOOL_MODEL_MARKERS)}function isAnthropicWebSearchToolType(toolType){return toolType.startsWith("web_search_")}function sanitizeUnsupportedNativeTools(model,params){let payload=params,headers=stringRecord(payload.headers),headerSanitization=rejectsComputerUseBeta(model)?removeComputerUseBetaHeader(headers):{changed:!1},rejectsNativeWebSearch=!getAnthropicCompat(model).supportsWebSearch,tools=payload.tools,sanitized={...payload},changed=!1;if(Array.isArray(tools)){let supportedTools=[];for(let tool of tools){let hookTool=tool;if(isRecord3(hookTool)&&typeof hookTool.type=="string"&&(rejectsNativeComputerTool(model,hookTool.type)||rejectsNativeWebSearch&&isAnthropicWebSearchToolType(hookTool.type))){changed=!0;continue}supportedTools.push(tool)}changed&&(supportedTools.length>0?sanitized.tools=supportedTools:delete sanitized.tools)}if(headerSanitization.changed&&(changed=!0,headerSanitization.headers?sanitized.headers=headerSanitization.headers:delete sanitized.headers),changed&&isRecord3(sanitized.tool_choice)){let toolChoiceName=sanitized.tool_choice.name,hasSelectedTool=typeof toolChoiceName=="string"&&Array.isArray(sanitized.tools)&&sanitized.tools.some(tool=>isRecord3(tool)&&tool.name===toolChoiceName);(sanitized.tools===void 0||typeof toolChoiceName=="string"&&!hasSelectedTool)&&delete sanitized.tool_choice}return changed?sanitized:params}function httpStatusOfError(error){if(!isRecord3(error))return;let status=error.status;return typeof status=="number"&&Number.isInteger(status)&&status>=100&&status<600?status:void 0}function sanitizeAdaptiveThinkingPayload(model,params,options){if(!supportsAdaptiveThinking(model))return params;let payload=params,headers=stringRecord(payload.headers),headerSanitization=removeAnthropicBetaHeaders(headers,beta=>beta===INTERLEAVED_THINKING_BETA),sanitized={...payload},changed=!1,thinking=isRecord3(payload.thinking)?payload.thinking:void 0;if(thinking?.type==="enabled"){let display=thinking.display==="omitted"||thinking.display==="summarized"?thinking.display:options?.thinkingDisplay??"summarized";sanitized.thinking={type:"adaptive",display},options?.effort!==void 0&&!isRecord3(payload.output_config)&&(sanitized.output_config={effort:options.effort}),changed=!0}return headerSanitization.changed&&(changed=!0,headerSanitization.headers?sanitized.headers=headerSanitization.headers:delete sanitized.headers),changed?sanitized:params}function isCacheableUserContentBlock(block){return block?.type==="text"||block?.type==="image"||block?.type==="tool_result"}function appendUserBlocks(params,newBlocks){if(newBlocks.length===0)return;let lastParam=params[params.length-1];lastParam?.role==="user"?typeof lastParam.content=="string"?lastParam.content=[{type:"text",text:lastParam.content},...newBlocks]:Array.isArray(lastParam.content)&&lastParam.content.push(...newBlocks):params.push({role:"user",content:newBlocks})}function isToolLoopContinuation(messages){let tail=messages[messages.length-1],preceding=messages[messages.length-2];return tail?.role==="user"&&Array.isArray(tail.content)&&tail.content.some(block=>block.type==="tool_result")&&preceding?.role==="assistant"&&Array.isArray(preceding.content)&&preceding.content.some(block=>block.type==="tool_use")}function markSystemMessageCacheCheckpoint(message,cacheControl){if(!Array.isArray(message.content))return;let lastBlock=message.content[message.content.length-1];lastBlock&&(lastBlock.type==="text"||lastBlock.type==="tool_addition"||lastBlock.type==="tool_removal")&&(lastBlock.cache_control=cacheControl)}function markUserMessageCacheCheckpoint(message,cacheControl){if(message.role!=="user")return!1;if(Array.isArray(message.content)){let lastBlock=message.content[message.content.length-1];return isCacheableUserContentBlock(lastBlock)?(lastBlock.cache_control=cacheControl,!0):!1}return typeof message.content=="string"?(message.content=[{type:"text",text:message.content,cache_control:cacheControl}],!0):!1}var ANTHROPIC_MESSAGE_EVENTS=new Set(["message_start","message_delta","message_stop","content_block_start","content_block_delta","content_block_stop"]);function flushSseEvent(state){if(!state.event&&state.data.length===0)return null;let event={event:state.event,data:state.data.join(`
|
package/dist/bundle/chunks/{app-server-command-I2AKSC6I.js → app-server-command-3Q5G4CAF.js}
RENAMED
|
@@ -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{import_websocket_server,wrapper_default}from"./chunk-YBZDAABT.js";import{AuthStorage,DefaultResourceLoader,GOAL_STORE_CHANGED_EVENT,ModelRegistry,
|
|
2
|
+
import{import_websocket_server,wrapper_default}from"./chunk-YBZDAABT.js";import{AuthStorage,DefaultResourceLoader,GOAL_STORE_CHANGED_EVENT,ModelRegistry,clearGoal,createAgentSession,createGoal,createPendingQuestion,defaultModelPerProvider,formatProviderNativeBody,formatProviderNativeSummary,getMcpService,goalStoreRef,loadMcpConfig,loadSkills,readGoal,resolveAuthMode,updateGoal}from"./chunk-EEOKVSNF.js";import{RPC_ERROR_UNKNOWN_COMMAND,UNKNOWN_COMMAND_CONFIRM_HINT,UnknownCommandError,getCredentialAccounts,getModels,getProviders,getSupportedThinkingLevels,pinCredentialAccount,removeCredentialAccount,subscribeProviderAccountEvents}from"./chunk-UUAKEDVS.js";import"./chunk-QNAG7FYM.js";import{SessionManager,loadEntriesFromFile,require_ignore}from"./chunk-WTJU5B2C.js";import{SettingsManager,getAvailableThemesWithPaths,getThemeByName,takeOverStdout,theme,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-UXIQK5NQ.js";import"./chunk-LYYI74CY.js";import"./chunk-V2VQ4BHG.js";import{x}from"./chunk-K4AZKFRB.js";import"./chunk-WIAXG52U.js";import"./chunk-U5KVIAHJ.js";import"./chunk-ECDLITEY.js";import"./chunk-JABBHOD5.js";import"./chunk-2WV426OJ.js";import"./chunk-K3BXFPWZ.js";import"./chunk-QMRJYMNH.js";import{acquireOwnershipSafeLock}from"./chunk-6JXPZACL.js";import"./chunk-UWYQPA26.js";import"./chunk-H4QOEVS5.js";import"./chunk-JVSOW4QU.js";import"./chunk-F6EQ7EV3.js";import"./chunk-JEZWV7JW.js";import"./chunk-S2TCHQTE.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-YU2P3CAR.js";import"./chunk-BMX2U22F.js";import"./chunk-HKG7XL4H.js";import"./chunk-CIRZTP7W.js";import{parseDaemonPidFile,processMatchesPidFile,readProcessStartTime,stopValidatedPid,waitForGone,waitForStartTime}from"./chunk-22DAHAHO.js";import{attachJsonlLineReader}from"./chunk-XYDZ3LIE.js";import"./chunk-HB35RBP4.js";import"./chunk-7Q3EY6HH.js";import"./chunk-6SMU7ANE.js";import"./chunk-MH2BFYGN.js";import"./chunk-26UBFF6N.js";import"./chunk-UHRXXTFZ.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-KEMQXWPY.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import{APP_NAME,CONFIG_DIR_NAME,ENV_SESSION_DIR,VERSION,getAgentDir,getSessionsDir,isLocalPath,resolvePath}from"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-JRGNL6WM.js";import"./chunk-RKJNJ3GI.js";import"./chunk-CWLCGRUS.js";import"./chunk-6WCOSBI7.js";import"./chunk-YSPHACIN.js";import"./chunk-KRNXUTZJ.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-BBK6SSYT.js";import"./chunk-BPX6QWPD.js";import{normalizeProviderId}from"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import{__toESM}from"./chunk-IKOFCODM.js";import{isIP}from"node:net";var APP_SERVER_LISTEN_USAGE="Invalid --listen value. Use stdio://, unix://, unix:///abs/path, or ws://IP:PORT.";function formatAppServerUsage(){let listenForms="stdio://|unix://|unix:///abs/path|ws://IP:PORT";return[`Usage: ${APP_NAME} app-server [--listen <${listenForms}>] [--ws-auth <token-file|off>] [--json-logs] [--extension <path>]...`,` ${APP_NAME} app-server daemon <start|stop|status|restart> [--listen <${listenForms}>] [--extension <path>]...`].join(`
|
|
3
3
|
`)}function parseListen(value){if(value==="stdio://")return{kind:"stdio",url:"stdio://"};if(value==="unix://")return{kind:"unix",url:"unix://"};if(value.startsWith("unix:///")){let path=value.slice(7);return path.startsWith("/")?{kind:"unix",url:value,path}:void 0}if(!value.startsWith("ws://"))return;let parsed;try{parsed=new URL(value)}catch(error){if(error instanceof TypeError)return;throw error}let port=Number(parsed.port);if(!(parsed.protocol!=="ws:"||parsed.username!==""||parsed.password!==""||parsed.pathname!=="/"||parsed.search!==""||parsed.hash!==""||parsed.port===""||!Number.isInteger(port)||port<1||port>65535||isIP(parsed.hostname)===0))return{kind:"ws",url:value,host:parsed.hostname,port}}function parseDaemonVerb(value){switch(value){case"start":case"stop":case"status":case"restart":return value;default:return}}function parseWsAuth(value){return value==="off"?{kind:"off"}:{kind:"token-file",path:value}}var EXTENSION_USAGE="--extension requires <path>.";function parseServerArgs(args){let listen3={kind:"stdio",url:"stdio://"},wsAuth,jsonLogs=!1,extensions=[];for(let index=0;index<args.length;index++){let arg=args[index];if(arg==="--extension"){let value=args[index+1];if(value===void 0)return{kind:"usage-error",message:EXTENSION_USAGE};extensions.push(value),index++;continue}if(arg==="--listen"){let value=args[index+1];if(value===void 0)return{kind:"usage-error",message:APP_SERVER_LISTEN_USAGE};let parsed=parseListen(value);if(parsed===void 0)return{kind:"usage-error",message:APP_SERVER_LISTEN_USAGE};listen3=parsed,index++;continue}if(arg==="--ws-auth"){let value=args[index+1];if(value===void 0)return{kind:"usage-error",message:"--ws-auth requires <token-file|off>."};wsAuth=parseWsAuth(value),index++;continue}if(arg==="--json-logs"){jsonLogs=!0;continue}return{kind:"usage-error",message:`Unexpected app-server argument: ${arg}`}}return{kind:"server",listen:listen3,wsAuth,jsonLogs,extensions}}function parseDaemonArgs(args){let verb=parseDaemonVerb(args[0]);if(verb===void 0)return{kind:"usage-error",message:"Usage: app-server daemon <start|stop|status|restart>."};let listen3={kind:"ws",url:"ws://127.0.0.1:18800",host:"127.0.0.1",port:18800},extensions=[];for(let index=1;index<args.length;index++){let arg=args[index];if(arg==="--extension"){let value=args[index+1];if(value===void 0)return{kind:"usage-error",message:EXTENSION_USAGE};extensions.push(value),index++;continue}if(arg==="--listen"){let value=args[index+1];if(value===void 0)return{kind:"usage-error",message:APP_SERVER_LISTEN_USAGE};let parsed=parseListen(value);if(parsed===void 0)return{kind:"usage-error",message:APP_SERVER_LISTEN_USAGE};listen3=parsed,index++;continue}return{kind:"usage-error",message:`Unexpected app-server daemon argument: ${arg}`}}return{kind:"daemon",verb,listen:listen3,extensions}}function parseAppServerCliArgs(args){return args[0]==="daemon"?parseDaemonArgs(args.slice(1)):parseServerArgs(args)}function resolveAppServerExtensionPaths(extensions,cwd=process.cwd()){return extensions.map(value=>isLocalPath(value)?resolvePath(value,cwd):value)}var RpcHandlerError=class extends Error{constructor(error){super(error.message),this.name="RpcHandlerError",this.rpcError=error}};function invalidRequestError(){return{code:-32600,message:"Invalid request"}}function methodNotFoundError(method){return{code:-32601,message:`Method not found: ${method}`}}function invalidParamsError(){return{code:-32602,message:"Invalid params"}}function internalError(message="Internal error"){return{code:-32603,message}}function notInitializedError(){return{code:-32600,message:"Not initialized"}}function alreadyInitializedError(){return{code:-32600,message:"Already initialized"}}function experimentalCapabilityError(method){return{code:-32600,message:`${method} requires experimentalApi capability`}}function registerExtensionRequestMethod(registry,getThread){registry.register("extension_request",{scope:"thread",handler:async({request})=>{let params=request.params;if(typeof params!="object"||params===null||Array.isArray(params))throw new RpcHandlerError({code:-32602,message:"Invalid params"});let threadId=Reflect.get(params,"threadId"),name=Reflect.get(params,"name");if(typeof threadId!="string"||threadId.length===0||typeof name!="string"||name.length===0)throw new RpcHandlerError({code:-32602,message:"Invalid params"});try{return await getThread(threadId).extensionRunner.requestRpc(name,Reflect.get(params,"data"))}catch(error){throw new RpcHandlerError(internalError(error instanceof Error?error.message:String(error)))}}})}function createRegistry(){return new InMemoryMethodRegistry}var InMemoryMethodRegistry=class{constructor(){this.methods=new Map}register(method,registration){this.methods.set(method,registration)}async dispatch(connection,request){if(!connection.initialized){let registration2=this.methods.get(request.method);if(request.method!=="initialize"||registration2?.requiresInit!==!1)return{id:request.id,error:notInitializedError()}}if(connection.initialized&&request.method==="initialize")return{id:request.id,error:alreadyInitializedError()};let registration=this.methods.get(request.method);if(!registration)return{id:request.id,error:methodNotFoundError(request.method)};if(registration.experimental===!0&&connection.capabilities?.experimentalApi!==!0)return{id:request.id,error:experimentalCapabilityError(request.method)};try{let result=await registration.handler({connection,request});return{id:request.id,result}}catch(error){return error instanceof RpcHandlerError?{id:request.id,error:error.rpcError}:{id:request.id,error:internalError(error instanceof Error?error.message:String(error))}}}};function registerFuzzyFileSearchMethods(registry,service){registry.register("fuzzyFileSearch",{scope:"global",handler:({request})=>service.search(parseOneShotParams(request.params))}),registry.register("fuzzyFileSearch/sessionStart",{experimental:!0,scope:"global",handler:({request})=>service.startSession(parseSessionStartParams(request.params))}),registry.register("fuzzyFileSearch/sessionUpdate",{experimental:!0,scope:"global",handler:({request})=>service.updateSession(parseSessionUpdateParams(request.params))}),registry.register("fuzzyFileSearch/sessionStop",{experimental:!0,scope:"global",handler:({request})=>service.stopSession(parseSessionStopParams(request.params))})}function parseOneShotParams(value){let params=objectParams(value,"fuzzyFileSearch");return{query:requiredString(params.query,"fuzzyFileSearch query"),roots:requiredStringArray(params.roots,"fuzzyFileSearch roots"),cancellationToken:optionalString(params.cancellationToken,"fuzzyFileSearch cancellationToken")}}function parseSessionStartParams(value){let params=objectParams(value,"fuzzyFileSearch/sessionStart");return{sessionId:requiredString(params.sessionId,"fuzzyFileSearch/sessionStart sessionId"),roots:requiredStringArray(params.roots,"fuzzyFileSearch/sessionStart roots")}}function parseSessionUpdateParams(value){let params=objectParams(value,"fuzzyFileSearch/sessionUpdate");return{sessionId:requiredString(params.sessionId,"fuzzyFileSearch/sessionUpdate sessionId"),query:requiredString(params.query,"fuzzyFileSearch/sessionUpdate query")}}function parseSessionStopParams(value){let params=objectParams(value,"fuzzyFileSearch/sessionStop");return{sessionId:requiredString(params.sessionId,"fuzzyFileSearch/sessionStop sessionId")}}function objectParams(value,method){if(!isRecord(value))throw invalidRequest(`${method} params must be an object`);return value}function requiredString(value,field){if(typeof value!="string")throw invalidRequest(`${field} must be a string`);return value}function requiredStringArray(value,field){if(!Array.isArray(value)||value.some(entry=>typeof entry!="string"))throw invalidRequest(`${field} must be an array of strings`);return value}function optionalString(value,field){if(value==null)return null;if(typeof value!="string")throw invalidRequest(`${field} must be a string or null`);return value}function invalidRequest(message){return new RpcHandlerError({code:-32600,message})}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{lstat,readdir}from"node:fs/promises";import{basename,join as join2,relative as relative2,resolve,sep as sep2}from"node:path";var import_ignore=__toESM(require_ignore(),1);import{readFile}from"node:fs/promises";import{join,relative,sep}from"node:path";async function addGitignoreScope(matchers,directory){let gitignore=await readableText(join(directory,".gitignore"));return gitignore===void 0?matchers:[...matchers,{directory,matcher:(0,import_ignore.default)().add(gitignore)}]}function isIgnored(matchers,path,isDirectory){let ignored=!1;for(let scope of matchers){let relativePath=relative(scope.directory,path).split(sep).join("/"),result=scope.matcher.test(isDirectory?`${relativePath}/`:relativePath);result.ignored&&(ignored=!0),result.unignored&&(ignored=!1)}return ignored}async function readableText(path){try{return await readFile(path,"utf8")}catch(error){if(error instanceof Error)return;throw error}}var FUZZY_SEARCH_MAX_DEPTH=12,FUZZY_SEARCH_MAX_VISITED_ENTRIES=5e4,FUZZY_SEARCH_RESULT_LIMIT=50,FILENAME_MATCH_BONUS=1e6,CHARACTER_MATCH_SCORE=10,CONTIGUOUS_MATCH_BONUS=20,BOUNDARY_MATCH_BONUS=5,CANCELLATION_YIELD_INTERVAL=256;async function collectFuzzyFileEntries(roots,options={}){let entries=[],state={visitedEntries:0,stopped:!1},maxDepth=options.maxDepth??FUZZY_SEARCH_MAX_DEPTH,maxVisitedEntries=options.maxVisitedEntries??FUZZY_SEARCH_MAX_VISITED_ENTRIES;for(let root of roots){if(options.signal?.aborted||state.stopped)break;let absoluteRoot=resolve(root),rootStat=await readableStat(absoluteRoot);!rootStat?.isDirectory()||rootStat.isSymbolicLink()||await walkDirectory({wireRoot:root,absoluteRoot,absoluteDirectory:absoluteRoot,depth:0,matchers:[],entries,state,signal:options.signal,maxDepth,maxVisitedEntries})}return entries}function rankFuzzyFileEntries(query,entries){if(query.length===0)return[];let results=[];for(let entry of entries){let filenameMatch=scoreSubsequence(entry.fileName,query),pathMatch=filenameMatch??scoreSubsequence(entry.path,query);if(!pathMatch)continue;let filenameOffset=Array.from(entry.path).length-Array.from(entry.fileName).length,indices=filenameMatch?filenameMatch.indices.map(index=>index+filenameOffset):pathMatch.indices;results.push({root:entry.root,path:entry.path,match_type:entry.matchType,file_name:entry.fileName,score:pathMatch.score+(filenameMatch?FILENAME_MATCH_BONUS:0),indices})}return results.sort(compareResults),results.slice(0,FUZZY_SEARCH_RESULT_LIMIT)}async function walkDirectory(input){let matchers=await addGitignoreScope(input.matchers,input.absoluteDirectory),directoryEntries=await readableDirectory(input.absoluteDirectory);directoryEntries.sort((left,right)=>compareText(left.name,right.name));for(let directoryEntry of directoryEntries){if(input.signal?.aborted||input.state.stopped)return;if(input.state.visitedEntries>=input.maxVisitedEntries){input.state.stopped=!0;return}if(input.state.visitedEntries+=1,directoryEntry.name===".git"||directoryEntry.name==="node_modules"||directoryEntry.isSymbolicLink())continue;let isDirectory=directoryEntry.isDirectory();if(!isDirectory&&!directoryEntry.isFile())continue;let absolutePath=join2(input.absoluteDirectory,directoryEntry.name),relativePath=toPosixPath(relative2(input.absoluteRoot,absolutePath));if(isIgnored(matchers,absolutePath,isDirectory))continue;input.entries.push({root:input.wireRoot,path:relativePath,matchType:isDirectory?"directory":"file",fileName:basename(relativePath)});let entryDepth=input.depth+1;isDirectory&&entryDepth<input.maxDepth&&await walkDirectory({...input,absoluteDirectory:absolutePath,depth:entryDepth,matchers}),input.state.visitedEntries%CANCELLATION_YIELD_INTERVAL===0&&await yieldToEventLoop()}}function scoreSubsequence(candidate,query){let normalizedCandidate=normalizeText(candidate),normalizedQuery=query.toLowerCase(),contiguousStart=normalizedCandidate.value.indexOf(normalizedQuery),normalizedIndices=[];if(contiguousStart>=0){let cursor=contiguousStart;for(let character of normalizedQuery)normalizedIndices.push(cursor),cursor+=character.length}else{let cursor=0;for(let character of normalizedQuery){let matchIndex=normalizedCandidate.value.indexOf(character,cursor);if(matchIndex<0)return;normalizedIndices.push(matchIndex),cursor=matchIndex+character.length}}let indices=[];for(let normalizedIndex of normalizedIndices){let sourceIndex=normalizedCandidate.sourceIndices[normalizedIndex];if(sourceIndex===void 0)return;indices.at(-1)!==sourceIndex&&indices.push(sourceIndex)}let candidateCharacters=Array.from(candidate),score=indices.length*CHARACTER_MATCH_SCORE;for(let index=0;index<indices.length;index++){let current=indices[index];if(current===void 0)continue;let previous=indices[index-1];previous!==void 0&¤t===previous+1&&(score+=CONTIGUOUS_MATCH_BONUS),(current===0||isBoundary(candidateCharacters[current-1]))&&(score+=BOUNDARY_MATCH_BONUS)}return{score,indices}}function normalizeText(value){let sourceIndices=[];for(let[sourceIndex,character]of Array.from(value).entries())for(let index=0;index<character.toLowerCase().length;index++)sourceIndices.push(sourceIndex);return{value:value.toLowerCase(),sourceIndices}}function compareResults(left,right){return left.score!==right.score?right.score-left.score:compareText(left.path,right.path)}function compareText(left,right){return left<right?-1:left>right?1:0}function isBoundary(character){return character==="/"||character==="-"||character==="_"||character==="."||character===" "}async function readableDirectory(path){try{return await readdir(path,{withFileTypes:!0})}catch(error){if(error instanceof Error)return[];throw error}}async function readableStat(path){try{return await lstat(path)}catch(error){if(error instanceof Error)return;throw error}}function toPosixPath(path){return path.split(sep2).join("/")}function yieldToEventLoop(){return new Promise(resolve4=>setImmediate(resolve4))}var FuzzyFileSearchService=class{constructor(options){this.activeSearches=new Set,this.pendingSearches=new Map,this.sessions=new Map,this.disposed=!1,this.broadcast=options.broadcast,this.collectEntries=options.collectEntries??((roots,signal)=>collectFuzzyFileEntries(roots,{signal})),this.rankEntries=options.rankEntries??rankFuzzyFileEntries}async search(params){if(this.disposed)return{files:[]};let controller=new AbortController;this.activeSearches.add(controller);let token=params.cancellationToken;token!==null&&(this.pendingSearches.get(token)?.abort(),this.pendingSearches.set(token,controller));try{if(params.query.length===0)return{files:[]};let entries=await this.collectEntries(params.roots,controller.signal);return controller.signal.aborted||this.disposed?{files:[]}:{files:this.rankEntries(params.query,entries)}}finally{this.activeSearches.delete(controller),token!==null&&this.pendingSearches.get(token)===controller&&this.pendingSearches.delete(token)}}startSession(params){if(params.sessionId.length===0)throw invalidRequest2("sessionId must not be empty");this.cancelSession(params.sessionId);let session={id:params.sessionId,roots:params.roots,controller:new AbortController,query:"",version:0,entries:void 0,active:!this.disposed,completedVersion:void 0};return this.sessions.set(session.id,session),this.runTraversal(session),{}}updateSession(params){let session=this.sessions.get(params.sessionId);if(!session?.active)throw invalidRequest2(`fuzzy file search session not found: ${params.sessionId}`);return session.query=params.query,session.version+=1,session.entries!==void 0&&this.emitVersion(session,session.version),{}}stopSession(params){return this.cancelSession(params.sessionId),{}}dispose(){if(!this.disposed){this.disposed=!0;for(let controller of this.activeSearches)controller.abort();this.activeSearches.clear(),this.pendingSearches.clear();for(let session of this.sessions.values())this.deactivate(session);this.sessions.clear()}}async runTraversal(session){let entries;try{entries=await this.collectEntries(session.roots,session.controller.signal)}catch(error){if(!(error instanceof Error))throw error;entries=[]}if(this.isLive(session))for(session.entries=entries;this.isLive(session);){let version=session.version;if(await this.emitVersion(session,version))break}}async emitVersion(session,version){if(await Promise.resolve(),!this.isLive(session)||session.version!==version||session.entries===void 0)return!1;if(session.completedVersion===version)return!0;let query=session.query,files=query.length===0?[]:this.rankEntries(query,session.entries);return!this.isLive(session)||session.version!==version||(this.broadcast({method:"fuzzyFileSearch/sessionUpdated",params:{sessionId:session.id,query,files}}),!this.isLive(session)||session.version!==version)?!1:(session.completedVersion=version,this.broadcast({method:"fuzzyFileSearch/sessionCompleted",params:{sessionId:session.id}}),!0)}cancelSession(sessionId){let session=this.sessions.get(sessionId);session&&(this.deactivate(session),this.sessions.get(sessionId)===session&&this.sessions.delete(sessionId))}deactivate(session){session.active=!1,session.controller.abort()}isLive(session){return!this.disposed&&session.active&&this.sessions.get(session.id)===session}};function invalidRequest2(message){return new RpcHandlerError({code:-32600,message})}var APPROVAL_DECISIONS=["accept","acceptForSession","decline","cancel"],PERMISSION_OPTIONS=["Allow once","Allow always","Deny","Deny with feedback"],CANCEL_REASON="approval request was cancelled because the turn ended",NO_SUBSCRIBER_REASON="no client connected to approve";var ApprovalBridge=class{constructor(sendToThreadSubscribers){this.nextServerRequestId=0,this.pending=new Map,this.sessionAllows=new Set,this.sendToThreadSubscribers=sendToThreadSubscribers}get pendingCount(){return this.pending.size}requestApproval(threadId,kind,payload){let allowKey=createAllowKey(threadId,kind,payload);if(allowKey&&this.sessionAllows.has(allowKey))return Promise.resolve({allow:!0,decision:"acceptForSession"});let requestId=this.nextServerRequestId;this.nextServerRequestId+=1;let request=buildApprovalRequest(threadId,requestId,kind,payload);return new Promise(resolve4=>{this.pending.set(requestId,{threadId,request,allowKey,resolve:resolve4}),!(this.sendToThreadSubscribers(threadId,request)>0)&&(this.pending.delete(requestId),resolve4({allow:!1,decision:"decline",reason:NO_SUBSCRIBER_REASON}))})}resolveResponse(response){let pending=this.pending.get(response.id);if(!pending)return!1;let decision=readDecision(response);return this.pending.delete(response.id),decision==="acceptForSession"&&pending.allowKey&&this.sessionAllows.add(pending.allowKey),this.emitResolved(pending.threadId,response.id),pending.resolve(decisionToOutcome(decision,readReason(response))),!0}replayPendingForThread(threadId){let replayed=0;for(let pending of this.pending.values())pending.threadId===threadId&&(this.sendToThreadSubscribers(threadId,pending.request),replayed+=1);return replayed}cancelPendingForThread(threadId){let cancelled=0;for(let[requestId,pending]of Array.from(this.pending.entries()))pending.threadId===threadId&&(this.pending.delete(requestId),this.emitResolved(threadId,requestId),pending.resolve({allow:!1,decision:"cancel",reason:CANCEL_REASON}),cancelled+=1);return cancelled}emitResolved(threadId,requestId){this.sendToThreadSubscribers(threadId,{method:"serverRequest/resolved",params:{threadId,requestId}})}};function buildApprovalRequest(threadId,requestId,kind,payload){let base={threadId,turnId:payload.turnId??"turn-approval",itemId:payload.itemId??(kind==="commandExecution"?"approval-command":"approval-file-change"),startedAtMs:Date.now()};return kind==="fileChange"?{id:requestId,method:"item/fileChange/requestApproval",params:{...base,reason:payload.reason??null,grantRoot:payload.grantRoot??null}}:{id:requestId,method:"item/commandExecution/requestApproval",params:{...base,approvalId:payload.approvalId??null,environmentId:payload.environmentId??null,reason:payload.reason??null,command:payload.command??null,cwd:payload.cwd??null,availableDecisions:[...APPROVAL_DECISIONS]}}}function decisionToOutcome(decision,reason){return decision==="accept"||decision==="acceptForSession"?{allow:!0,decision}:reason?{allow:!1,decision,reason}:{allow:!1,decision}}function readDecision(response){let decision=isRecord2(response.result)?response.result.decision:void 0;return isApprovalDecision(decision)?decision:"cancel"}function readReason(response){let resultReason=isRecord2(response.result)?response.result.reason??response.result.message:void 0,errorReason=isRecord2(response.error)?response.error.message:void 0,reason=typeof resultReason=="string"?resultReason:errorReason;return typeof reason=="string"&&reason.length>0?reason:void 0}function createAllowKey(threadId,kind,payload){if(!(!payload.toolName||typeof payload.command!="string"))return`${threadId}\0${kind}\0${payload.toolName}\0${payload.command}`}function isApprovalDecision(value){return value==="accept"||value==="acceptForSession"||value==="decline"||value==="cancel"}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function createAppServerUIContext(bridge,threadId,userInput,getTurnId=()=>"turn-user-input"){let pendingInput,editorText="",editorFactory,toolsExpanded=!1;return{question(request,opts){return userInput?.requestUserInput(threadId,getTurnId(),request.requestId,request,opts)??Promise.resolve({status:"unavailable",answers:{},unanswered:request.questions.map(question=>question.id)})},async select(title,options){let prompt=parsePermissionPrompt(title);if(!prompt||!isPermissionOptions(options))return;let outcome=await bridge.requestApproval(threadId,prompt.kind,{turnId:"turn-approval",itemId:`approval-${prompt.toolName}`,toolName:prompt.toolName,command:prompt.command,reason:prompt.reason});return outcome.decision==="accept"?"Allow once":outcome.decision==="acceptForSession"?"Allow always":outcome.reason&&outcome.reason!==NO_SUBSCRIBER_REASON&&outcome.reason!==CANCEL_REASON?(pendingInput=outcome.reason,"Deny with feedback"):"Deny"},async confirm(title,message){return(await bridge.requestApproval(threadId,"commandExecution",{turnId:"turn-approval",itemId:"approval-confirm",toolName:"confirm",command:title,reason:message})).allow},async input(){let value=pendingInput;return pendingInput=void 0,value},notify(){},onTerminalInput(){return()=>{}},setStatus(){},setWorkingMessage(){},setWorkingVisible(){},setWorkingIndicator(){},setHiddenThinkingLabel(){},setWidget(){},setFooter(){},setHeader(){},setTitle(){},custom(){return Promise.reject(new Error("Custom UI is not available in app-server mode."))},pasteToEditor(text){editorText=text},setEditorText(text){editorText=text},getEditorText(){return editorText},async editor(_title,prefill){return prefill},addAutocompleteProvider(){},setEditorComponent(factory){editorFactory=factory},getEditorComponent(){return editorFactory},theme,getAllThemes:getAvailableThemesWithPaths,getTheme(name){return getThemeByName(name)},setTheme(_nextTheme){return{success:!1,error:"Theme switching is not available in app-server mode."}},getToolsExpanded(){return toolsExpanded},setToolsExpanded(expanded){toolsExpanded=expanded}}}function parsePermissionPrompt(title){let[firstLine="",...rest]=title.split(`
|
|
4
4
|
`),prefix="Permission required: ";if(!firstLine.startsWith(prefix))return;let toolName=firstLine.slice(prefix.length).trim(),reason=rest.join(`
|
|
5
5
|
`).trim();return{kind:permissionKind(toolName),toolName,command:readLineValue(reason,"Command: $ ")??readLineValue(reason,"File: ")??readLineValue(reason,"Path: ")??null,reason}}function permissionKind(toolName){return toolName==="edit"||toolName==="write"||toolName==="apply_patch"||toolName==="multiedit"?"fileChange":"commandExecution"}function readLineValue(text,prefix){return text.split(`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CUSTOM_UNSUPPORTED_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,RPC_CLIENT_CAPABILITIES_ENV,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,hostLaunchProfile,socketHostLaunchProfile}from"./chunk-LJWC5IVX.js";import{BUILTIN_PATH_PREFIX}from"./chunk-QMRJYMNH.js";import{acquireHostEnsureLock,acquireOwnershipSafeLock,anyGenerationLive,endpointKindOfSocket,gcEndpoint,gcHostEndpoints,hostEnsureLockOptions,hostEnsureLockTarget,listHostEndpoints,socketNeedsHandshake}from"./chunk-6JXPZACL.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{DEFAULT_HOST_IDLE_EXIT_MS,INTERNAL_SUPERVISOR_FLAG,OBSERVE_REQUEST_FIELD,readHostCrashRecords,resolveCliMainPath,rpcHostExecArgv}from"./chunk-HKG7XL4H.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV}from"./chunk-CIRZTP7W.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,MAX_SOCKET_PATH_BYTES,ProcessIdentityUnreadableError,claimOwnerIsLive,clearHostRegistration,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,ensureEndpointIdentity,generationBindPath,generationPaths,hostDaemonDirectoryPaths,parseDaemonPidFile,parseJson,parseShardSocket,processIsLive,processMatchesPidFile,provenOwner,pruneDeadGenerations,readFileOrUndefined,readGenerationRows,readHostProcessMetrics,readHostRegistration,readHostSettings,readProcessStartTime,readSessionPathClaims,readSocketSecret,releaseGeneration,resolveSocketTransportAddress,sameEndpoint,sendSocketHandshake,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,socketSecretPath,statSocketIdentity,waitForStartTime,writeGenerationRecord,writeHostRegistration,writeHostSettings,writeStateFile,writtenByThisProcess}from"./chunk-22DAHAHO.js";import{compareEngineOrdinal,engineBuildIdentity}from"./chunk-XYDZ3LIE.js";import{isSessionRuntimeKind}from"./chunk-MH2BFYGN.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-463OK2Y4.js";import{writeSync}from"node:fs";import{join as join7,resolve as resolve3}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path=>["--extension",path])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID"]);function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{createHash}from"node:crypto";import{existsSync}from"node:fs";import{readdir,readFile as readFile2,realpath as realpath2,stat as stat2}from"node:fs/promises";import{basename,dirname as dirname2,join as join2,relative as relative2,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=dirname2(fileURLToPath(import.meta.url)),packageRoot=nearestPackageRoot(moduleDir),[top,next]=relative2(packageRoot,moduleDir).split(sep);return top==="dist"?{flavour:"packaged",root:join2(packageRoot,next==="bundle"?join2("dist","bundle"):"dist")}:{flavour:"dev",root:join2(packageRoot,top??"")}}function nearestPackageRoot(start){for(let dir=start;;dir=dirname2(dir)){if(existsSync(join2(dir,"package.json")))return dir;if(dirname2(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 stat2(root)).isFile()?files.push(["",root]):await collect(await realpath2(root),"",files,new Set);let digests=await mapLimited(files,READ_CONCURRENCY,async([path,file])=>[path,sha256(await readFile2(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=join2(dir,entry.name),name=prefix===""?entry.name:`${prefix}/${entry.name}`,kind=entry.isSymbolicLink()?await stat2(path).catch(()=>{}):entry;kind!==void 0&&(kind.isDirectory()?await collect(await realpath2(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")}function parseHostProtocolInfo(data){if(!isRecord2(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);return{protocolVersion:typeof data.protocolVersion=="number"?data.protocolVersion:0,serverVersion:data.serverVersion,capabilities:data.capabilities,...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},...runtimeBuildId!==void 0&&{runtimeBuildId},...isRecord2(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(!isRecord2(value)||typeof value.profile_id!="string"||!isRecord2(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 isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var HOST_PROTOCOL_VERSION=1,GENERATION_HANDOFF_CAPABILITY="generation_handoff",REQUIRED_HOST_CAPABILITIES=["multi_session",EXTENSION_EVENTS_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY],HostEnsureRefusedError=class extends Error{constructor(socket,reason,host,detail){super(`RPC socket ${socket} refused: ${reason} - ${refusalDetail(reason,host)}${detail?`: ${detail}`:""}`),this.name="HostEnsureRefusedError",this.socket=socket,this.reason=reason,this.detail=detail}};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"its pidfile was written by another process, so this one may not signal it; stop that host explicitly instead";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";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.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{mkdir,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname5}from"node:path";function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:REQUIRED_HOST_CAPABILITIES,identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile3}from"node:fs/promises";var SIGKILL_GRACE_MS=2e3;async function matchesPidFileOrUnknown(pidFile,probe){try{return await processMatchesPidFile(pidFile,probe)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!1;throw error}}async function stopSpawnedChild(child,childExit,termTimeoutMs){let exited=()=>child.exitCode!==null||child.signalCode!==null;if(exited())return;let signal=name=>{try{child.kill(name)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}},waitFor=ms=>Promise.race([childExit.then(()=>!0),delay(ms).then(()=>exited())]);if(signal("SIGTERM"),!await waitFor(termTimeoutMs)&&(signal("SIGKILL"),!await waitFor(SIGKILL_GRACE_MS)))throw new Error(`RPC socket host pid ${child.pid??"?"} remained alive after SIGKILL`)}async function stopManagedHost(pidFile,termTimeoutMs,readStartTime=readProcessStartTime){if(await signalValidated(pidFile,"SIGTERM",readStartTime),!await waitForGone(pidFile,termTimeoutMs,readStartTime)&&(await signalValidated(pidFile,"SIGKILL",readStartTime),!await waitForGone(pidFile,SIGKILL_GRACE_MS,readStartTime)))throw new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`)}async function resolvePidFileOwnership(pidFile,readStartTime){try{return await processMatchesPidFile(pidFile,readStartTime,processIsLive,{attempts:1})?"owns":"gone"}catch(error){if(error instanceof ProcessIdentityUnreadableError)return"unknown";throw error}}async function signalValidated(pidFile,signal,readStartTime=readProcessStartTime){if(await resolvePidFileOwnership(pidFile,readStartTime)==="owns")try{process.kill(pidFile.pid,signal)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}}async function waitForGone(pidFile,timeoutMs,readStartTime=readProcessStartTime){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await resolvePidFileOwnership(pidFile,readStartTime)==="gone")return!0;await delay(50)}return await resolvePidFileOwnership(pidFile,readStartTime)==="gone"}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}import{existsSync as existsSync2}from"node:fs";import{basename as basename2,dirname as dirname3,resolve as resolve2}from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...rpcHostExecArgv(),sibling,...supervisorArgs]}:{command:process.execPath,args:[...rpcHostExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath2(import.meta.url);if(basename2(dirname3(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname3(modulePath),`host-lifecycle${extension}`);return existsSync2(sibling)?sibling:void 0}import{createConnection}from"node:net";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,PROBE_REQUEST_ID="ensure-host-probe";function probeHost(options){return probeProtocolInfo(options.socket,options.timeoutMs??DEFAULT_PROBE_TIMEOUT_MS)}async function probeProtocolInfo(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info"},timeoutMs);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function observeProtocolInfo(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info",[OBSERVE_REQUEST_FIELD]:!0},timeoutMs);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function holdProtocolInfo(socketPath,timeoutMs){let outcome=await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs,!0),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){return(await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs)).connected}async function probeSessionCount(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"list_sessions",include_workers:!0},timeoutMs);if(!(!isRecord3(reply)||!Array.isArray(reply.sessions)))return reply.sessions.length}async function requestOnSocket(socketPath,command,timeoutMs){return(await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,...command},timeoutMs)).answer}async function connectAndAsk(socketPath,request,timeoutMs,keep=!1){let secret;if(socketNeedsHandshake(socketPath))try{secret=await readSocketSecret(socketSecretPath(socketPath))}catch{return{connected:!1,answer:void 0}}return new Promise(resolveProbe=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform,secret)),buffer="",settled=!1,connected=!1,finish=value=>{if(!settled){if(settled=!0,clearTimeout(timeout),keep&&value!==void 0&&!socket.destroyed){resolveProbe({connected,answer:value,kept:socket});return}socket.destroy(),resolveProbe({connected,answer:value})}},timeout=setTimeout(()=>finish(),timeoutMs);socket.once("connect",()=>{connected=!0,socket.write(`${JSON.stringify(request)}
|
|
2
|
+
import{CUSTOM_UNSUPPORTED_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,RPC_CLIENT_CAPABILITIES_ENV,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,hostLaunchProfile,socketHostLaunchProfile}from"./chunk-K3BXFPWZ.js";import{BUILTIN_PATH_PREFIX}from"./chunk-QMRJYMNH.js";import{acquireHostEnsureLock,acquireOwnershipSafeLock,anyGenerationLive,endpointKindOfSocket,gcEndpoint,gcHostEndpoints,hostEnsureLockOptions,hostEnsureLockTarget,listHostEndpoints,socketNeedsHandshake}from"./chunk-6JXPZACL.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{DEFAULT_HOST_IDLE_EXIT_MS,INTERNAL_SUPERVISOR_FLAG,OBSERVE_REQUEST_FIELD,readHostCrashRecords,resolveCliMainPath,rpcHostExecArgv}from"./chunk-HKG7XL4H.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV}from"./chunk-CIRZTP7W.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,MAX_SOCKET_PATH_BYTES,ProcessIdentityUnreadableError,claimOwnerIsLive,clearHostRegistration,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,ensureEndpointIdentity,generationBindPath,generationPaths,hostDaemonDirectoryPaths,parseDaemonPidFile,parseJson,parseShardSocket,processIsLive,processMatchesPidFile,provenOwner,pruneDeadGenerations,readFileOrUndefined,readGenerationRows,readHostProcessMetrics,readHostRegistration,readHostSettings,readProcessStartTime,readSessionPathClaims,readSocketSecret,releaseGeneration,resolveSocketTransportAddress,sameEndpoint,sendSocketHandshake,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,socketSecretPath,statSocketIdentity,waitForStartTime,writeGenerationRecord,writeHostRegistration,writeHostSettings,writeStateFile,writtenByThisProcess}from"./chunk-22DAHAHO.js";import{compareEngineOrdinal,engineBuildIdentity}from"./chunk-XYDZ3LIE.js";import{isSessionRuntimeKind}from"./chunk-MH2BFYGN.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-463OK2Y4.js";import{writeSync}from"node:fs";import{join as join7,resolve as resolve3}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path=>["--extension",path])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^BSK_(HOME|BIN)$/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","OMO_BROWSER_ENGINE","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID"]);function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{createHash}from"node:crypto";import{existsSync}from"node:fs";import{readdir,readFile as readFile2,realpath as realpath2,stat as stat2}from"node:fs/promises";import{basename,dirname as dirname2,join as join2,relative as relative2,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=dirname2(fileURLToPath(import.meta.url)),packageRoot=nearestPackageRoot(moduleDir),[top,next]=relative2(packageRoot,moduleDir).split(sep);return top==="dist"?{flavour:"packaged",root:join2(packageRoot,next==="bundle"?join2("dist","bundle"):"dist")}:{flavour:"dev",root:join2(packageRoot,top??"")}}function nearestPackageRoot(start){for(let dir=start;;dir=dirname2(dir)){if(existsSync(join2(dir,"package.json")))return dir;if(dirname2(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 stat2(root)).isFile()?files.push(["",root]):await collect(await realpath2(root),"",files,new Set);let digests=await mapLimited(files,READ_CONCURRENCY,async([path,file])=>[path,sha256(await readFile2(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=join2(dir,entry.name),name=prefix===""?entry.name:`${prefix}/${entry.name}`,kind=entry.isSymbolicLink()?await stat2(path).catch(()=>{}):entry;kind!==void 0&&(kind.isDirectory()?await collect(await realpath2(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")}function parseHostProtocolInfo(data){if(!isRecord2(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);return{protocolVersion:typeof data.protocolVersion=="number"?data.protocolVersion:0,serverVersion:data.serverVersion,capabilities:data.capabilities,...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},...runtimeBuildId!==void 0&&{runtimeBuildId},...isRecord2(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(!isRecord2(value)||typeof value.profile_id!="string"||!isRecord2(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 isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var HOST_PROTOCOL_VERSION=1,GENERATION_HANDOFF_CAPABILITY="generation_handoff",REQUIRED_HOST_CAPABILITIES=["multi_session",EXTENSION_EVENTS_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY],HostEnsureRefusedError=class extends Error{constructor(socket,reason,host,detail){super(`RPC socket ${socket} refused: ${reason} - ${refusalDetail(reason,host)}${detail?`: ${detail}`:""}`),this.name="HostEnsureRefusedError",this.socket=socket,this.reason=reason,this.detail=detail}};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"its pidfile was written by another process, so this one may not signal it; stop that host explicitly instead";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";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.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{mkdir,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname5}from"node:path";function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:REQUIRED_HOST_CAPABILITIES,identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile3}from"node:fs/promises";var SIGKILL_GRACE_MS=2e3;async function matchesPidFileOrUnknown(pidFile,probe){try{return await processMatchesPidFile(pidFile,probe)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!1;throw error}}async function stopSpawnedChild(child,childExit,termTimeoutMs){let exited=()=>child.exitCode!==null||child.signalCode!==null;if(exited())return;let signal=name=>{try{child.kill(name)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}},waitFor=ms=>Promise.race([childExit.then(()=>!0),delay(ms).then(()=>exited())]);if(signal("SIGTERM"),!await waitFor(termTimeoutMs)&&(signal("SIGKILL"),!await waitFor(SIGKILL_GRACE_MS)))throw new Error(`RPC socket host pid ${child.pid??"?"} remained alive after SIGKILL`)}async function stopManagedHost(pidFile,termTimeoutMs,readStartTime=readProcessStartTime){if(await signalValidated(pidFile,"SIGTERM",readStartTime),!await waitForGone(pidFile,termTimeoutMs,readStartTime)&&(await signalValidated(pidFile,"SIGKILL",readStartTime),!await waitForGone(pidFile,SIGKILL_GRACE_MS,readStartTime)))throw new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`)}async function resolvePidFileOwnership(pidFile,readStartTime){try{return await processMatchesPidFile(pidFile,readStartTime,processIsLive,{attempts:1})?"owns":"gone"}catch(error){if(error instanceof ProcessIdentityUnreadableError)return"unknown";throw error}}async function signalValidated(pidFile,signal,readStartTime=readProcessStartTime){if(await resolvePidFileOwnership(pidFile,readStartTime)==="owns")try{process.kill(pidFile.pid,signal)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}}async function waitForGone(pidFile,timeoutMs,readStartTime=readProcessStartTime){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await resolvePidFileOwnership(pidFile,readStartTime)==="gone")return!0;await delay(50)}return await resolvePidFileOwnership(pidFile,readStartTime)==="gone"}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}import{existsSync as existsSync2}from"node:fs";import{basename as basename2,dirname as dirname3,resolve as resolve2}from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...rpcHostExecArgv(),sibling,...supervisorArgs]}:{command:process.execPath,args:[...rpcHostExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath2(import.meta.url);if(basename2(dirname3(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname3(modulePath),`host-lifecycle${extension}`);return existsSync2(sibling)?sibling:void 0}import{createConnection}from"node:net";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,PROBE_REQUEST_ID="ensure-host-probe";function probeHost(options){return probeProtocolInfo(options.socket,options.timeoutMs??DEFAULT_PROBE_TIMEOUT_MS)}async function probeProtocolInfo(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info"},timeoutMs);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function observeProtocolInfo(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"get_protocol_info",[OBSERVE_REQUEST_FIELD]:!0},timeoutMs);return reply===void 0?void 0:parseHostProtocolInfo(reply)}async function holdProtocolInfo(socketPath,timeoutMs){let outcome=await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs,!0),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){return(await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,type:"get_protocol_info"},timeoutMs)).connected}async function probeSessionCount(socketPath,timeoutMs){let reply=await requestOnSocket(socketPath,{type:"list_sessions",include_workers:!0},timeoutMs);if(!(!isRecord3(reply)||!Array.isArray(reply.sessions)))return reply.sessions.length}async function requestOnSocket(socketPath,command,timeoutMs){return(await connectAndAsk(socketPath,{id:PROBE_REQUEST_ID,...command},timeoutMs)).answer}async function connectAndAsk(socketPath,request,timeoutMs,keep=!1){let secret;if(socketNeedsHandshake(socketPath))try{secret=await readSocketSecret(socketSecretPath(socketPath))}catch{return{connected:!1,answer:void 0}}return new Promise(resolveProbe=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform,secret)),buffer="",settled=!1,connected=!1,finish=value=>{if(!settled){if(settled=!0,clearTimeout(timeout),keep&&value!==void 0&&!socket.destroyed){resolveProbe({connected,answer:value,kept:socket});return}socket.destroy(),resolveProbe({connected,answer:value})}},timeout=setTimeout(()=>finish(),timeoutMs);socket.once("connect",()=>{connected=!0,socket.write(`${JSON.stringify(request)}
|
|
3
3
|
`)}),socket.on("data",chunk=>{for(buffer+=chunk.toString("utf8");;){let newline=buffer.indexOf(`
|
|
4
|
-
`);if(newline===-1)return;let line=buffer.slice(0,newline);buffer=buffer.slice(newline+1);let answer2=readAnswer(line);if(answer2!==void 0)return finish(answer2)}}),socket.once("error",()=>finish()),socket.once("close",()=>finish()),secret&&sendSocketHandshake(socket,secret)})}function readAnswer(text){let parsed;try{parsed=JSON.parse(text)}catch{return}if(!(!isRecord3(parsed)||parsed.id!==PROBE_REQUEST_ID||parsed.success!==!0))return parsed.data??{}}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SPAWNED_HOST_PROBE_TIMEOUT_MS=1e4;async function pollProtocolInfo(socket,timeoutMs,isCompatible2,childExit){let deadline=Date.now()+timeoutMs,lastProtocol;for(;Date.now()<=deadline;){let probe=holdProtocolInfo(socket,Math.min(SPAWNED_HOST_PROBE_TIMEOUT_MS,Math.max(1,deadline-Date.now()))),raced=childExit?await Promise.race([probe,childExit]):await probe;if(isChildExit(raced)){let held=await probe;if(!held)return{ready:!1,protocol:lastProtocol,exited:raced};if(lastProtocol=held.info,isCompatible2(held.info))return{ready:!0,protocol:held.info,hold:held.hold};held.hold.release()}else if(raced){if(lastProtocol=raced.info,isCompatible2(raced.info))return{ready:!0,protocol:raced.info,hold:raced.hold};raced.hold.release()}await delay2(50)}return{ready:!1,protocol:lastProtocol}}function isChildExit(value){return!!value&&"code"in value&&"signal"in value}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}var EXPECTED_RUNTIME_BUILD_ID_ENV="SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID",NEW_WORK_COMMANDS=new Set(["prompt","steer","follow_up","send_custom_message","append_user_message","bash","compact","wake","edit_assistant_message","edit_user_message"]),DEFAULT_POLL_MS=200,HostIdleHandover=class{constructor(options){this.options=options}view(){return this.operation?.view}admits(commandType){let state=this.operation?.view.state;return state===void 0||state==="handover_blocked"||!NEW_WORK_COMMANDS.has(commandType)}async begin(request){let current=this.operation;if(current!==void 0&¤t.view.operationId===request.operationId)return sameTerms(current.request,request)?answer(current):{kind:"refused",reason:"operation_conflict",detail:"this operation id names other terms"};if(current!==void 0&¤t.view.state!=="handover_blocked")return current.request.targetRuntimeBuildId===request.targetRuntimeBuildId?answer(current):{kind:"refused",reason:"handover_in_progress",detail:current.view.operationId};let self=this.options.identity();if(self.instanceId!==request.ifInstanceId||self.generation!==request.ifGeneration)return{kind:"refused",reason:"stale_generation",detail:`this host is ${self.instanceId} generation ${self.generation}`};if(self.runtimeBuildId===request.targetRuntimeBuildId)return{kind:"refused",reason:"already_current",detail:self.runtimeBuildId};let operation={request,view:{operationId:request.operationId,state:"handover_pending",targetRuntimeBuildId:request.targetRuntimeBuildId}};return this.operation=operation,this.options.log?.(`handover ${request.operationId} pending: no new work is admitted`),this.idleNow()?(await this.switchOver(operation),answer(operation)):(this.timer=setInterval(()=>this.observe(),this.options.pollMs??DEFAULT_POLL_MS),this.timer.unref?.(),answer(operation))}observe(){let operation=this.operation;operation?.view.state==="handover_pending"&&this.idleNow()&&this.switchOver(operation)}dispose(){this.stopTimer()}idleNow(){try{return this.options.isIdle()}catch(cause){return this.options.log?.(`handover idle check failed, waiting: ${String(cause)}`),!1}}async switchOver(operation){if(operation.view.state!=="handover_pending")return;this.stopTimer(),operation.view={...operation.view,state:"handover_switching"};let outcome=await this.options.perform(operation.request).catch(cause=>({ok:!1,reason:`successor_unavailable: ${String(cause)}`}));operation.view=outcome.ok?{...operation.view,state:"handover_completed",successor:outcome.successor}:{...operation.view,state:"handover_blocked",reason:outcome.reason},this.options.log?.(`handover ${operation.view.operationId} ${operation.view.state}`)}stopTimer(){this.timer!==void 0&&clearInterval(this.timer),this.timer=void 0}};function sameTerms(a,b){return a.targetRuntimeBuildId===b.targetRuntimeBuildId&&a.ifInstanceId===b.ifInstanceId&&a.ifGeneration===b.ifGeneration}function answer(operation){return{kind:"operation",view:operation.view}}function initialHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[ENV_AGENT_DIR]:options.agentDir??getAgentDir(),[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir})}function successorHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),...options.agentDir?{[ENV_AGENT_DIR]:options.agentDir}:{},[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir,...options.expectedRuntimeBuildId!==void 0&&{[EXPECTED_RUNTIME_BUILD_ID_ENV]:options.expectedRuntimeBuildId}})}var DEFAULT_READINESS_TIMEOUT_MS=1e4,DEFAULT_STOP_TIMEOUT_MS=1e4;async function startHost(paths,socket,options,generation=0){let testOptions=options._test,instanceId=randomUUID();process.platform==="win32"&&await createSocketSecret(socketSecretPath(socket)),await writeHostSettings(paths,{socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??9e5,generation,instanceId});let stderr=await open(paths.stderrLog,generation===0?"w":"a",384),pidFile,child,exitedEarly,childExit;try{let supervisorArgs=["--socket",socket,...options.hostArgs??[]],launch=testOptions?.spawn??testOptions?.launch?.(supervisorArgs)??defaultHostLaunch(supervisorArgs);if(child=spawn(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:initialHostEnvironment({agentDir:options.agentDir,env:options.env,paths,instanceId,generation}),stdio:["ignore","ignore",stderr.fd]}),childExit=new Promise(resolveExit=>{child.once("exit",(code,signal)=>{exitedEarly={code,signal},resolveExit(exitedEarly)})}),child.pid===void 0)throw new Error("failed to spawn RPC socket host");let probe=testOptions?.readProcessStartTime??readProcessStartTime,observedStartTime=await Promise.race([waitForStartTime(child.pid,1e4,probe),childExit.then(()=>{throw new Error("RPC socket host exited before its start time could be read")})]),unhurriedProbe=testOptions?.readProcessStartTime?testOptions.readProcessStartTime:pid=>readProcessStartTime(pid,process.platform,15e3),processStartTime=observedStartTime??await unhurriedProbe(child.pid).catch(()=>{});pidFile={pid:child.pid,processStartTime:processStartTime??null},await testOptions?.beforePidFileWrite?.(),await writeHostRegistration(paths,{record:pidFile,socket,instanceId,generation,launchProfileId:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd()).profile_id}),child.unref()}catch(error){let exitedBeforeCleanup=exitedEarly;if(!exitedBeforeCleanup&&child&&child.exitCode===null&&child.signalCode===null){try{child.kill("SIGTERM")}catch{}if(childExit&&await Promise.race([childExit,delay(2e3)]),child.exitCode===null&&child.signalCode===null)try{child.kill("SIGKILL")}catch{}}if(!exitedBeforeCleanup)throw await clearHostRegistration(paths),error;let diagnostic2=await appendStderr(paths,`RPC socket host exited with code ${exitedBeforeCleanup.code??"null"}${exitedBeforeCleanup.signal?` (${exitedBeforeCleanup.signal})`:""} before answering get_protocol_info`);throw await clearHostRegistration(paths),new Error(diagnostic2)}finally{await stderr.close()}let readinessTimeoutMs=testOptions?.readinessTimeoutMs??DEFAULT_READINESS_TIMEOUT_MS,result=await pollProtocolInfo(socket,readinessTimeoutMs,isCompatible,childExit);if(result.ready)return{pid:pidFile.pid,socket,reused:!1,release:result.hold.release};let stopFailure=await stopSpawnedChild(child,childExit,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS).then(()=>{},error=>error instanceof Error?error.message:String(error)),message=result.protocol?`RPC socket host answered get_protocol_info with protocolVersion ${result.protocol.protocolVersion}, serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with protocol version ${HOST_PROTOCOL_VERSION} and required capabilities ${JSON.stringify(REQUIRED_HOST_CAPABILITIES)}`:result.exited?`RPC socket host exited with code ${result.exited.code??"null"}${result.exited.signal?` (${result.exited.signal})`:""} before answering get_protocol_info`:`spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`,diagnostic=await appendStderr(paths,stopFailure===void 0?message:`${message} (teardown also reported: ${stopFailure})`);throw await clearHostRegistration(paths),new Error(diagnostic)}async function appendStderr(paths,message){try{let stderr=(await readFile3(paths.stderrLog,"utf8")).trim();return stderr?`${message}
|
|
4
|
+
`);if(newline===-1)return;let line=buffer.slice(0,newline);buffer=buffer.slice(newline+1);let answer2=readAnswer(line);if(answer2!==void 0)return finish(answer2)}}),socket.once("error",()=>finish()),socket.once("close",()=>finish()),secret&&sendSocketHandshake(socket,secret)})}function readAnswer(text){let parsed;try{parsed=JSON.parse(text)}catch{return}if(!(!isRecord3(parsed)||parsed.id!==PROBE_REQUEST_ID||parsed.success!==!0))return parsed.data??{}}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SPAWNED_HOST_PROBE_TIMEOUT_MS=1e4;async function pollProtocolInfo(socket,timeoutMs,isCompatible2,childExit){let deadline=Date.now()+timeoutMs,lastProtocol;for(;Date.now()<=deadline;){let probe=holdProtocolInfo(socket,Math.min(SPAWNED_HOST_PROBE_TIMEOUT_MS,Math.max(1,deadline-Date.now()))),raced=childExit?await Promise.race([probe,childExit]):await probe;if(isChildExit(raced)){let held=await probe;if(!held)return{ready:!1,protocol:lastProtocol,exited:raced};if(lastProtocol=held.info,isCompatible2(held.info))return{ready:!0,protocol:held.info,hold:held.hold};held.hold.release()}else if(raced){if(lastProtocol=raced.info,isCompatible2(raced.info))return{ready:!0,protocol:raced.info,hold:raced.hold};raced.hold.release()}await delay2(50)}return{ready:!1,protocol:lastProtocol}}function isChildExit(value){return!!value&&"code"in value&&"signal"in value}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}var EXPECTED_RUNTIME_BUILD_ID_ENV="SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID",NEW_WORK_COMMANDS=new Set(["prompt","steer","follow_up","send_custom_message","continue_from_leaf","append_user_message","bash","compact","wake","edit_assistant_message","edit_user_message"]),DEFAULT_POLL_MS=200,HostIdleHandover=class{constructor(options){this.options=options}view(){return this.operation?.view}admits(commandType){let state=this.operation?.view.state;return state===void 0||state==="handover_blocked"||!NEW_WORK_COMMANDS.has(commandType)}async begin(request){let current=this.operation;if(current!==void 0&¤t.view.operationId===request.operationId)return sameTerms(current.request,request)?answer(current):{kind:"refused",reason:"operation_conflict",detail:"this operation id names other terms"};if(current!==void 0&¤t.view.state!=="handover_blocked")return current.request.targetRuntimeBuildId===request.targetRuntimeBuildId?answer(current):{kind:"refused",reason:"handover_in_progress",detail:current.view.operationId};let self=this.options.identity();if(self.instanceId!==request.ifInstanceId||self.generation!==request.ifGeneration)return{kind:"refused",reason:"stale_generation",detail:`this host is ${self.instanceId} generation ${self.generation}`};if(self.runtimeBuildId===request.targetRuntimeBuildId)return{kind:"refused",reason:"already_current",detail:self.runtimeBuildId};let operation={request,view:{operationId:request.operationId,state:"handover_pending",targetRuntimeBuildId:request.targetRuntimeBuildId}};return this.operation=operation,this.options.log?.(`handover ${request.operationId} pending: no new work is admitted`),this.idleNow()?(await this.switchOver(operation),answer(operation)):(this.timer=setInterval(()=>this.observe(),this.options.pollMs??DEFAULT_POLL_MS),this.timer.unref?.(),answer(operation))}observe(){let operation=this.operation;operation?.view.state==="handover_pending"&&this.idleNow()&&this.switchOver(operation)}dispose(){this.stopTimer()}idleNow(){try{return this.options.isIdle()}catch(cause){return this.options.log?.(`handover idle check failed, waiting: ${String(cause)}`),!1}}async switchOver(operation){if(operation.view.state!=="handover_pending")return;this.stopTimer(),operation.view={...operation.view,state:"handover_switching"};let outcome=await this.options.perform(operation.request).catch(cause=>({ok:!1,reason:`successor_unavailable: ${String(cause)}`}));operation.view=outcome.ok?{...operation.view,state:"handover_completed",successor:outcome.successor}:{...operation.view,state:"handover_blocked",reason:outcome.reason},this.options.log?.(`handover ${operation.view.operationId} ${operation.view.state}`)}stopTimer(){this.timer!==void 0&&clearInterval(this.timer),this.timer=void 0}};function sameTerms(a,b){return a.targetRuntimeBuildId===b.targetRuntimeBuildId&&a.ifInstanceId===b.ifInstanceId&&a.ifGeneration===b.ifGeneration}function answer(operation){return{kind:"operation",view:operation.view}}function initialHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[ENV_AGENT_DIR]:options.agentDir??getAgentDir(),[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir})}function successorHostEnvironment(options){return daemonEnvironment(process.env,options.env,{[RPC_CLIENT_CAPABILITIES_ENV]:PINNED_HOST_CLIENT_CAPABILITIES.join(","),...options.agentDir?{[ENV_AGENT_DIR]:options.agentDir}:{},[HOST_INSTANCE_ID_ENV]:options.instanceId,[HOST_GENERATION_ENV]:String(options.generation),[HOST_DAEMON_DIR_ENV]:options.paths.dir,...options.expectedRuntimeBuildId!==void 0&&{[EXPECTED_RUNTIME_BUILD_ID_ENV]:options.expectedRuntimeBuildId}})}var DEFAULT_READINESS_TIMEOUT_MS=1e4,DEFAULT_STOP_TIMEOUT_MS=1e4;async function startHost(paths,socket,options,generation=0){let testOptions=options._test,instanceId=randomUUID();process.platform==="win32"&&await createSocketSecret(socketSecretPath(socket)),await writeHostSettings(paths,{socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??9e5,generation,instanceId});let stderr=await open(paths.stderrLog,generation===0?"w":"a",384),pidFile,child,exitedEarly,childExit;try{let supervisorArgs=["--socket",socket,...options.hostArgs??[]],launch=testOptions?.spawn??testOptions?.launch?.(supervisorArgs)??defaultHostLaunch(supervisorArgs);if(child=spawn(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:initialHostEnvironment({agentDir:options.agentDir,env:options.env,paths,instanceId,generation}),stdio:["ignore","ignore",stderr.fd]}),childExit=new Promise(resolveExit=>{child.once("exit",(code,signal)=>{exitedEarly={code,signal},resolveExit(exitedEarly)})}),child.pid===void 0)throw new Error("failed to spawn RPC socket host");let probe=testOptions?.readProcessStartTime??readProcessStartTime,observedStartTime=await Promise.race([waitForStartTime(child.pid,1e4,probe),childExit.then(()=>{throw new Error("RPC socket host exited before its start time could be read")})]),unhurriedProbe=testOptions?.readProcessStartTime?testOptions.readProcessStartTime:pid=>readProcessStartTime(pid,process.platform,15e3),processStartTime=observedStartTime??await unhurriedProbe(child.pid).catch(()=>{});pidFile={pid:child.pid,processStartTime:processStartTime??null},await testOptions?.beforePidFileWrite?.(),await writeHostRegistration(paths,{record:pidFile,socket,instanceId,generation,launchProfileId:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd()).profile_id}),child.unref()}catch(error){let exitedBeforeCleanup=exitedEarly;if(!exitedBeforeCleanup&&child&&child.exitCode===null&&child.signalCode===null){try{child.kill("SIGTERM")}catch{}if(childExit&&await Promise.race([childExit,delay(2e3)]),child.exitCode===null&&child.signalCode===null)try{child.kill("SIGKILL")}catch{}}if(!exitedBeforeCleanup)throw await clearHostRegistration(paths),error;let diagnostic2=await appendStderr(paths,`RPC socket host exited with code ${exitedBeforeCleanup.code??"null"}${exitedBeforeCleanup.signal?` (${exitedBeforeCleanup.signal})`:""} before answering get_protocol_info`);throw await clearHostRegistration(paths),new Error(diagnostic2)}finally{await stderr.close()}let readinessTimeoutMs=testOptions?.readinessTimeoutMs??DEFAULT_READINESS_TIMEOUT_MS,result=await pollProtocolInfo(socket,readinessTimeoutMs,isCompatible,childExit);if(result.ready)return{pid:pidFile.pid,socket,reused:!1,release:result.hold.release};let stopFailure=await stopSpawnedChild(child,childExit,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS).then(()=>{},error=>error instanceof Error?error.message:String(error)),message=result.protocol?`RPC socket host answered get_protocol_info with protocolVersion ${result.protocol.protocolVersion}, serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with protocol version ${HOST_PROTOCOL_VERSION} and required capabilities ${JSON.stringify(REQUIRED_HOST_CAPABILITIES)}`:result.exited?`RPC socket host exited with code ${result.exited.code??"null"}${result.exited.signal?` (${result.exited.signal})`:""} before answering get_protocol_info`:`spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`,diagnostic=await appendStderr(paths,stopFailure===void 0?message:`${message} (teardown also reported: ${stopFailure})`);throw await clearHostRegistration(paths),new Error(diagnostic)}async function appendStderr(paths,message){try{let stderr=(await readFile3(paths.stderrLog,"utf8")).trim();return stderr?`${message}
|
|
5
5
|
${stderr}`:message}catch(error){if(isNodeErrorCode(error,"ENOENT"))return message;throw error}}import{appendFile}from"node:fs/promises";import{basename as basename3,join as join4}from"node:path";import{readFile as readFile4,rename,writeFile}from"node:fs/promises";import{join as join3}from"node:path";var GC_SKIP_INITIAL_BACKOFF_MS=10*6e4,GC_SKIP_MAX_BACKOFF_MS=1440*6e4,skipEntrySchema=external_exports.object({skipUntil:external_exports.number(),backoffMs:external_exports.number()}),markerSchema=external_exports.object({completedAt:external_exports.number(),cursor:external_exports.string().nullable(),examined:external_exports.number(),removed:external_exports.number(),stoppedBy:external_exports.enum(["time","count","exhausted"]),skip:external_exports.record(external_exports.string(),skipEntrySchema)});function hostGcPassMarkerPath(agentDir){return join3(agentDir,"rpc-host-daemon","gc-last-run.json")}function parseHostGcPassMarker(text){try{let parsed=markerSchema.safeParse(JSON.parse(text));return parsed.success?parsed.data:void 0}catch(error){if(error instanceof SyntaxError)return;throw error}}async function readHostGcPassMarker(agentDir){let text=await readFile4(hostGcPassMarkerPath(agentDir),"utf8").catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});return text===void 0?void 0:parseHostGcPassMarker(text)}async function writeHostGcPassMarker(agentDir,marker){let path=hostGcPassMarkerPath(agentDir),staged=`${path}.${process.pid}.tmp`;await writeFile(staged,`${JSON.stringify(marker)}
|
|
6
6
|
`,{mode:384}),await rename(staged,path)}function nextSkip(previous,now){let backoffMs=previous===void 0?GC_SKIP_INITIAL_BACKOFF_MS:Math.min(previous.backoffMs*2,GC_SKIP_MAX_BACKOFF_MS);return{skipUntil:now+backoffMs,backoffMs}}var OPPORTUNISTIC_GC_BUDGET={budgetMs:1500,maxEndpoints:32,minIntervalMs:3e5};async function gcHostEndpointsOpportunistically(options){let now=options.now??Date.now,budgetMs=options.budgetMs??OPPORTUNISTIC_GC_BUDGET.budgetMs,maxEndpoints=options.maxEndpoints??OPPORTUNISTIC_GC_BUDGET.maxEndpoints,minIntervalMs=options.minIntervalMs??OPPORTUNISTIC_GC_BUDGET.minIntervalMs,previous=await readHostGcPassMarker(options.agentDir),startedAt=now();if(previous!==void 0&&startedAt-previous.completedAt<minIntervalMs)return{ran:!1};let candidates=await gcCandidates(options),present=new Set(candidates.map(endpoint=>endpoint.name)),skip={};for(let[name,entry]of Object.entries(previous?.skip??{}))present.has(name)&&(skip[name]=entry);let cursor=previous?.cursor??null,examined=0,removed=0,stoppedBy="exhausted";for(let endpoint of rotateAfter(candidates,cursor)){if((skip[endpoint.name]?.skipUntil??0)>now())continue;if(examined>=maxEndpoints){stoppedBy="count";break}if(now()-startedAt>=budgetMs){stoppedBy="time";break}examined+=1,cursor=endpoint.name,(await gcEndpoint(endpoint.socket,endpoint.dir,{}).catch(()=>({removed:!1}))).removed?(removed+=1,delete skip[endpoint.name]):skip[endpoint.name]=nextSkip(skip[endpoint.name],now())}let marker={completedAt:now(),cursor,examined,removed,stoppedBy,skip};return await writeHostGcPassMarker(options.agentDir,marker),{ran:!0,marker}}var passesRunning=new Map;function scheduleOpportunisticHostGc(options){if(passesRunning.has(options.agentDir))return;let pass=new Promise(resolve4=>{setImmediate(()=>{gcHostEndpointsOpportunistically(options).then(()=>{},error=>recordPassFailure(options.agentDir,error)).finally(()=>{passesRunning.delete(options.agentDir),resolve4()})}).unref()});passesRunning.set(options.agentDir,pass)}async function gcCandidates(options){let targetName=basename3(createHostDaemonPaths({socket:options.exclude,agentDir:options.agentDir}).dir),candidates=[];for(let endpoint of await listHostEndpoints(options.agentDir)){let name=basename3(endpoint.dir);endpoint.socket===null||name===targetName||sameEndpoint(endpoint.socket,options.exclude)||candidates.push({...endpoint,socket:endpoint.socket,name})}return candidates}function rotateAfter(endpoints,cursor){if(cursor===null)return endpoints;let start=endpoints.findIndex(endpoint=>endpoint.name>cursor);return start<=0?endpoints:[...endpoints.slice(start),...endpoints.slice(0,start)]}async function recordPassFailure(agentDir,error){let line=`${new Date().toISOString()} gc pass failed: ${error instanceof Error?error.message:String(error)}
|
|
7
7
|
`;await appendFile(join4(agentDir,"rpc-host-daemon","gc-pass.log"),line,{mode:384}).catch(logError=>{logError instanceof Error&&"code"in logError&&logError.code==="ENOENT"||process.emitWarning(`host gc pass failed and could not be recorded: ${String(logError)}`)})}import{spawn as spawn2}from"node:child_process";import{randomUUID as randomUUID2}from"node:crypto";import{open as open2,rm,writeFile as writeFile2}from"node:fs/promises";import{dirname as dirname4,join as join5}from"node:path";var LEGACY_PROBE_TIMEOUT_MS=1e4,DRAIN_POLL_MS=50;async function retireIdleLegacyHost(paths,probe,drainTimeoutMs){let judged=await judgeLegacyHost(paths,probe);if(judged.verdict==="absent")return;if(judged.verdict==="held")return judged.detail;let{record,socket}=judged.host;if(!await drainAndWait(record,probe,drainTimeoutMs))return`pid ${record.pid} (${socket}) was asked to drain and is still running after ${drainTimeoutMs}ms; retry once it exits`}async function readLegacyHost(paths){let text=await readFileOrUndefined(paths.legacyPidFile),record=text===void 0?void 0:parseDaemonPidFile(text);if(record===void 0)return;let stamped=parseJson(text)?.socket;return{record,socket:typeof stamped=="string"?stamped:join5(dirname4(paths.flatDir),"rpc","rpc.sock")}}async function provenLegacyOwner(paths,socket){let legacy=await readLegacyHost(paths),startTime=legacy?.record.processStartTime;if(!legacy||startTime===null||startTime===void 0||!sameEndpoint(legacy.socket,socket))return;let identity={pid:legacy.record.pid,processStartTime:startTime};return await processMatchesPidFile(identity,readProcessStartTime).catch(()=>!1)?identity:void 0}async function judgeLegacyHost(paths,probe,platform=process.platform){let host=await readLegacyHost(paths);if(host===void 0)return{verdict:"absent"};let{pid}=host.record,identity=await processMatchesPidFile(host.record,probe).then(owns=>owns?"proven":"gone",error=>{if(error instanceof ProcessIdentityUnreadableError)return"unreadable";throw error});if(identity==="gone")return{verdict:"absent"};let where=`pid ${pid} (${host.socket})`;if(identity==="unreadable")return{verdict:"held",detail:`${where} cannot be proven to be the process its record names; stop it by hand`};if(platform==="win32")return{verdict:"held",detail:`${where} cannot be drained on win32; it exits once idle, then retry`};let protocol=await probeProtocolInfo(host.socket,LEGACY_PROBE_TIMEOUT_MS);if(!protocol?.capabilities.includes(GENERATION_HANDOFF_CAPABILITY))return{verdict:"held",detail:`${where} ${protocol?"cannot drain":"does not answer"}; it is never signalled - stop it by hand, then retry`};let sessions=await probeSessionCount(host.socket,LEGACY_PROBE_TIMEOUT_MS);if(sessions===0)return{verdict:"idle",host};let held=sessions===void 0?"an unknown number of sessions":`${sessions} open session${sessions===1?"":"s"}`;return{verdict:"held",detail:`${where} holds ${held}; run \`${APP_NAME} host stop --drain --socket ${host.socket}\` to let it finish that work and exit, then retry`}}async function drainAndWait(record,probe,timeoutMs){try{process.kill(record.pid,"SIGUSR1")}catch(error){if(!(error instanceof Error&&"code"in error&&error.code==="ESRCH"))throw error}let stillRunning=()=>processMatchesPidFile(record,probe,processIsLive,{attempts:1}).catch(error=>{if(error instanceof ProcessIdentityUnreadableError)return!0;throw error}),deadline=Date.now()+timeoutMs;for(;await stillRunning();){if(Date.now()>deadline)return!1;await new Promise(resolve4=>setTimeout(resolve4,DRAIN_POLL_MS))}return!0}async function stopHost(options){let paths=createHostDaemonPaths({socket:options.socket,...options.agentDir?{agentDir:options.agentDir}:{}}),registered=await readHostRegistration(paths),owner=await provenOwner(registered,options.socket);if(options.drain===!0){let pid=owner?.pid??(await provenLegacyOwner(paths,options.socket))?.pid;return pid===void 0?{action:"refuse",reason:"unknown_owner"}:!(await probeProtocolInfo(options.socket,options.timeoutMs??1e4))?.capabilities.includes(GENERATION_HANDOFF_CAPABILITY)||process.platform==="win32"?{action:"refuse",reason:"drain_unsupported"}:(signalGeneration(pid,"SIGUSR1"),{action:"drained",pid})}if(!owner)return{action:"refuse",reason:"unknown_owner"};let host=await probeProtocolInfo(options.socket,options.timeoutMs??1e4),sessions=await probeSessionCount(options.socket,options.timeoutMs??1e4);return options.force!==!0&&host!==void 0&&sessions!==void 0&&sessions>0?{action:"refuse",reason:"sessions_live"}:(signalGeneration(owner.pid,"SIGTERM"),await releaseGeneration(paths,{instanceId:owner.instanceId,pid:owner.pid}),{action:"stopped",pid:owner.pid})}function signalGeneration(pid,signal){try{return process.kill(pid,signal),!0}catch(error){if(error instanceof Error&&"code"in error&&error.code==="ESRCH")return!1;throw error}}var DEFAULT_HANDOFF_READINESS_MS=3e4,SUCCESSOR_EXIT_WAIT_MS=5e3,SUCCESSOR_START_BUDGET_MS=1e4+DEFAULT_HANDOFF_READINESS_MS+2e3+SUCCESSOR_EXIT_WAIT_MS;async function startSuccessor(context){let{options,paths,host,owner}=context,generation=(host.generation??0)+1,instanceId=randomUUID2(),bindSocket=generationBindPath(options.socket,generation);if(Buffer.byteLength(bindSocket)>MAX_SOCKET_PATH_BYTES)return{action:"refuse",reason:"socket_path_too_long",upgradeable:!0,detail:bindSocket};let replaced=await statSocketIdentity(options.socket);if(!replaced)return{action:"refuse",reason:"socket_replaced",upgradeable:!0};let running=await readHostSettings(paths),bootSettings=await readFileOrUndefined(paths.settingsFile);await writeHostSettings(paths,{socket:options.socket,capabilities:PINNED_HOST_CLIENT_CAPABILITIES,coldStart:options.policy?.coldStart??running?.coldStart??"transient",idleExitMs:options.policy?.idleExitMs??running?.idleExitMs??9e5,generation,instanceId});let child,exited;try{await options._test?.beforeSpawn?.();let argv=["--socket",options.socket,"--bind",bindSocket,"--replace",`${replaced.dev}:${replaced.ino}`,...options.hostArgs??[]],launch=(options._test?.launch??options.launch)?.(argv)??defaultHostLaunch(argv),stderr=await open2(paths.stderrLog,"a",384),spawned=spawn2(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:successorHostEnvironment({agentDir:options.agentDir,env:options.env,expectedRuntimeBuildId:options.expectedRuntimeBuildId,paths,generation,instanceId}),stdio:["ignore","ignore",stderr.fd]});if(await stderr.close(),child=spawned,exited=new Promise(resolve4=>spawned.once("exit",()=>resolve4())),child.pid===void 0)throw new Error("failed to spawn the successor generation");let processStartTime=await waitForStartTime(child.pid,1e4).catch(()=>{})??null,registration={record:{pid:child.pid,processStartTime},socket:options.socket,instanceId,generation,launchProfileId:hostLaunchProfile(["--mode","rpc","--multi-session",...options.hostArgs??[]],process.cwd()).profile_id};await writeGenerationRecord(paths,registration),await options._test?.afterSpawn?.(child.pid);let answer2=await awaitSuccessor(options,host,exited);if(!answer2){let reason=await abortReason(options.socket,replaced),cleanupFailure=await abandonSuccessor({child,exited,paths,instanceId,bootSettings});return{action:"refuse",reason,upgradeable:!0,...cleanupFailure&&{detail:cleanupFailure}}}return await options._test?.beforeRegistration?.(),await writeHostRegistration(paths,registration),child.unref(),signalGeneration(owner.pid,"SIGUSR1"),{action:"handoff",pid:child.pid,socket:options.socket,generation:answer2.generation??generation,instanceId:answer2.instanceId??""}}catch(cause){let cleanupFailure=await abandonSuccessor({child,exited,paths,instanceId,bootSettings}),detail=cause instanceof Error?cause.message:String(cause);return{action:"refuse",reason:"successor_unavailable",upgradeable:!0,detail:cleanupFailure?`${detail}; ${cleanupFailure}`:detail}}}async function abandonSuccessor(context){let{child,exited,paths,instanceId,bootSettings}=context;child!==void 0&&child.exitCode===null&&child.signalCode===null&&child.kill("SIGKILL");try{bootSettings===void 0?await rm(paths.settingsFile,{force:!0}):await writeFile2(paths.settingsFile,bootSettings,{mode:HOST_STATE_FILE_MODE}),child?.pid===void 0?await rm(generationPaths(paths,instanceId).dir,{recursive:!0,force:!0}):exited!==void 0&&await exitedWithin(exited,SUCCESSOR_EXIT_WAIT_MS)&&await releaseGeneration(paths,{instanceId,pid:child.pid});return}catch(cause){return`successor cleanup failed: ${cause instanceof Error?cause.message:String(cause)}`}}async function exitedWithin(exited,ms){let timer,timedOut=new Promise(resolve4=>{timer=setTimeout(()=>resolve4(!1),ms)});try{return await Promise.race([exited.then(()=>!0),timedOut])}finally{clearTimeout(timer)}}async function awaitSuccessor(options,previous,exited){let deadline=Date.now()+(options._test?.readinessTimeoutMs??DEFAULT_HANDOFF_READINESS_MS),childGone=!1;for(exited.then(()=>{childGone=!0});Date.now()<=deadline;){let answer2=await probeProtocolInfo(options.socket,2e3);if(answer2&&answer2.instanceId!==void 0&&answer2.instanceId!==previous.instanceId)return answer2;if(childGone)return;await delay3(50)}}async function abortReason(socket,replaced){let current=await statSocketIdentity(socket).catch(()=>{});return current===void 0||current.dev!==replaced.dev||current.ino!==replaced.ino?"socket_replaced":"successor_unavailable"}function delay3(ms){return new Promise(resolve4=>setTimeout(resolve4,ms))}var HANDOFF_PROBE_TIMEOUT_MS=1e4,HANDOFF_LOCK_HOLD_MS=HANDOFF_PROBE_TIMEOUT_MS+SUCCESSOR_START_BUDGET_MS,HANDOFF_LOCK_WAIT_MS=HANDOFF_PROBE_TIMEOUT_MS+HANDOFF_LOCK_HOLD_MS+1e4;async function handoffHost(options){if(handoffUnsupported(options))return{action:"refuse",reason:"upgrade_unsupported",upgradeable:!1};let release=await acquireHostEnsureLock(options.socket,HANDOFF_LOCK_WAIT_MS);try{return await handoffHostLocked(options)}finally{await release()}}async function handoffHostLocked(options){if(handoffUnsupported(options))return{action:"refuse",reason:"upgrade_unsupported",upgradeable:!1};let paths=createHostDaemonPaths({socket:options.socket,...options.agentDir?{agentDir:options.agentDir}:{}});await createDaemonDirectories(paths);let host=await probeProtocolInfo(options.socket,HANDOFF_PROBE_TIMEOUT_MS);if(!host)return{action:"refuse",reason:"no_host",upgradeable:!1};if(!host.capabilities.includes(GENERATION_HANDOFF_CAPABILITY))return{action:"refuse",reason:"handoff_unsupported",upgradeable:!1};let registered=await readHostRegistration(paths),owner=await provenOwner(registered,options.socket);return owner?startSuccessor({options,paths,host,owner}):{action:"refuse",reason:"unknown_owner",upgradeable:!0}}function handoffUnsupported(options){return(options._test?.platform??process.platform)==="win32"}import{readdir as readdir2,readFile as readFile5,rm as rm2}from"node:fs/promises";import{tmpdir}from"node:os";import{join as join6}from"node:path";async function reapOrphanedInternalHostDirs(){try{let entries=await readdir2(tmpdir(),{withFileTypes:!0});await Promise.all(entries.filter(entry=>entry.isDirectory()&&entry.name.startsWith("senpi-rpc-host-internal-")).map(async entry=>{try{let owner=JSON.parse(await readFile5(join6(tmpdir(),entry.name,".owner"),"utf8"));typeof owner.pid=="number"&&typeof owner.processStartTime=="string"&&typeof owner.createdAt=="number"&&owner.processStartTime.length>0&&owner.createdAt<Date.now()-6e4&&(await readdir2(join6(tmpdir(),entry.name))).length===1&&!await processMatchesPidFile({pid:owner.pid,processStartTime:owner.processStartTime}).catch(error=>{if(error instanceof ProcessIdentityUnreadableError)return!0;throw error})&&await rm2(join6(tmpdir(),entry.name),{recursive:!0,force:!0})}catch{}}))}catch{}}var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}var EXISTING_HOST_PROBE_TIMEOUT_MS=1e4,ENSURE_LOCK_WAIT_MS=EXISTING_HOST_PROBE_TIMEOUT_MS+Math.max(DEFAULT_STOP_TIMEOUT_MS+SIGKILL_GRACE_MS+DEFAULT_READINESS_TIMEOUT_MS,HANDOFF_LOCK_HOLD_MS)+1e4,lockOptions=hostEnsureLockOptions(ENSURE_LOCK_WAIT_MS);async function ensureHost(options){let socket=normalizeSocketPath(options.socket),paths=createHostDaemonPaths({socket,...options.agentDir?{agentDir:options.agentDir}:{}});await createDaemonDirectories(paths);let lockTarget=hostEnsureLockTarget(socket);await mkdir(dirname5(lockTarget),{recursive:!0}),await writeFile3(lockTarget,"",{flag:"a",mode:384}),await reapOrphanedInternalHostDirs();let release=await acquireOwnershipSafeLock(`${lockTarget}.lock`,lockOptions),ensured;try{await options._test?.afterLockAcquired?.(),ensured=await ensureHostLocked(paths,socket,options)}finally{await release()}return scheduleOpportunisticHostGc({agentDir:options.agentDir??getAgentDir(),exclude:socket}),ensured}async function ensureHostLocked(paths,socket,options){await ensureEndpointIdentity(paths,socket,{repair:!0});let testOptions=options._test,registered=await readHostRegistration(paths),registeredHere=registersSocket(registered,socket),held=await holdProtocolInfo(socket,EXISTING_HOST_PROBE_TIMEOUT_MS),protocol=held?.info,startedByUs=registeredHere&&await writtenByThisProcess(registered?.writer,testOptions?.readProcessStartTime),attachedPid=registeredHere?registered?.record.pid??0:0,decision=decide(options,startedByUs,protocol);if(decision.action==="reuse"&&held)return{pid:attachedPid,socket,reused:!0,release:held.hold.release};switch(held?.hold.release(),decision.action){case"reuse":throw new Error(`host at ${socket} was reused without answering its probe`);case"refuse":throw new HostEnsureRefusedError(socket,decision.reason,protocol);case"handoff":return upgradeGeneration(paths,socket,options,attachedPid);case"start":break;default:return assertNever2(decision)}let probe=testOptions?.readProcessStartTime??readProcessStartTime,pidMatches=registeredHere&®istered?await matchesPidFileOrUnknown(registered.record,probe):!1,stranded;if(registered&&pidMatches)if(startedByUs){if(await probeSocketReachable(socket,EXISTING_HOST_PROBE_TIMEOUT_MS))throw new HostEnsureRefusedError(socket,"host_busy",protocol);await stopManagedHost(registered.record,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS,probe)}else{if(await publicEndpointAccepts(socket))throw new HostEnsureRefusedError(socket,"foreign_writer",protocol);stranded=registered}let legacyRefusal=await retireIdleLegacyHost(paths,probe,testOptions?.stopTimeoutMs??DEFAULT_STOP_TIMEOUT_MS);if(legacyRefusal!==void 0)throw new HostEnsureRefusedError(socket,"legacy_host",protocol,legacyRefusal);return stranded!==void 0?startHost(paths,socket,options,stranded.generation+1):(registeredHere&&await clearHostRegistration(paths),startHost(paths,socket,options))}var FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS=2e3;async function publicEndpointAccepts(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!0;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:probeSocketReachable(socket,FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS)}function decide(options,startedByUs,protocol){if(options.upgrade!=="if-engine-differs"||isHostGenerationProcess())return decideHostAction(ensureClient(options,startedByUs),protocol,"never");let decision=decideHostAction(ensureClient(options,startedByUs),protocol,"upgrade");return decision.action==="fallback"?{action:"reuse",reason:"compatible",upgradeable:!1}:decision}async function upgradeGeneration(paths,socket,options,attachedPid){let result=await handoffHostLocked({socket,agentDir:options.agentDir??getAgentDir(),hostArgs:options.hostArgs??[],...options.env?{env:options.env}:{},...options.policy?{policy:options.policy}:{},_test:{...options._test?.launch?{launch:options._test.launch}:{},...options._test?.readinessTimeoutMs?{readinessTimeoutMs:options._test.readinessTimeoutMs}:{}}});return result.action==="handoff"?{pid:result.pid,socket,reused:!1,release:await holdEnsured(socket)}:(await appendStderr(paths,`generation handoff refused: ${result.reason}${result.detail?` (${result.detail})`:""}`),{pid:attachedPid,socket,reused:!0,release:await holdEnsured(socket)})}async function holdEnsured(socket){let held=await holdProtocolInfo(socket,EXISTING_HOST_PROBE_TIMEOUT_MS);if(!held)throw new Error(`RPC socket host at ${socket} stopped answering before this ensure could hold it`);return held.hold.release}function registersSocket(registered,socket){return registered===void 0?!1:registered.socket===void 0||sameEndpoint(registered.socket,socket)}function normalizeSocketPath(value){return value.startsWith("unix://")?value.slice(7):value}function assertNever2(value){throw new Error(`unreachable host decision: ${JSON.stringify(value)}`)}var WakeSourceTracker=class{constructor(){this.counts=new Map}observe(data){if(typeof data!="object"||data===null)return;let{source,activeCount}=data;typeof source!="string"||source.length===0||typeof activeCount!="number"||!Number.isFinite(activeCount)||(activeCount>0?this.counts.set(source,activeCount):this.counts.delete(source))}get hasActive(){return this.counts.size>0}get activeSources(){return[...this.counts.keys()]}};function isSessionBusySnapshot(snapshot){return snapshot.isStreaming||snapshot.isBashRunning||snapshot.isCompacting||snapshot.hasSessionWork||snapshot.hasActiveWakeSource}function isHandoffBusy(snapshot){return isSessionBusySnapshot({...snapshot,hasActiveWakeSource:!1})}function selectDrainVerdicts(registry,inFlight,unreadable){let park=[],gone=[];for(let{sessionId,status,sessionPath}of registry.list()){if(status!=="open"||inFlight(sessionId))continue;let entry=registry.peek(sessionId);!entry||handoffBusy(entry,sessionId,unreadable)||(sessionPath!==void 0&&sessionDirectoryRemoved(sessionPath)?gone.push(sessionId):park.push(sessionId))}return{park,gone}}function handoffBusy(entry,sessionId,unreadable){try{let snapshot=entry.runtime?.session.activitySnapshot;return entry.worker?.handoffBusy===!0||snapshot!==void 0&&isHandoffBusy(snapshot)}catch(cause){return unreadable(sessionId,cause),!1}}function readDrainVerdicts(registry,inFlight){try{return selectDrainVerdicts(registry,inFlight,(sessionId,cause)=>{process.stderr.write(`senpi rpc handoff activity of ${sessionId} unreadable, parking: ${String(cause)}
|
|
@@ -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{watchWithErrorHandler}from"./chunk-JABBHOD5.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{ProjectTrustStore}from"./chunk-6SMU7ANE.js";import{sanitizeProviderDiagnostic}from"./chunk-YOPVJDSU.js";var clientMessageIdentitySchema=external_exports.object({clientMessageId:external_exports.string().min(1).max(256).optional(),clientTurnId:external_exports.string().min(1).max(256).optional()});function clientMessageIdentity(value={}){return{...value.clientMessageId===void 0?{}:{clientMessageId:value.clientMessageId},...value.clientTurnId===void 0?{}:{clientTurnId:value.clientTurnId}}}function readClientMessageIdentity(value){let parsed=clientMessageIdentitySchema.safeParse(value);return parsed.success?clientMessageIdentity(parsed.data):{}}var MAX_RPC_MESSAGE_CHARACTERS=1e6,SESSION_CONTEXT_LIMITS={keys:32,valueBytes:16*1024,totalBytes:32*1024},SESSION_CONTEXT_KEY_PATTERN=/^[a-z][a-z0-9_]*$/;function validContent(content){return typeof content=="string"?!0:Array.isArray(content)&&content.every(item=>{if(typeof item!="object"||item===null)return!1;let value=item;return value.type==="text"?typeof value.text=="string":value.type==="image"&&typeof value.data=="string"&&typeof value.mimeType=="string"})}function validBaseEntry(entry){return typeof entry.id=="string"&&(entry.parentId===null||typeof entry.parentId=="string")&&typeof entry.timestamp=="string"}function validSessionEntry(entry){if(typeof entry!="object"||entry===null||Array.isArray(entry))return!1;let value=entry;if(!validBaseEntry(value))return!1;switch(value.type){case"message":{let message=value.message;if(typeof message!="object"||message===null)return!1;let item=message;return["user","assistant","tool"].includes(item.role)&&validContent(item.content)}case"thinking_level_change":return typeof value.thinkingLevel=="string";case"model_change":return typeof value.provider=="string"&&typeof value.modelId=="string";case"model_change_rejected":return typeof value.provider=="string"&&typeof value.modelId=="string"&&typeof value.detail=="string";case"compaction":return typeof value.summary=="string"&&typeof value.firstKeptEntryId=="string"&&typeof value.tokensBefore=="number";case"branch_summary":return typeof value.fromId=="string"&&typeof value.summary=="string";case"custom":return typeof value.customType=="string";case"custom_message":return typeof value.customType=="string"&&validContent(value.content)&&typeof value.display=="boolean";case"label":return typeof value.targetId=="string"&&(value.label===void 0||typeof value.label=="string");case"session_info":return value.name===void 0||typeof value.name=="string";default:return!1}}function rpcCommandPayloadError(command){if(rpcCommandShapeError(command))return;let value=command;if((value.type==="prompt"||value.type==="steer"||value.type==="follow_up")&&!clientMessageIdentitySchema.safeParse(value).success)return"clientMessageId and clientTurnId must be non-empty strings of at most 256 characters.";if((value.type==="steer"||value.type==="follow_up")&&value.enqueueOrder!==void 0&&!(typeof value.enqueueOrder=="number"&&Number.isFinite(value.enqueueOrder)))return"enqueueOrder must be a finite number.";if(value.type==="append_user_message"&&!validContent(value.content))return"append_user_message content must be a string or text/image content array.";if(value.type==="append_session_entry"&&!validSessionEntry(value.entry))return"append_session_entry entry is malformed."}function sessionContextError(context){if(context===void 0)return;if(typeof context!="object"||context===null||Array.isArray(context))return"context must be an object of string values.";let entries=Object.entries(context);if(entries.length>SESSION_CONTEXT_LIMITS.keys)return`context has ${entries.length} keys, at most ${SESSION_CONTEXT_LIMITS.keys} are accepted.`;for(let[key,value]of entries){if(!SESSION_CONTEXT_KEY_PATTERN.test(key))return`context key "${key}" must match ${SESSION_CONTEXT_KEY_PATTERN.source}.`;if(typeof value!="string")return`context value for key "${key}" must be a string.`;let valueBytes=Buffer.byteLength(value);if(valueBytes>SESSION_CONTEXT_LIMITS.valueBytes)return`context value for key "${key}" is ${valueBytes} bytes, at most ${SESSION_CONTEXT_LIMITS.valueBytes} bytes are accepted.`}let totalBytes=Buffer.byteLength(JSON.stringify(context));if(totalBytes>SESSION_CONTEXT_LIMITS.totalBytes)return`context is ${totalBytes} bytes of JSON, at most ${SESSION_CONTEXT_LIMITS.totalBytes} bytes are accepted.`}function sessionKindError(kind){if(!(kind===void 0||kind==="interactive"||kind==="worker"))return'kind must be "interactive" or "worker".'}function sessionAutoTitleError(value){if(!(value===void 0||typeof value=="boolean"))return"auto_title must be a boolean."}function sessionPromptSurfaceError(value){if(!(value===void 0||value==="terminal"||value==="app"||value==="chat"))return'promptSurface must be "terminal", "app" or "chat".'}function rpcCommandShapeError(command){if(typeof command!="object"||command===null||Array.isArray(command))return"RPC command must be a JSON object."}function rpcMessageLengthError(command){if(rpcCommandShapeError(command))return;let input=command;if(!(input.type!=="prompt"&&input.type!=="steer"&&input.type!=="follow_up")&&!(typeof input.message!="string"||input.message.length<=MAX_RPC_MESSAGE_CHARACTERS))return`RPC ${input.type} message exceeds ${MAX_RPC_MESSAGE_CHARACTERS} characters.`}import{randomUUID}from"node:crypto";import{mkdir,rm,writeFile}from"node:fs/promises";import{join}from"node:path";import{setTimeout as delay}from"node:timers/promises";import{Worker}from"node:worker_threads";var RECURSIVE_WATCH_WORKER_SOURCE=`
|
|
2
|
+
import{watchWithErrorHandler}from"./chunk-JABBHOD5.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{ProjectTrustStore}from"./chunk-6SMU7ANE.js";import{sanitizeProviderDiagnostic}from"./chunk-YOPVJDSU.js";var BROWSER_ENGINES=["connected","builtin","none"];function isBrowserEngine(value){return BROWSER_ENGINES.some(engine=>engine===value)}var clientMessageIdentitySchema=external_exports.object({clientMessageId:external_exports.string().min(1).max(256).optional(),clientTurnId:external_exports.string().min(1).max(256).optional()});function clientMessageIdentity(value={}){return{...value.clientMessageId===void 0?{}:{clientMessageId:value.clientMessageId},...value.clientTurnId===void 0?{}:{clientTurnId:value.clientTurnId}}}function readClientMessageIdentity(value){let parsed=clientMessageIdentitySchema.safeParse(value);return parsed.success?clientMessageIdentity(parsed.data):{}}var MAX_RPC_MESSAGE_CHARACTERS=1e6,SESSION_CONTEXT_LIMITS={keys:32,valueBytes:16*1024,totalBytes:32*1024},SESSION_CONTEXT_KEY_PATTERN=/^[a-z][a-z0-9_]*$/;function validContent(content){return typeof content=="string"?!0:Array.isArray(content)&&content.every(item=>{if(typeof item!="object"||item===null)return!1;let value=item;return value.type==="text"?typeof value.text=="string":value.type==="image"&&typeof value.data=="string"&&typeof value.mimeType=="string"})}function validBaseEntry(entry){return typeof entry.id=="string"&&(entry.parentId===null||typeof entry.parentId=="string")&&typeof entry.timestamp=="string"}function validSessionEntry(entry){if(typeof entry!="object"||entry===null||Array.isArray(entry))return!1;let value=entry;if(!validBaseEntry(value))return!1;switch(value.type){case"message":{let message=value.message;if(typeof message!="object"||message===null)return!1;let item=message;return["user","assistant","tool"].includes(item.role)&&validContent(item.content)}case"thinking_level_change":return typeof value.thinkingLevel=="string";case"model_change":return typeof value.provider=="string"&&typeof value.modelId=="string";case"model_change_rejected":return typeof value.provider=="string"&&typeof value.modelId=="string"&&typeof value.detail=="string";case"compaction":return typeof value.summary=="string"&&typeof value.firstKeptEntryId=="string"&&typeof value.tokensBefore=="number";case"branch_summary":return typeof value.fromId=="string"&&typeof value.summary=="string";case"custom":return typeof value.customType=="string";case"custom_message":return typeof value.customType=="string"&&validContent(value.content)&&typeof value.display=="boolean";case"label":return typeof value.targetId=="string"&&(value.label===void 0||typeof value.label=="string");case"session_info":return value.name===void 0||typeof value.name=="string";default:return!1}}function rpcCommandPayloadError(command){if(rpcCommandShapeError(command))return;let value=command;if((value.type==="prompt"||value.type==="steer"||value.type==="follow_up")&&!clientMessageIdentitySchema.safeParse(value).success)return"clientMessageId and clientTurnId must be non-empty strings of at most 256 characters.";if((value.type==="steer"||value.type==="follow_up")&&value.enqueueOrder!==void 0&&!(typeof value.enqueueOrder=="number"&&Number.isFinite(value.enqueueOrder)))return"enqueueOrder must be a finite number.";if(value.type==="append_user_message"&&!validContent(value.content))return"append_user_message content must be a string or text/image content array.";if(value.type==="append_session_entry"&&!validSessionEntry(value.entry))return"append_session_entry entry is malformed."}function sessionContextError(context){if(context===void 0)return;if(typeof context!="object"||context===null||Array.isArray(context))return"context must be an object of string values.";let entries=Object.entries(context);if(entries.length>SESSION_CONTEXT_LIMITS.keys)return`context has ${entries.length} keys, at most ${SESSION_CONTEXT_LIMITS.keys} are accepted.`;for(let[key,value]of entries){if(!SESSION_CONTEXT_KEY_PATTERN.test(key))return`context key "${key}" must match ${SESSION_CONTEXT_KEY_PATTERN.source}.`;if(typeof value!="string")return`context value for key "${key}" must be a string.`;let valueBytes=Buffer.byteLength(value);if(valueBytes>SESSION_CONTEXT_LIMITS.valueBytes)return`context value for key "${key}" is ${valueBytes} bytes, at most ${SESSION_CONTEXT_LIMITS.valueBytes} bytes are accepted.`}let totalBytes=Buffer.byteLength(JSON.stringify(context));if(totalBytes>SESSION_CONTEXT_LIMITS.totalBytes)return`context is ${totalBytes} bytes of JSON, at most ${SESSION_CONTEXT_LIMITS.totalBytes} bytes are accepted.`}function sessionKindError(kind){if(!(kind===void 0||kind==="interactive"||kind==="worker"))return'kind must be "interactive" or "worker".'}function sessionAutoTitleError(value){if(!(value===void 0||typeof value=="boolean"))return"auto_title must be a boolean."}function sessionPromptSurfaceError(value){if(!(value===void 0||value==="terminal"||value==="app"||value==="chat"))return'promptSurface must be "terminal", "app" or "chat".'}function sessionBrowserEngineError(value){if(!(value===void 0||isBrowserEngine(value)))return'browserEngine must be "connected", "builtin" or "none".'}function rpcCommandShapeError(command){if(typeof command!="object"||command===null||Array.isArray(command))return"RPC command must be a JSON object."}function rpcMessageLengthError(command){if(rpcCommandShapeError(command))return;let input=command;if(!(input.type!=="prompt"&&input.type!=="steer"&&input.type!=="follow_up")&&!(typeof input.message!="string"||input.message.length<=MAX_RPC_MESSAGE_CHARACTERS))return`RPC ${input.type} message exceeds ${MAX_RPC_MESSAGE_CHARACTERS} characters.`}import{randomUUID}from"node:crypto";import{mkdir,rm,writeFile}from"node:fs/promises";import{join}from"node:path";import{setTimeout as delay}from"node:timers/promises";import{Worker}from"node:worker_threads";var RECURSIVE_WATCH_WORKER_SOURCE=`
|
|
3
3
|
const { watch } = require("node:fs");
|
|
4
4
|
const { parentPort } = require("node:worker_threads");
|
|
5
5
|
|
|
@@ -52,4 +52,4 @@ parentPort.on("message", (message) => {
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
-
`;function createRecursiveWatchWorker(){return new Worker(RECURSIVE_WATCH_WORKER_SOURCE,{eval:!0})}var recursiveWorkerStates=new Map;function isRecursiveWatchMessage(message){return typeof message!="object"||message===null||!("kind"in message)||!("id"in message)||typeof message.id!="number"?!1:message.kind==="error"?"message"in message&&typeof message.message=="string":message.kind==="event"&&"eventType"in message&&typeof message.eventType=="string"&&"filename"in message&&(message.filename===null||typeof message.filename=="string")}var WORKER_OFFLOADED_WATCH_PLATFORMS=new Set(["linux","darwin"]);function createFsWatchEventSource(onError=()=>{},options={}){let createWorker=options.createRecursiveWorker??createRecursiveWatchWorker,state=recursiveWorkerStates.get(createWorker);state||(state={subscriptions:new Map,nextSubscriptionId:1},recursiveWorkerStates.set(createWorker,state));let recursiveSubscriptions=state.subscriptions,ensureRecursiveWorker=()=>{if(state.worker)return state.worker;let worker=createWorker();return worker.on("message",message=>{if(!isRecursiveWatchMessage(message))return;let subscription=recursiveSubscriptions.get(message.id);if(subscription){if(message.kind==="event"){subscription.listener(message.eventType,message.filename);return}subscription.onError(new Error(message.message),subscription.path)}}),worker.on("error",error=>{for(let subscription of recursiveSubscriptions.values())subscription.onError(error,subscription.path);if(state.worker!==worker||(state.worker=void 0,recursiveSubscriptions.size===0))return;let replacement=ensureRecursiveWorker();for(let[id,subscription]of recursiveSubscriptions)replacement.postMessage({kind:"watch",id,path:subscription.path,recursive:subscription.recursive,active:subscription.active})}),state.worker=worker,worker};return(path,listener,watchOptions)=>{if(WORKER_OFFLOADED_WATCH_PLATFORMS.has(options.platform??process.platform)){let id=state.nextSubscriptionId++,recursive=watchOptions?.recursive??!1,active=new Int32Array(new SharedArrayBuffer(4));Atomics.store(active,0,1),ensureRecursiveWorker().postMessage({kind:"watch",id,path,recursive,active}),recursiveSubscriptions.set(id,{path,listener,recursive,active,onError});let closing;return()=>{if(!recursiveSubscriptions.delete(id))return closing;Atomics.store(active,0,0);let worker=state.worker;if(!worker)return closing;if(worker.postMessage({kind:"unwatch",id}),!(recursiveSubscriptions.size>0))return state.worker=void 0,closing=worker.terminate().then(()=>{},error=>{throw onError(error,path),error}),closing}}let watcher=watchWithErrorHandler(path,listener,()=>onError(new Error(`fs.watch failed for ${path}`),path),{recursive:watchOptions?.recursive??!1});return()=>watcher?.close()}}var REASON_PRIORITY=["submission","draft_cleared","idle","continue","command","emitted","inbox"],EMPTY_RESULT={admitted:[]},WakeScheduler=class{constructor(pass,onError){this.running=!1,this.disposed=!1,this.pass=pass,this.onError=onError}request(reason,deliveryIds){if(this.disposed)return Promise.resolve(EMPTY_RESULT);this.next??={reasons:new Set,deliveryIds:new Set,waiters:[]};let batch=this.next;batch.reasons.add(reason);for(let id of deliveryIds??[])batch.deliveryIds.add(id);let settled=new Promise(resolve=>batch.waiters.push(resolve));return this.running||this.run(),settled}dispose(){this.disposed=!0;let batch=this.next;this.next=void 0;for(let waiter of batch?.waiters??[])waiter(EMPTY_RESULT)}async run(){this.running=!0;try{for(let batch=this.next;batch!==void 0&&!this.disposed;batch=this.next){this.next=void 0;let result=EMPTY_RESULT;try{result=await this.pass(wakeEvent(batch))}catch(error){this.onError(error)}for(let waiter of batch.waiters)waiter(result)}}finally{this.running=!1}}};function wakeEvent(batch){let reasons=REASON_PRIORITY.filter(reason2=>batch.reasons.has(reason2)),reason=reasons[0]??"inbox",ids=[...batch.deliveryIds];return{type:"session_control_wake",reason,reasons,...ids.length>0?{delivery_ids:ids}:{}}}var INBOX_ENGINE_ENTRY_PREFIX=".senpi-",INBOX_ARM_ATTEMPTS=25,INBOX_ARM_ATTEMPT_MS=200;async function watchInbox(inboxDir,onChange,onError){await mkdir(inboxDir,{recursive:!0,mode:448});let sentinel=`${INBOX_ENGINE_ENTRY_PREFIX}armed-${randomUUID()}`,armed=Promise.withResolvers(),unsubscribe=createFsWatchEventSource(error=>onError(error))(inboxDir,(_eventType,filename)=>{filename===sentinel?armed.resolve(!0):filename?.startsWith(INBOX_ENGINE_ENTRY_PREFIX)||onChange()},{recursive:!1}),confirmed=!1;for(let attempt=0;attempt<INBOX_ARM_ATTEMPTS&&!confirmed;attempt++)await writeFile(join(inboxDir,sentinel),String(attempt),{mode:384}),confirmed=await Promise.race([armed.promise,delay(INBOX_ARM_ATTEMPT_MS,!1)]);return await rm(join(inboxDir,sentinel),{force:!0}),confirmed||onError(new Error(`inbox watch on ${inboxDir} was not confirmed`)),()=>{Promise.resolve(unsubscribe()).catch(onError)}}function onProcessContinue(listener){let handler=()=>{setImmediate(listener)};return process.on("SIGCONT",handler),()=>{process.removeListener("SIGCONT",handler)}}function answeredUiRequestId(frame){return typeof frame.uiRequestId=="string"?frame.uiRequestId:typeof frame.id=="string"?frame.id:void 0}function settledQuestionStatus(answers,comment){return comment?.trim()?"comment-submitted":Object.keys(answers).length>0?"answered":void 0}function unansweredQuestionIds(questions,answers){return questions.filter(question=>!answers[question.id]?.selected.length&&!answers[question.id]?.text?.trim()).map(question=>question.id)}function settleExtensionUiResponse(response,targets){let requestId=answeredUiRequestId(response)??response.id,answer=requestId===response.id?response:{...response,id:requestId},question=targets.questions.respond(answer);return typeof question=="string"?refused(response.id,question):question||targets.dialogs.resolve(answer)?{...reply(response.id),success:!0}:targets.routed?refused(response.id,"unknown_extension_ui_request"):void 0}function reply(id){return{id,type:"response",command:"extension_ui_response"}}function refused(id,error){return{...reply(id),success:!1,error}}var sessionQuestionBridges=new WeakMap,ConnectionQuestionBridge=class{constructor(output){this.pending=new Map,this.resolved=new Set,this.output=output}pendingQuestions(){return[...this.pending.values()].map(({frame})=>({...frame,remainingMs:Math.max(0,frame.deadlineAtMs-Date.now())}))}ask(request,opts){let id=crypto.randomUUID(),askedAtMs=Date.now(),timeout=opts?.timeout??request.timeoutMs,frame={type:"extension_ui_request",method:"question",id,requestId:request.requestId,toolCallId:request.requestId,waitForAnswer:request.waitForAnswer,questions:request.questions,timeout,askedAtMs,deadlineAtMs:askedAtMs+timeout,remainingMs:timeout};return new Promise(resolve=>{let answers={},comment,timer,finished=!1,unanswered=()=>unansweredQuestionIds(request.questions,answers),finish=(status,resolvedBy)=>{if(finished)return;finished=!0,clearTimeout(timer),opts?.signal?.removeEventListener("abort",cancel),this.pending.delete(id),this.resolved.add(id);let result={status,...resolvedBy!==void 0?{resolvedBy}:{},answers,comment,unanswered:unanswered(),...status==="timed_out"?{autoResolvedAfterMs:Date.now()-askedAtMs}:{}};this.output({type:"question_resolved",id,requestId:frame.requestId,toolCallId:frame.toolCallId,outcome:status,...result.resolvedBy!==void 0?{resolvedBy:result.resolvedBy}:{},answers,comment,unanswered:result.unanswered,deadlineAtMs:frame.deadlineAtMs}),resolve(result)},cancel=()=>{let reason=opts?.signal?.reason;finish(reason==="timed_out"?"timed_out":"cancelled")},arm=()=>{clearTimeout(timer),frame.deadlineAtMs=Date.now()+timeout,timer=setTimeout(()=>finish("timed_out"),timeout)};this.pending.set(id,{frame,cancel,progress:draft=>{draft.answers!==void 0&&(answers=draft.answers),draft.comment!==void 0&&(comment=draft.comment),arm(),opts?.onProgress?.({answers,comment}),finished||this.output({type:"question_updated",id,deadlineAtMs:frame.deadlineAtMs,remainingMs:Math.max(0,frame.deadlineAtMs-Date.now())})},respond:response=>{if("cancelled"in response)return cancel(),!0;if(!("answers"in response))return!1;answers=response.answers,comment=response.comment;let status=settledQuestionStatus(answers,comment);return status===void 0?!1:(finish(status,"rpc_connection"),!0)}}),arm(),this.output(frame),opts?.signal?.addEventListener("abort",cancel,{once:!0}),opts?.signal?.aborted&&cancel()})}respond(response){let pending=this.pending.get(response.id);return pending?pending.respond(response)||"question_incomplete":this.resolved.has(response.id)?"question_already_resolved":!1}progress(draft){this.pending.get(draft.id)?.progress(draft)}cancelAll(){for(let pending of this.pending.values())pending.cancel()}};async function degradeQuestion(ui,request,opts){let answers={},other="Other (type an answer)";for(let question of request.questions){let selected=await ui.select(question.question,[...question.options.map(option=>option.label),other],opts);if(selected===other){let text=await ui.input(question.question,void 0,opts);text?.trim()&&(answers[question.id]={selected:[],text})}else selected!==void 0&&(answers[question.id]={selected:[selected]})}let comment=await ui.input("Anything else? (optional)",void 0,opts),unanswered=request.questions.filter(q=>!answers[q.id]).map(q=>q.id);return{status:comment?.trim()?"comment-submitted":unanswered.length?"cancelled":"answered",...comment?.trim()||unanswered.length===0?{resolvedBy:"rpc_connection"}:{},answers,comment,unanswered}}import{existsSync}from"node:fs";function buildRpcSessionState(session,lastAbortSource){let cwd=session.sessionManager.getCwd();if(!session.agentDir)throw new Error("RPC session invariant violated: agentDir is required");let projectTrusted=new ProjectTrustStore(session.agentDir).get(cwd)===!0,lastProviderDiagnostic=sanitizeProviderDiagnostic(session.agent.state.providerDiagnostic);return{pendingQuestions:sessionQuestionBridges.get(session)?.pendingQuestions(),model:session.model,pendingModelSwitch:session.pendingModelSwitch?{provider:session.pendingModelSwitch.model.provider,id:session.pendingModelSwitch.model.id}:null,thinkingLevel:session.thinkingLevel,...session.thinkingSelection?{thinkingSelection:session.thinkingSelection}:{},...lastAbortSource?{lastAbortSource}:{},...lastProviderDiagnostic?{lastProviderDiagnostic}:{},serviceTier:session.effectiveServiceTier,fastMode:session.isFastModeActive(),isStreaming:session.isStreaming,isCompacting:session.isCompacting,retryAttempt:session.retryAttempt,isBashRunning:session.isBashRunning,steeringMode:session.steeringMode,followUpMode:session.followUpMode,sessionFile:session.sessionFile,sessionId:session.sessionId,sessionName:session.sessionName,cwd,projectTrusted,...session.sessionFile&&!existsSync(session.sessionFile)&&session.sessionManager.getEntries().some(entry=>entry.type!=="model_change"&&entry.type!=="model_change_rejected"&&entry.type!=="thinking_level_change")?{entries:session.sessionManager.getEntries()}:{},steering:typeof session.getSteeringMessages=="function"?[...session.getSteeringMessages()]:[],followUp:typeof session.getFollowUpMessages=="function"?[...session.getFollowUpMessages()]:[],ordered:[...session._queuedInputOrder??[]].sort((a,b)=>a.enqueueOrder-b.enqueueOrder),autoCompactionEnabled:session.autoCompactionEnabled,messageCount:session.messages.length,pendingMessageCount:session.pendingMessageCount,usageTotals:session.sessionManager.getUsageTotals(),contextUsage:typeof session.getContextUsage=="function"?session.getContextUsage():void 0,favoriteModels:session.favoriteModels?.map(entry=>({...entry}))??[],scopedModels:session.scopedModels?.map(entry=>({...entry}))??[]}}export{clientMessageIdentitySchema,clientMessageIdentity,readClientMessageIdentity,createFsWatchEventSource,answeredUiRequestId,settledQuestionStatus,unansweredQuestionIds,settleExtensionUiResponse,sessionQuestionBridges,ConnectionQuestionBridge,degradeQuestion,buildRpcSessionState,rpcCommandPayloadError,sessionContextError,sessionKindError,sessionAutoTitleError,sessionPromptSurfaceError,rpcCommandShapeError,rpcMessageLengthError,WakeScheduler,watchInbox,onProcessContinue};
|
|
55
|
+
`;function createRecursiveWatchWorker(){return new Worker(RECURSIVE_WATCH_WORKER_SOURCE,{eval:!0})}var recursiveWorkerStates=new Map;function isRecursiveWatchMessage(message){return typeof message!="object"||message===null||!("kind"in message)||!("id"in message)||typeof message.id!="number"?!1:message.kind==="error"?"message"in message&&typeof message.message=="string":message.kind==="event"&&"eventType"in message&&typeof message.eventType=="string"&&"filename"in message&&(message.filename===null||typeof message.filename=="string")}var WORKER_OFFLOADED_WATCH_PLATFORMS=new Set(["linux","darwin"]);function createFsWatchEventSource(onError=()=>{},options={}){let createWorker=options.createRecursiveWorker??createRecursiveWatchWorker,state=recursiveWorkerStates.get(createWorker);state||(state={subscriptions:new Map,nextSubscriptionId:1},recursiveWorkerStates.set(createWorker,state));let recursiveSubscriptions=state.subscriptions,ensureRecursiveWorker=()=>{if(state.worker)return state.worker;let worker=createWorker();return worker.on("message",message=>{if(!isRecursiveWatchMessage(message))return;let subscription=recursiveSubscriptions.get(message.id);if(subscription){if(message.kind==="event"){subscription.listener(message.eventType,message.filename);return}subscription.onError(new Error(message.message),subscription.path)}}),worker.on("error",error=>{for(let subscription of recursiveSubscriptions.values())subscription.onError(error,subscription.path);if(state.worker!==worker||(state.worker=void 0,recursiveSubscriptions.size===0))return;let replacement=ensureRecursiveWorker();for(let[id,subscription]of recursiveSubscriptions)replacement.postMessage({kind:"watch",id,path:subscription.path,recursive:subscription.recursive,active:subscription.active})}),state.worker=worker,worker};return(path,listener,watchOptions)=>{if(WORKER_OFFLOADED_WATCH_PLATFORMS.has(options.platform??process.platform)){let id=state.nextSubscriptionId++,recursive=watchOptions?.recursive??!1,active=new Int32Array(new SharedArrayBuffer(4));Atomics.store(active,0,1),ensureRecursiveWorker().postMessage({kind:"watch",id,path,recursive,active}),recursiveSubscriptions.set(id,{path,listener,recursive,active,onError});let closing;return()=>{if(!recursiveSubscriptions.delete(id))return closing;Atomics.store(active,0,0);let worker=state.worker;if(!worker)return closing;if(worker.postMessage({kind:"unwatch",id}),!(recursiveSubscriptions.size>0))return state.worker=void 0,closing=worker.terminate().then(()=>{},error=>{throw onError(error,path),error}),closing}}let watcher=watchWithErrorHandler(path,listener,()=>onError(new Error(`fs.watch failed for ${path}`),path),{recursive:watchOptions?.recursive??!1});return()=>watcher?.close()}}var REASON_PRIORITY=["submission","draft_cleared","idle","continue","command","emitted","inbox"],EMPTY_RESULT={admitted:[]},WakeScheduler=class{constructor(pass,onError){this.running=!1,this.disposed=!1,this.pass=pass,this.onError=onError}request(reason,deliveryIds){if(this.disposed)return Promise.resolve(EMPTY_RESULT);this.next??={reasons:new Set,deliveryIds:new Set,waiters:[]};let batch=this.next;batch.reasons.add(reason);for(let id of deliveryIds??[])batch.deliveryIds.add(id);let settled=new Promise(resolve=>batch.waiters.push(resolve));return this.running||this.run(),settled}dispose(){this.disposed=!0;let batch=this.next;this.next=void 0;for(let waiter of batch?.waiters??[])waiter(EMPTY_RESULT)}async run(){this.running=!0;try{for(let batch=this.next;batch!==void 0&&!this.disposed;batch=this.next){this.next=void 0;let result=EMPTY_RESULT;try{result=await this.pass(wakeEvent(batch))}catch(error){this.onError(error)}for(let waiter of batch.waiters)waiter(result)}}finally{this.running=!1}}};function wakeEvent(batch){let reasons=REASON_PRIORITY.filter(reason2=>batch.reasons.has(reason2)),reason=reasons[0]??"inbox",ids=[...batch.deliveryIds];return{type:"session_control_wake",reason,reasons,...ids.length>0?{delivery_ids:ids}:{}}}var INBOX_ENGINE_ENTRY_PREFIX=".senpi-",INBOX_ARM_ATTEMPTS=25,INBOX_ARM_ATTEMPT_MS=200;async function watchInbox(inboxDir,onChange,onError){await mkdir(inboxDir,{recursive:!0,mode:448});let sentinel=`${INBOX_ENGINE_ENTRY_PREFIX}armed-${randomUUID()}`,armed=Promise.withResolvers(),unsubscribe=createFsWatchEventSource(error=>onError(error))(inboxDir,(_eventType,filename)=>{filename===sentinel?armed.resolve(!0):filename?.startsWith(INBOX_ENGINE_ENTRY_PREFIX)||onChange()},{recursive:!1}),confirmed=!1;for(let attempt=0;attempt<INBOX_ARM_ATTEMPTS&&!confirmed;attempt++)await writeFile(join(inboxDir,sentinel),String(attempt),{mode:384}),confirmed=await Promise.race([armed.promise,delay(INBOX_ARM_ATTEMPT_MS,!1)]);return await rm(join(inboxDir,sentinel),{force:!0}),confirmed||onError(new Error(`inbox watch on ${inboxDir} was not confirmed`)),()=>{Promise.resolve(unsubscribe()).catch(onError)}}function onProcessContinue(listener){let handler=()=>{setImmediate(listener)};return process.on("SIGCONT",handler),()=>{process.removeListener("SIGCONT",handler)}}function answeredUiRequestId(frame){return typeof frame.uiRequestId=="string"?frame.uiRequestId:typeof frame.id=="string"?frame.id:void 0}function settledQuestionStatus(answers,comment){return comment?.trim()?"comment-submitted":Object.keys(answers).length>0?"answered":void 0}function unansweredQuestionIds(questions,answers){return questions.filter(question=>!answers[question.id]?.selected.length&&!answers[question.id]?.text?.trim()).map(question=>question.id)}function settleExtensionUiResponse(response,targets){let requestId=answeredUiRequestId(response)??response.id,answer=requestId===response.id?response:{...response,id:requestId},question=targets.questions.respond(answer);return typeof question=="string"?refused(response.id,question):question||targets.dialogs.resolve(answer)?{...reply(response.id),success:!0}:targets.routed?refused(response.id,"unknown_extension_ui_request"):void 0}function reply(id){return{id,type:"response",command:"extension_ui_response"}}function refused(id,error){return{...reply(id),success:!1,error}}var sessionQuestionBridges=new WeakMap,ConnectionQuestionBridge=class{constructor(output){this.pending=new Map,this.resolved=new Set,this.output=output}pendingQuestions(){return[...this.pending.values()].map(({frame})=>({...frame,remainingMs:Math.max(0,frame.deadlineAtMs-Date.now())}))}ask(request,opts){let id=crypto.randomUUID(),askedAtMs=Date.now(),timeout=opts?.timeout??request.timeoutMs,frame={type:"extension_ui_request",method:"question",id,requestId:request.requestId,toolCallId:request.requestId,waitForAnswer:request.waitForAnswer,questions:request.questions,timeout,askedAtMs,deadlineAtMs:askedAtMs+timeout,remainingMs:timeout};return new Promise(resolve=>{let answers={},comment,timer,finished=!1,unanswered=()=>unansweredQuestionIds(request.questions,answers),finish=(status,resolvedBy)=>{if(finished)return;finished=!0,clearTimeout(timer),opts?.signal?.removeEventListener("abort",cancel),this.pending.delete(id),this.resolved.add(id);let result={status,...resolvedBy!==void 0?{resolvedBy}:{},answers,comment,unanswered:unanswered(),...status==="timed_out"?{autoResolvedAfterMs:Date.now()-askedAtMs}:{}};this.output({type:"question_resolved",id,requestId:frame.requestId,toolCallId:frame.toolCallId,outcome:status,...result.resolvedBy!==void 0?{resolvedBy:result.resolvedBy}:{},answers,comment,unanswered:result.unanswered,deadlineAtMs:frame.deadlineAtMs}),resolve(result)},cancel=()=>{let reason=opts?.signal?.reason;finish(reason==="timed_out"?"timed_out":"cancelled")},arm=()=>{clearTimeout(timer),frame.deadlineAtMs=Date.now()+timeout,timer=setTimeout(()=>finish("timed_out"),timeout)};this.pending.set(id,{frame,cancel,progress:draft=>{draft.answers!==void 0&&(answers=draft.answers),draft.comment!==void 0&&(comment=draft.comment),arm(),opts?.onProgress?.({answers,comment}),finished||this.output({type:"question_updated",id,deadlineAtMs:frame.deadlineAtMs,remainingMs:Math.max(0,frame.deadlineAtMs-Date.now())})},respond:response=>{if("cancelled"in response)return cancel(),!0;if(!("answers"in response))return!1;answers=response.answers,comment=response.comment;let status=settledQuestionStatus(answers,comment);return status===void 0?!1:(finish(status,"rpc_connection"),!0)}}),arm(),this.output(frame),opts?.signal?.addEventListener("abort",cancel,{once:!0}),opts?.signal?.aborted&&cancel()})}respond(response){let pending=this.pending.get(response.id);return pending?pending.respond(response)||"question_incomplete":this.resolved.has(response.id)?"question_already_resolved":!1}progress(draft){this.pending.get(draft.id)?.progress(draft)}cancelAll(){for(let pending of this.pending.values())pending.cancel()}};async function degradeQuestion(ui,request,opts){let answers={},other="Other (type an answer)";for(let question of request.questions){let selected=await ui.select(question.question,[...question.options.map(option=>option.label),other],opts);if(selected===other){let text=await ui.input(question.question,void 0,opts);text?.trim()&&(answers[question.id]={selected:[],text})}else selected!==void 0&&(answers[question.id]={selected:[selected]})}let comment=await ui.input("Anything else? (optional)",void 0,opts),unanswered=request.questions.filter(q=>!answers[q.id]).map(q=>q.id);return{status:comment?.trim()?"comment-submitted":unanswered.length?"cancelled":"answered",...comment?.trim()||unanswered.length===0?{resolvedBy:"rpc_connection"}:{},answers,comment,unanswered}}import{existsSync}from"node:fs";function buildRpcSessionState(session,lastAbortSource){let cwd=session.sessionManager.getCwd();if(!session.agentDir)throw new Error("RPC session invariant violated: agentDir is required");let projectTrusted=new ProjectTrustStore(session.agentDir).get(cwd)===!0,lastProviderDiagnostic=sanitizeProviderDiagnostic(session.agent.state.providerDiagnostic);return{pendingQuestions:sessionQuestionBridges.get(session)?.pendingQuestions(),model:session.model,pendingModelSwitch:session.pendingModelSwitch?{provider:session.pendingModelSwitch.model.provider,id:session.pendingModelSwitch.model.id}:null,thinkingLevel:session.thinkingLevel,...session.thinkingSelection?{thinkingSelection:session.thinkingSelection}:{},...lastAbortSource?{lastAbortSource}:{},...lastProviderDiagnostic?{lastProviderDiagnostic}:{},serviceTier:session.effectiveServiceTier,fastMode:session.isFastModeActive(),isStreaming:session.isStreaming,isCompacting:session.isCompacting,retryAttempt:session.retryAttempt,isBashRunning:session.isBashRunning,steeringMode:session.steeringMode,followUpMode:session.followUpMode,sessionFile:session.sessionFile,sessionId:session.sessionId,sessionName:session.sessionName,cwd,projectTrusted,...session.sessionFile&&!existsSync(session.sessionFile)&&session.sessionManager.getEntries().some(entry=>entry.type!=="model_change"&&entry.type!=="model_change_rejected"&&entry.type!=="thinking_level_change")?{entries:session.sessionManager.getEntries()}:{},steering:typeof session.getSteeringMessages=="function"?[...session.getSteeringMessages()]:[],followUp:typeof session.getFollowUpMessages=="function"?[...session.getFollowUpMessages()]:[],ordered:[...session._queuedInputOrder??[]].sort((a,b)=>a.enqueueOrder-b.enqueueOrder),autoCompactionEnabled:session.autoCompactionEnabled,messageCount:session.messages.length,pendingMessageCount:session.pendingMessageCount,usageTotals:session.sessionManager.getUsageTotals(),contextUsage:typeof session.getContextUsage=="function"?session.getContextUsage():void 0,favoriteModels:session.favoriteModels?.map(entry=>({...entry}))??[],scopedModels:session.scopedModels?.map(entry=>({...entry}))??[]}}export{clientMessageIdentitySchema,clientMessageIdentity,readClientMessageIdentity,createFsWatchEventSource,answeredUiRequestId,settledQuestionStatus,unansweredQuestionIds,settleExtensionUiResponse,sessionQuestionBridges,ConnectionQuestionBridge,degradeQuestion,buildRpcSessionState,rpcCommandPayloadError,sessionContextError,sessionKindError,sessionAutoTitleError,sessionPromptSurfaceError,sessionBrowserEngineError,rpcCommandShapeError,rpcMessageLengthError,WakeScheduler,watchInbox,onProcessContinue};
|