@code-yeongyu/senpi 2026.9.28-5 → 2026.9.28-7
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 +35 -0
- package/dist/bundle/chunks/{anthropic-messages-GG4ZKS6A.js → anthropic-messages-QOQJCY3F.js} +1 -1
- package/dist/bundle/chunks/{app-server-command-3AJWPHKJ.js → app-server-command-OUTRKHMK.js} +8 -8
- package/dist/bundle/chunks/{chunk-XYGXUFMG.js → chunk-3HCYHGK2.js} +1 -1
- package/dist/bundle/chunks/{chunk-EXUI5D5V.js → chunk-56COAYOU.js} +9 -9
- package/dist/bundle/chunks/{chunk-MMHQLGF2.js → chunk-AIM2YESB.js} +1 -1
- package/dist/bundle/chunks/{chunk-4BDFNRBE.js → chunk-B32PXL7U.js} +1 -1
- package/dist/bundle/chunks/chunk-CEMOA3TF.js +2 -0
- package/dist/bundle/chunks/{chunk-XNIX26QC.js → chunk-DB2X7SOZ.js} +2 -2
- package/dist/bundle/chunks/chunk-E5F5SVZF.js +5 -0
- package/dist/bundle/chunks/{chunk-OHJLQ7BY.js → chunk-F2YU5BZG.js} +1 -1
- package/dist/bundle/chunks/{chunk-BQGVC47Y.js → chunk-FILEUW2D.js} +1 -1
- package/dist/bundle/chunks/{chunk-JGRPPPHS.js → chunk-JASECXGC.js} +1 -1
- package/dist/bundle/chunks/{chunk-YLIS5N3W.js → chunk-JK5LVAOU.js} +1 -1
- package/dist/bundle/chunks/{chunk-KDZAVHA7.js → chunk-L4OOEWAT.js} +2 -2
- package/dist/bundle/chunks/{chunk-Z5NVK72W.js → chunk-LM2UMEX6.js} +1 -1
- package/dist/bundle/chunks/{chunk-C5I2LUOI.js → chunk-SQUUL72H.js} +1 -1
- package/dist/bundle/chunks/{chunk-LEAJXPT2.js → chunk-TOCWAEQB.js} +1 -1
- package/dist/bundle/chunks/{chunk-YEMM3LPR.js → chunk-VW3QZSX3.js} +1 -1
- package/dist/bundle/chunks/{chunk-7SFG425F.js → chunk-Y4CH7LYI.js} +2 -2
- package/dist/bundle/chunks/chunk-YJUO37UX.js +2 -0
- package/dist/bundle/chunks/{cli-main-NUSBF3HE.js → cli-main-26P4V2BK.js} +1 -1
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{help-fast-path-A4S4KOQ6.js → help-fast-path-BOMUI7U3.js} +1 -1
- package/dist/bundle/chunks/{host-command-D2CHSATG.js → host-command-ZVXNTXMN.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle-MPLSJ5NB.js +3 -0
- package/dist/bundle/chunks/host-lifecycle.js +3 -3
- package/dist/bundle/chunks/{interactive-host-runtime-AAK47HIV.js → interactive-host-runtime-Q5EORM6B.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-LSTD6EUQ.js → interactive-mode-OVSKUTVC.js} +1 -1
- package/dist/bundle/chunks/{list-tips-S4U7TKER.js → list-tips-ARO4HRVK.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-5WNZ7XRV.js → multi-session-host-LJNXZRFA.js} +7 -7
- package/dist/bundle/chunks/{openai-completions-DVEOAQK4.js → openai-completions-BHE6TMUP.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-7H2ADNW4.js → openai-responses-OGQ5QORF.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-3HZYQYVX.js → package-manager-cli-MJCRY2JU.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-F36RJ6VP.js → rotation-stream-Q2EVDMUU.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-GMPBEVSL.js → rpc-mode-LY4HAZ5G.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-BYWZGYOJ.js → schedule-command-3ANAEUY6.js} +1 -1
- package/dist/bundle/chunks/{session-picker-6VU2F5VF.js → session-picker-DRM7AGPY.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +37 -37
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/core/extensions/builtin/btw/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/btw/index.js +3 -1
- package/dist/core/extensions/builtin/btw/index.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js +2 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/native.d.ts +1 -0
- package/dist/core/extensions/builtin/websearch/websearch/native.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/native.js +8 -1
- package/dist/core/extensions/builtin/websearch/websearch/native.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/app-server/cli-args.d.ts +3 -0
- package/dist/modes/app-server/cli-args.d.ts.map +1 -1
- package/dist/modes/app-server/cli-args.js +25 -4
- package/dist/modes/app-server/cli-args.js.map +1 -1
- package/dist/modes/app-server/daemon/probe.d.ts +1 -0
- package/dist/modes/app-server/daemon/probe.d.ts.map +1 -1
- package/dist/modes/app-server/daemon/probe.js +4 -1
- package/dist/modes/app-server/daemon/probe.js.map +1 -1
- package/dist/modes/app-server/daemon/spawn.d.ts +26 -0
- package/dist/modes/app-server/daemon/spawn.d.ts.map +1 -0
- package/dist/modes/app-server/daemon/spawn.js +112 -0
- package/dist/modes/app-server/daemon/spawn.js.map +1 -0
- package/dist/modes/app-server/daemon.d.ts.map +1 -1
- package/dist/modes/app-server/daemon.js +14 -112
- package/dist/modes/app-server/daemon.js.map +1 -1
- package/dist/modes/app-server/extension-paths.d.ts +7 -0
- package/dist/modes/app-server/extension-paths.d.ts.map +1 -0
- package/dist/modes/app-server/extension-paths.js +10 -0
- package/dist/modes/app-server/extension-paths.js.map +1 -0
- package/dist/modes/app-server/index.d.ts.map +1 -1
- package/dist/modes/app-server/index.js +4 -1
- package/dist/modes/app-server/index.js.map +1 -1
- package/dist/modes/app-server/runtime.d.ts +5 -1
- package/dist/modes/app-server/runtime.d.ts.map +1 -1
- package/dist/modes/app-server/runtime.js +19 -3
- package/dist/modes/app-server/runtime.js.map +1 -1
- package/dist/modes/interactive/tips/catalog/computer-tips.js +1 -1
- package/dist/modes/interactive/tips/catalog/computer-tips.js.map +1 -1
- package/dist/modes/rpc/custom-capability.d.ts +5 -0
- package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
- package/dist/modes/rpc/custom-capability.js +5 -0
- package/dist/modes/rpc/custom-capability.js.map +1 -1
- package/dist/modes/rpc/host-identity-env.d.ts +20 -0
- package/dist/modes/rpc/host-identity-env.d.ts.map +1 -0
- package/dist/modes/rpc/host-identity-env.js +20 -0
- package/dist/modes/rpc/host-identity-env.js.map +1 -0
- package/dist/modes/rpc/host-lifecycle.js +1 -1
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-observe-request.d.ts +2 -0
- package/dist/modes/rpc/host-observe-request.d.ts.map +1 -1
- package/dist/modes/rpc/host-observe-request.js +4 -0
- package/dist/modes/rpc/host-observe-request.js.map +1 -1
- package/dist/modes/rpc/host-spawn-environment.js +1 -1
- package/dist/modes/rpc/host-spawn-environment.js.map +1 -1
- package/dist/modes/rpc/host-warm.d.ts +57 -0
- package/dist/modes/rpc/host-warm.d.ts.map +1 -0
- package/dist/modes/rpc/host-warm.js +125 -0
- package/dist/modes/rpc/host-warm.js.map +1 -0
- package/dist/modes/rpc/protocol-identity.d.ts +2 -11
- package/dist/modes/rpc/protocol-identity.d.ts.map +1 -1
- package/dist/modes/rpc/protocol-identity.js +2 -11
- package/dist/modes/rpc/protocol-identity.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +24 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +2 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +12 -1
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +6 -2
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +6 -0
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/docs/app-server-daemon.md +1 -1
- package/docs/app-server.md +3 -0
- package/docs/rpc.md +48 -2
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-endpoint.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-endpoint.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-endpoint.js +48 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-endpoint.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-errors.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-errors.js +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-errors.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js +18 -36
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +6 -5
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.js +15 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/chunk-A4UMPXQF.js +0 -2
- package/dist/bundle/chunks/chunk-HH3KJDWA.js +0 -2
- package/dist/bundle/chunks/chunk-XPJLBOWV.js +0 -5
- package/dist/bundle/chunks/host-lifecycle-S7O5K62Z.js +0 -3
|
@@ -0,0 +1,5 @@
|
|
|
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{VERSION}from"./chunk-PBWQK23Z.js";var CALVER=/^(\d+)\.(\d+)\.(\d+)(?:-(\d+))?/;function engineBuildIdentityFrom(build){let match=CALVER.exec(build.version),epoch=Number.isSafeInteger(build.epoch)&&build.epoch!==void 0&&build.epoch>0?build.epoch:0,sha7=build.sha7??"";return{text:epoch===0?build.version:`${build.version}+${epoch}${sha7===""?"":`.${sha7}`}`,ordinal:[match?Number(match[1]):0,match?Number(match[2]):0,match?Number(match[3]):0,match?.[4]?Number(match[4]):0,epoch],scheme:epoch===0?"nodef":"epoch"}}var BUILT=engineBuildIdentityFrom({version:VERSION,epoch:typeof SENPI_BUILD_EPOCH=="number"?SENPI_BUILD_EPOCH:0,sha7:typeof SENPI_BUILD_SHA7=="string"?SENPI_BUILD_SHA7:""});function engineBuildIdentity(){return BUILT}function compareEngineOrdinal(a,b){for(let index=0;index<4;index++)if(a.ordinal[index]!==b.ordinal[index])return a.ordinal[index]>b.ordinal[index]?1:-1;return a.scheme!=="epoch"||b.scheme!=="epoch"||a.ordinal[4]===b.ordinal[4]?0:a.ordinal[4]>b.ordinal[4]?1:-1}var HOST_GENERATION_ENV="SENPI_RPC_HOST_GENERATION",HOST_INSTANCE_ID_ENV="SENPI_RPC_HOST_INSTANCE_ID";import{StringDecoder}from"node:string_decoder";function serializeJsonLine(value){return`${JSON.stringify(value)}
|
|
3
|
+
`}var MAX_RPC_LINE_CHARACTERS=16*1024*1024;function attachJsonlLineReader(stream,onLine,options={}){let decoder=new StringDecoder("utf8"),maxLineLength=options.maxLineLength??Number.POSITIVE_INFINITY;if(!(maxLineLength>0))throw new Error("maxLineLength must be greater than zero.");let buffer="",discardingOversizedLine=!1,consume=text=>{let offset=0;for(;offset<text.length;){if(discardingOversizedLine){let newlineIndex2=text.indexOf(`
|
|
4
|
+
`,offset);if(newlineIndex2===-1)return;discardingOversizedLine=!1,offset=newlineIndex2+1;continue}let newlineIndex=text.indexOf(`
|
|
5
|
+
`,offset);if(newlineIndex===-1){let remainder=text.slice(offset);buffer.length+remainder.length>maxLineLength?(buffer="",discardingOversizedLine=!0,options.onOversizedLine?.()):buffer+=remainder;return}let segment=text.slice(offset,newlineIndex);if(buffer.length+segment.length>maxLineLength)options.onOversizedLine?.();else{let line=buffer+segment;onLine(line.endsWith("\r")?line.slice(0,-1):line)}buffer="",offset=newlineIndex+1}},onData=chunk=>{consume(typeof chunk=="string"?chunk:decoder.write(chunk))},onEnd=()=>{consume(decoder.end()),!discardingOversizedLine&&buffer.length>0&&onLine(buffer.endsWith("\r")?buffer.slice(0,-1):buffer),buffer="",discardingOversizedLine=!1};return stream.on("data",onData),stream.on("end",onEnd),()=>{stream.off("data",onData),stream.off("end",onEnd)}}export{engineBuildIdentityFrom,engineBuildIdentity,compareEngineOrdinal,HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,serializeJsonLine,MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader};
|
|
@@ -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{readSocketSecret,resolveSocketTransportAddress,sendSocketHandshake,socketSecretPath}from"./chunk-
|
|
2
|
+
import{readSocketSecret,resolveSocketTransportAddress,sendSocketHandshake,socketSecretPath}from"./chunk-Y4CH7LYI.js";import{attachJsonlLineReader,serializeJsonLine}from"./chunk-E5F5SVZF.js";import{sanitizeBinaryOutput}from"./chunk-ASAQQ6VM.js";import{dropFailedAssistantTurns}from"./chunk-TOCWAEQB.js";import{copyContextProvenance}from"./chunk-UDTWLXSQ.js";import{APP_NAME,getAgentDir,getSessionsDir,normalizePath,resolvePath}from"./chunk-PBWQK23Z.js";import{normalizeProviderId}from"./chunk-7X4ZMME4.js";var ENVIRONMENT_CONTEXT_MESSAGE_TYPE="environment-context";function resolveEnvironmentContext(cwd,now=new Date){return{cwd:cwd.replace(/\\/g,"/"),currentDate:now.toISOString().slice(0,10)}}function formatEnvironmentContext(context){return["<environment_context>",` <cwd>${context.cwd}</cwd>`,` <current_date>${context.currentDate}</current_date>`,"</environment_context>"].join(`
|
|
3
3
|
`)}function isEnvironmentContext(value){if(typeof value!="object"||value===null)return!1;let candidate=value;return typeof candidate.cwd=="string"&&typeof candidate.currentDate=="string"}function latestEnvironmentContext(messages){for(let index=messages.length-1;index>=0;index--){let message=messages[index];if(message.role==="custom"&&message.customType===ENVIRONMENT_CONTEXT_MESSAGE_TYPE&&isEnvironmentContext(message.details))return message.details}}function createEnvironmentContextMessage(context,timestamp=Date.now()){return{role:"custom",customType:ENVIRONMENT_CONTEXT_MESSAGE_TYPE,content:formatEnvironmentContext(context),display:!1,details:{cwd:context.cwd,currentDate:context.currentDate},timestamp}}function environmentContextMessageIfChanged(messages,current){let latest=latestEnvironmentContext(messages);if(!(latest?.cwd===current.cwd&&latest.currentDate===current.currentDate))return createEnvironmentContextMessage(current)}function contentBlocks(content){return typeof content=="string"?[{type:"text",text:content}]:content}function foldEnvironmentContextIntoNextUserMessage(messages,environmentMessages){let folded=[];for(let index=0;index<messages.length;index++){let message=messages[index],next=messages[index+1];if(environmentMessages.has(message)&&message.role==="user"&&next?.role==="user"&&!environmentMessages.has(next)){folded.push({...next,content:[...contentBlocks(message.content),...contentBlocks(next.content)]}),index++;continue}folded.push(message)}return folded}var PROVIDER_IMAGE_REJECTION_PATTERN=/does not represent a valid image|image_parse_error|invalid_image|unsupported image|could not process image|unable to process input image|image_url'?\.?[^\n]*invalid base64|expected a base64-encoded data url|image was specified using the image\/[a-z]+ media type|unsupported media type for base64 image|invalid data url for image/i;function isProviderImageRejection(errorMessage){return errorMessage!==void 0&&PROVIDER_IMAGE_REJECTION_PATTERN.test(errorMessage)}function rejectedImagePlaceholder(source){return`[Image omitted: the provider rejected this image (${source}) as invalid, so it is no longer sent with the conversation.]`}function field(message,key){return key in message?message[key]:void 0}function contentBlocks2(message){let content=field(message,"content");return Array.isArray(content)?content:[]}function toolCallSource(block){let args=block.arguments;if(typeof args!="object"||args===null)return;let record=args;for(let key of["path","file_path","filePath"]){let value=record[key];if(typeof value=="string"&&value.trim().length>0)return value}}function imageSource(message,toolCallSources){if(message.role!=="toolResult")return"an attached image";let toolCallId=field(message,"toolCallId"),known=typeof toolCallId=="string"?toolCallSources.get(toolCallId):void 0;if(known)return known;let toolName=field(message,"toolName");return typeof toolName=="string"?`${toolName} tool result`:"a tool result"}function scanRejectedImages(messages){let toolCallSources=new Map,rejections=new Map,unconfirmed=[];return messages.forEach((message,messageIndex)=>{if(message.role==="assistant"){for(let block of contentBlocks2(message)){let source=block.type==="toolCall"?toolCallSource(block):void 0;source&&typeof block.id=="string"&&toolCallSources.set(block.id,source)}let stopReason=field(message,"stopReason"),errorMessage=field(message,"errorMessage");stopReason==="error"&&isProviderImageRejection(typeof errorMessage=="string"?errorMessage:void 0)?(unconfirmed.length>0&&rejections.set(messageIndex,unconfirmed),unconfirmed=[]):stopReason!=="error"&&stopReason!=="aborted"&&(unconfirmed=[]);return}message.role!=="user"&&message.role!=="toolResult"||contentBlocks2(message).forEach((block,blockIndex)=>{block.type==="image"&&unconfirmed.push({messageIndex,blockIndex,source:imageSource(message,toolCallSources)})})}),rejections}function rejectedImageSources(messages,failedTurn){let failedIndex=messages.lastIndexOf(failedTurn);return(scanRejectedImages(messages).get(failedIndex)??[]).map(image=>image.source)}function omitProviderRejectedImages(messages){let rejected=new Map;for(let images of scanRejectedImages(messages).values())for(let image of images){let blocks=rejected.get(image.messageIndex)??new Map;blocks.set(image.blockIndex,image.source),rejected.set(image.messageIndex,blocks)}return rejected.size===0?messages:messages.map((message,messageIndex)=>{let blocks=rejected.get(messageIndex);if(!blocks)return message;let content=contentBlocks2(message).map((block,blockIndex)=>{let source=blocks.get(blockIndex);return source===void 0?block:{type:"text",text:rejectedImagePlaceholder(source)}});return{...message,content}})}var COMPACTION_SUMMARY_PREFIX=`The conversation history before this point was compacted into the following summary:
|
|
4
4
|
|
|
5
5
|
<summary>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{classifyProviderFailure,formatProviderRequestId}from"./chunk-TJV2LFKM.js";import{attachProviderDiagnostic}from"./chunk-45SZOLCU.js";import{normalizeProviderError}from"./chunk-BBK6SSYT.js";import{appendAssistantMessageDiagnostic}from"./chunk-DMI55M2N.js";var GITHUB_COPILOT_TOOL_LIMIT=128,GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC="github_copilot_tool_limit";function isRecord(value){return typeof value=="object"&&value!==null}function selectedToolName(toolChoice){if(isRecord(toolChoice)){if(toolChoice.type==="function")return isRecord(toolChoice.function)&&typeof toolChoice.function.name=="string"?toolChoice.function.name:typeof toolChoice.name=="string"?toolChoice.name:void 0;if(!(toolChoice.type!=="custom"&&toolChoice.type!=="tool"))return typeof toolChoice.name=="string"?toolChoice.name:void 0}}function toolName(tool){if(isRecord(tool))return tool.type==="function"&&isRecord(tool.function)&&typeof tool.function.name=="string"?tool.function.name:typeof tool.name=="string"?tool.name:void 0}function limitGitHubCopilotTools(provider,tools,toolChoice){if(provider!=="github-copilot"||tools===void 0||tools.length<=GITHUB_COPILOT_TOOL_LIMIT)return{tools,omittedCount:0};let forcedName=selectedToolName(toolChoice),forcedIndex=forcedName===void 0?-1:tools.findIndex(tool=>toolName(tool)===forcedName);if(forcedIndex>=GITHUB_COPILOT_TOOL_LIMIT){let forcedTool=tools[forcedIndex];if(forcedTool!==void 0)return{tools:[...tools.slice(0,GITHUB_COPILOT_TOOL_LIMIT-1),forcedTool],omittedCount:tools.length-GITHUB_COPILOT_TOOL_LIMIT}}return{tools:tools.slice(0,GITHUB_COPILOT_TOOL_LIMIT),omittedCount:tools.length-GITHUB_COPILOT_TOOL_LIMIT}}function recordGitHubCopilotToolLimit(message,omittedCount){omittedCount===0||message.diagnostics?.some(diagnostic=>diagnostic.type===GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC)||appendAssistantMessageDiagnostic(message,{type:GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC,timestamp:Date.now(),details:{limit:GITHUB_COPILOT_TOOL_LIMIT,omittedCount,message:`GitHub Copilot accepts at most ${GITHUB_COPILOT_TOOL_LIMIT} tools on endpoints without tool search; senpi omitted ${omittedCount} excess tool definition${omittedCount===1?"":"s"}.`}})}function formatGitHubCopilotToolLimitError(message,errorMessage){let toolLimitApplied=message.diagnostics?.some(diagnostic=>diagnostic.type===GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC);return message.provider!=="github-copilot"||!toolLimitApplied||message.providerDiagnostic?.httpStatus!==400||!/400 Bad Request$/i.test(errorMessage)?errorMessage:`GitHub Copilot rejected the request after senpi limited its tool list to ${GITHUB_COPILOT_TOOL_LIMIT}. The endpoint may enforce a lower limit or count additional hosted tools. (${errorMessage})`}var SSE_ERROR_ENVELOPE_MAX_BYTES=8192;function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function optionalString(value){if(value!=null)return typeof value=="string"?value:null}function anthropicProviderDiagnosticFromError(error){try{if(!(error instanceof Error))return;let status=Reflect.get(error,"status"),direct=optionalString(Reflect.get(error,"type")),body=Reflect.get(error,"error"),nested=isRecord2(body)&&isRecord2(body.error)?optionalString(body.error.type):void 0;if(direct===null||nested===null||direct!==void 0&&nested!==void 0&&direct!==nested)return;let code=direct??nested;return code===void 0&&status==null?void 0:classifyProviderFailure({status,code})}catch{return}}function anthropicProviderDiagnosticFromSseData(data){try{if(new TextEncoder().encode(data).length>SSE_ERROR_ENVELOPE_MAX_BYTES)return;let parsed=JSON.parse(data);if(!isRecord2(parsed)||parsed.type!=="error"||!isRecord2(parsed.error))return;let code=parsed.error.type;return typeof code!="string"?void 0:classifyProviderFailure({status:void 0,code})}catch{return}}function openAICompatibleProviderDiagnosticFromError(error){try{if(!(error instanceof Error))return;let status=Reflect.get(error,"status"),code=optionalString(Reflect.get(error,"code"));return code===null||code===void 0&&status==null?void 0:classifyProviderFailure({status,code})}catch{return}}async function awaitProviderTransport(request,classify){try{return await request()}catch(error){throw typeof error=="object"&&error!==null&&attachProviderDiagnostic(error,classify(error)),error}}async function*iterateProviderTransport(source,classify){try{yield*source}catch(error){throw typeof error=="object"&&error!==null&&attachProviderDiagnostic(error,classify(error)),error}}var QUOTA_CODES=new Set(["quota_exceeded","free_quota_exceeded","overage_limit_reached","billing_not_configured","additional_spend_limit_reached"]);function headerValue(headers,name){if(headers instanceof Headers)return headers.get(name)??void 0;if(!(typeof headers!="object"||headers===null)){for(let[key,value]of Object.entries(headers))if(key.toLowerCase()===name&&typeof value=="string")return value}}function errorCode(body){if(body!==void 0)try{let parsed=JSON.parse(body);if(typeof parsed!="object"||parsed===null)return;let nested=Reflect.get(parsed,"error"),code=Reflect.get(typeof nested=="object"&&nested!==null?nested:parsed,"code");return typeof code=="string"?code:void 0}catch{return}}function isQuotaFailure(status,body,limitKey){let code=errorCode(body);return code!==void 0&"A_CODES.has(code)||status===402?!0:status===429&&(limitKey?.includes("quota")===!0||/quota exceeded/i.test(body??""))}function describeGitHubCopilotFailure(error){if(!(error instanceof Error))return;let{status,body}=normalizeProviderError(error);if(status===void 0)return;let headers=Reflect.get(error,"headers"),requestId=headerValue(headers,"x-github-request-id"),reference=requestId===void 0?"":` ${formatProviderRequestId("GitHub",requestId)}.`;if(isQuotaFailure(status,body,headerValue(headers,"x-ratelimit-exceeded")))return`GitHub Copilot quota exceeded (HTTP ${status}): the plan's included usage or its additional-usage limit is used up, so premium models are refused until it resets or the limit is raised. Usage is shown at https://github.com/settings/copilot.${reference}`;if(status===403)return`GitHub Copilot refused the request (HTTP 403${body===void 0?" with an empty body":""}). Copilot checks access per model and per client; if a fresh /login github-copilot does not help, report it with the GitHub request id.${reference}`}function withGitHubCopilotFailureNote(message,provider,error){if(provider!=="github-copilot")return message;let note=describeGitHubCopilotFailure(error);return note===void 0?message:`${message}
|
|
2
|
+
import{classifyProviderFailure,formatProviderRequestId}from"./chunk-TJV2LFKM.js";import{attachProviderDiagnostic}from"./chunk-45SZOLCU.js";import{normalizeProviderError}from"./chunk-BBK6SSYT.js";import{appendAssistantMessageDiagnostic}from"./chunk-DMI55M2N.js";var GITHUB_COPILOT_TOOL_LIMIT=128,GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC="github_copilot_tool_limit";function isRecord(value){return typeof value=="object"&&value!==null}function selectedToolName(toolChoice){if(isRecord(toolChoice)){if(toolChoice.type==="function")return isRecord(toolChoice.function)&&typeof toolChoice.function.name=="string"?toolChoice.function.name:typeof toolChoice.name=="string"?toolChoice.name:void 0;if(!(toolChoice.type!=="custom"&&toolChoice.type!=="tool"))return typeof toolChoice.name=="string"?toolChoice.name:void 0}}function toolName(tool){if(isRecord(tool))return tool.type==="function"&&isRecord(tool.function)&&typeof tool.function.name=="string"?tool.function.name:typeof tool.name=="string"?tool.name:void 0}function limitGitHubCopilotTools(provider,tools,toolChoice){if(provider!=="github-copilot"||tools===void 0||tools.length<=GITHUB_COPILOT_TOOL_LIMIT)return{tools,omittedCount:0};let forcedName=selectedToolName(toolChoice),forcedIndex=forcedName===void 0?-1:tools.findIndex(tool=>toolName(tool)===forcedName);if(forcedIndex>=GITHUB_COPILOT_TOOL_LIMIT){let forcedTool=tools[forcedIndex];if(forcedTool!==void 0)return{tools:[...tools.slice(0,GITHUB_COPILOT_TOOL_LIMIT-1),forcedTool],omittedCount:tools.length-GITHUB_COPILOT_TOOL_LIMIT}}return{tools:tools.slice(0,GITHUB_COPILOT_TOOL_LIMIT),omittedCount:tools.length-GITHUB_COPILOT_TOOL_LIMIT}}function recordGitHubCopilotToolLimit(message,omittedCount){omittedCount===0||message.diagnostics?.some(diagnostic=>diagnostic.type===GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC)||appendAssistantMessageDiagnostic(message,{type:GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC,timestamp:Date.now(),details:{limit:GITHUB_COPILOT_TOOL_LIMIT,omittedCount,message:`GitHub Copilot accepts at most ${GITHUB_COPILOT_TOOL_LIMIT} tools on endpoints without tool search; senpi omitted ${omittedCount} excess tool definition${omittedCount===1?"":"s"}.`}})}function formatGitHubCopilotToolLimitError(message,errorMessage){let toolLimitApplied=message.diagnostics?.some(diagnostic=>diagnostic.type===GITHUB_COPILOT_TOOL_LIMIT_DIAGNOSTIC);return message.provider!=="github-copilot"||!toolLimitApplied||message.providerDiagnostic?.httpStatus!==400||!/400 Bad Request$/i.test(errorMessage)?errorMessage:`GitHub Copilot rejected the request after senpi limited its tool list to ${GITHUB_COPILOT_TOOL_LIMIT}. The endpoint may enforce a lower limit or count additional hosted tools. (${errorMessage})`}var SSE_ERROR_ENVELOPE_MAX_BYTES=8192;function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function optionalString(value){if(value!=null)return typeof value=="string"?value:null}function anthropicProviderDiagnosticFromError(error){try{if(!(error instanceof Error))return;let status=Reflect.get(error,"status"),direct=optionalString(Reflect.get(error,"type")),body=Reflect.get(error,"error"),nested=isRecord2(body)&&isRecord2(body.error)?optionalString(body.error.type):void 0;if(direct===null||nested===null||direct!==void 0&&nested!==void 0&&direct!==nested)return;let code=direct??nested;return code===void 0&&status==null?void 0:classifyProviderFailure({status,code})}catch{return}}function anthropicProviderDiagnosticFromSseData(data){try{if(new TextEncoder().encode(data).length>SSE_ERROR_ENVELOPE_MAX_BYTES)return;let parsed=JSON.parse(data);if(!isRecord2(parsed)||parsed.type!=="error"||!isRecord2(parsed.error))return;let code=parsed.error.type;return typeof code!="string"?void 0:classifyProviderFailure({status:void 0,code})}catch{return}}function openAICompatibleProviderDiagnosticFromError(error){try{if(!(error instanceof Error))return;let status=Reflect.get(error,"status"),code=optionalString(Reflect.get(error,"code"));return code===null||code===void 0&&status==null?void 0:classifyProviderFailure({status,code})}catch{return}}async function awaitProviderTransport(request,classify){try{return await request()}catch(error){throw typeof error=="object"&&error!==null&&attachProviderDiagnostic(error,classify(error)),error}}async function*iterateProviderTransport(source,classify){try{yield*source}catch(error){throw typeof error=="object"&&error!==null&&attachProviderDiagnostic(error,classify(error)),error}}var QUOTA_CODES=new Set(["quota_exceeded","free_quota_exceeded","overage_limit_reached","billing_not_configured","additional_spend_limit_reached"]);function headerValue(headers,name){if(headers instanceof Headers)return headers.get(name)??void 0;if(!(typeof headers!="object"||headers===null)){for(let[key,value]of Object.entries(headers))if(key.toLowerCase()===name&&typeof value=="string")return value}}function errorCode(body){if(body!==void 0)try{let parsed=JSON.parse(body);if(typeof parsed!="object"||parsed===null)return;let nested=Reflect.get(parsed,"error"),code=Reflect.get(typeof nested=="object"&&nested!==null?nested:parsed,"code");return typeof code=="string"?code:void 0}catch{return}}function isQuotaFailure(status,body,limitKey){let code=errorCode(body);return code!==void 0&"A_CODES.has(code)||status===402?!0:status===429&&(limitKey?.includes("quota")===!0||/quota exceeded/i.test(body??""))}function describeGitHubCopilotFailure(error){if(!(error instanceof Error))return;let{status,body}=normalizeProviderError(error);if(status===void 0)return;let headers=Reflect.get(error,"headers"),requestId=headerValue(headers,"x-github-request-id"),reference=requestId===void 0?"":` ${formatProviderRequestId("GitHub",requestId)}.`;if(isQuotaFailure(status,body,headerValue(headers,"x-ratelimit-exceeded")))return`GitHub Copilot quota exceeded (HTTP ${status}): the plan's included usage or its additional-usage limit is used up, so premium models are refused until it resets or the limit is raised. Usage is shown at https://github.com/settings/copilot.${reference}`;if(status===421)return`GitHub Copilot sent this account to a different API host (HTTP 421 Misdirected Request): Business and Enterprise accounts are served from their own host, which senpi reads from the Copilot token. Run /login github-copilot so senpi stores the account's endpoint, and report it with the GitHub request id if it persists.${reference}`;if(status===403)return`GitHub Copilot refused the request (HTTP 403${body===void 0?" with an empty body":""}). Copilot checks access per model and per client; if a fresh /login github-copilot does not help, report it with the GitHub request id.${reference}`}function withGitHubCopilotFailureNote(message,provider,error){if(provider!=="github-copilot")return message;let note=describeGitHubCopilotFailure(error);return note===void 0?message:`${message}
|
|
3
3
|
${note}`}export{limitGitHubCopilotTools,recordGitHubCopilotToolLimit,formatGitHubCopilotToolLimitError,anthropicProviderDiagnosticFromError,anthropicProviderDiagnosticFromSseData,openAICompatibleProviderDiagnosticFromError,awaitProviderTransport,iterateProviderTransport,withGitHubCopilotFailureNote};
|
|
@@ -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{HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,acquireHostEnsureLock,daemonEnvKeys,daemonEnvOverrides,decideHostAction,ensureHost,handoffHost,observeProtocolInfo,probeProtocolInfo,readDaemonEnvKeys,requestOnSocket,stopHost,writeDaemonEnvKeys}from"./chunk-Z5NVK72W.js";import{HOST_DAEMON_LAYOUT,OBSERVE_REQUEST_FIELD,ProcessIdentityUnreadableError,claimOwnerIsLive,createHostDaemonPaths,generationPaths,hostDaemonDirectoryPaths,parseDaemonPidFile,parseJson,parseShardSocket,processMatchesPidFile,pruneDeadGenerations,readFileOrUndefined,readGenerationRows,readHostCrashRecords,readHostProcessMetrics,readSessionPathClaims,readSocketSecret,resolveSocketTransportAddress,shardKey,shardSocketPathForKey,socketNamesDirectory,socketSecretPath}from"./chunk-7SFG425F.js";import{engineBuildIdentity}from"./chunk-XPJLBOWV.js";import{isSessionRuntimeKind}from"./chunk-KDZAVHA7.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-PBWQK23Z.js";import{writeSync}from"node:fs";import{join as join4,resolve as resolve2}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{lstat as lstat2,rm}from"node:fs/promises";import{dirname as dirname3,join as join3}from"node:path";import{readdir}from"node:fs/promises";import{basename,join}from"node:path";var ENDPOINT_DIRECTORY_NAME=/^[0-9a-f]{16}$/;async function listHostEndpoints(agentDir){let flatDir=join(agentDir,"rpc-host-daemon");if(parseJson(await readFileOrUndefined(join(flatDir,"layout.json")).catch(()=>{}))?.layout!==HOST_DAEMON_LAYOUT)return[];let dirs=(await readdir(flatDir,{withFileTypes:!0}).catch(()=>[])).filter(entry=>entry.isDirectory()&&ENDPOINT_DIRECTORY_NAME.test(entry.name)).map(entry=>join(flatDir,entry.name)).sort(),endpoints=[];for(let dir of dirs)endpoints.push(await identifyEndpoint(dir));return endpoints}async function identifyEndpoint(dir){let paths=hostDaemonDirectoryPaths(dir),named=await socketNamedBy(paths.endpointFile,dir);if(named!==void 0)return{socket:named,dir,identity:"endpoint"};let booted=await socketNamedBy(paths.settingsFile,dir);if(booted!==void 0)return{socket:booted,dir,identity:"settings"};let generations=await readdir(paths.generationsDir).catch(()=>[]);for(let instanceId of generations.sort()){let recorded=await socketNamedBy(join(paths.generationsDir,instanceId,"settings.json"),dir);if(recorded!==void 0)return{socket:recorded,dir,identity:"generation-settings"}}return{socket:null,dir,identity:"unknown"}}async function socketNamedBy(file,dir){let socket=parseJson(await readFileOrUndefined(file).catch(()=>{}))?.socket;if(!(typeof socket!="string"||socket===""))return socketNamesDirectory(socket,basename(dir))?socket:void 0}import{lstat,readdir as readdir2}from"node:fs/promises";import{createConnection}from"node:net";import{basename as basename2,dirname as dirname2,join as join2}from"node:path";var SOCKET_PROBE_TIMEOUT_MS=2e3;async function endpointInUse(paths,socket){if(await anyGenerationLive(paths))return{inUse:"live_generation"};for(let claim of await readSessionPathClaims(paths.reservationsDir))if(await claimOwnerIsLive(claim.owner))return{inUse:"live_claim"};let silence=await socketSilence(socket);if(silence===void 0)return{inUse:"reachable"};let successors=(await socketSiblings(socket)).filter(name=>name.startsWith(`${basename2(socket)}.next-`));for(let successor of successors)if(await socketSilence(join2(dirname2(socket),successor))===void 0)return{inUse:"reachable"};return{inUse:void 0,silence}}async function socketSiblings(socket){let name=basename2(socket);return(await readdir2(dirname2(socket)).catch(()=>[])).filter(entry=>entry.startsWith(`${name}.next-`)||entry.startsWith(`${name}.shield-`))}async function anyGenerationLive(paths){for(let instanceId of await readdir2(paths.generationsDir).catch(()=>[])){let record=generationRecord(await readFileOrUndefined(generationPaths(paths,instanceId).pidFile));if(record!==void 0&&await recordIsLive(record))return!0}return!1}function generationRecord(text){if(text===void 0)return;let record=parseDaemonPidFile(text);if(record!==void 0)return record;let pid=parseJson(text)?.pid;return typeof pid=="number"&&Number.isInteger(pid)&&pid>0?{pid,processStartTime:null}:void 0}async function recordIsLive(record){try{return await processMatchesPidFile(record)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!0;throw error}}async function socketSilence(socket){let secret;return process.platform==="win32"&&(secret=await readSocketSecret(socketSecretPath(socket)).catch(()=>{}),secret===void 0)?"socket_absent":new Promise(resolveProbe=>{let connection=createConnection(resolveSocketTransportAddress(socket,process.platform,secret)),finish=value=>{clearTimeout(timeout),connection.destroy(),resolveProbe(value)},timeout=setTimeout(()=>finish(void 0),SOCKET_PROBE_TIMEOUT_MS);connection.once("connect",()=>finish(void 0)),connection.once("error",error=>{error.code==="ECONNREFUSED"?refusedBySocket(socket).then(finish):error.code==="ENOENT"?finish("socket_absent"):finish(void 0)})})}async function refusedBySocket(socket){if(process.platform==="win32"||socket.startsWith("\0"))return"socket_refused";try{return(await lstat(socket)).isSocket()?"socket_refused":void 0}catch(error){return error instanceof Error&&"code"in error&&error.code==="ENOENT"?"socket_absent":void 0}}var GC_LOCK_WAIT_MS=2e3;async function gcHostEndpoints(agentDir,options={}){let removed=[],kept=[],legacy=await legacyFlatDirectory(agentDir);legacy!==void 0&&kept.push({socket:null,dir:legacy,reason:"legacy_layout"});for(let endpoint of await listHostEndpoints(agentDir)){if(endpoint.socket===null){kept.push({socket:null,dir:endpoint.dir,reason:"unknown_identity"});continue}let entry={socket:endpoint.socket,dir:endpoint.dir};try{let outcome=await gcEndpoint(endpoint.socket,endpoint.dir,options);outcome.removed?outcome.skipped.length===0?removed.push({...entry,reason:outcome.reason}):removed.push({...entry,reason:outcome.reason,skipped:outcome.skipped}):kept.push({...entry,reason:outcome.reason})}catch(error){kept.push({...entry,reason:"failed",error:error instanceof Error?error.message:String(error)})}}return{removed,kept}}async function gcEndpoint(socket,dir,options){let release=await acquireEnsureLock(socket);if(release===void 0)return{removed:!1,reason:"locked"};try{await options._test?.afterLockAcquired?.(socket);let evidence=await endpointInUse(hostDaemonDirectoryPaths(dir),socket);if(evidence.inUse!==void 0)return{removed:!1,reason:evidence.inUse};let skipped=await removeEndpoint(socket,dir);return{removed:!0,reason:evidence.silence,skipped}}finally{await release()}}async function removeEndpoint(socket,dir){let skipped=[];for(let sibling of await socketSiblings(socket)){let path=join3(dirname3(socket),sibling),entry=await lstat2(path).catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});entry?.isDirectory()?skipped.push({path,type:"directory"}):entry!==void 0&&await rm(path,{force:!0})}return await rm(socket,{force:!0}),await rm(dir,{recursive:!0,force:!0}),skipped}async function acquireEnsureLock(socket){return acquireHostEnsureLock(socket,GC_LOCK_WAIT_MS).catch(()=>{})}async function legacyFlatDirectory(agentDir){let flatDir=join3(agentDir,"rpc-host-daemon");return parseJson(await readFileOrUndefined(join3(flatDir,"layout.json")).catch(()=>{}))?.layout===HOST_DAEMON_LAYOUT?void 0:await readFileOrUndefined(join3(flatDir,"host.pid")).catch(()=>{})!==void 0?flatDir:void 0}function parseSessionRows(reply){return!isRecord2(reply)||!Array.isArray(reply.sessions)?[]:reply.sessions.flatMap(entry=>isRecord2(entry)?[{id:typeof entry.sessionId=="string"?entry.sessionId:"",kind:typeof entry.kind=="string"?entry.kind:"interactive",session_path:typeof entry.sessionPath=="string"?entry.sessionPath:null,attachments:typeof entry.attachments=="number"?entry.attachments:0,context:stringRecord(entry.context)}]:[])}async function readClaimRows(paths,generations){let rows=[];for(let claim of await readSessionPathClaims(paths.reservationsDir)){let owner=claim.owner;rows.push({session_path:owner.sessionPath,owner_pid:owner.pid,instance_id:owner.instanceId,generation:generations.find(row=>row.instanceId===owner.instanceId)?.generation??null,attached:owner.attached??null,live:await claimOwnerIsLive(owner)})}return rows.sort((left,right)=>left.session_path.localeCompare(right.session_path))}function stringRecord(value){return isRecord2(value)?Object.fromEntries(Object.entries(value).filter(entry=>typeof entry[1]=="string")):null}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var STATUS_PROBE_TIMEOUT_MS=1e4;async function readHostStatus(options,read={}){let paths=createHostDaemonPaths({socket:options.socket,...options.agentDir?{agentDir:options.agentDir}:{}}),prune=read.prune!==!1,includeWorkers=options.includeWorkers===!0,timeoutMs=read.timeoutMs??STATUS_PROBE_TIMEOUT_MS,host=await observeProtocolInfo(options.socket,timeoutMs);prune&&await pruneDeadGenerations(paths);let generations=await readGenerationRows(paths,{includeDead:!prune}),current=generations.find(row=>row.current&&row.alive),metrics=current?await readHostProcessMetrics(current.pid):UNOBSERVED_METRICS,listing=host===void 0?[]:await readSessionListing(options.socket,includeWorkers,timeoutMs),claims=await readClaimRows(paths,generations);return{reachable:host!==void 0,socket:options.socket,pid:current?.pid??null,instanceId:host?.instanceId??current?.instanceId??null,generation:host?.generation??current?.generation??null,engineVersion:host?.engineVersion??current?.engineVersion??null,capabilities:host?.capabilities??[],launchProfile:host?.launch_profile??null,sessions:countSessions(listing),zombies:metrics.zombies,rss_mb:metrics.rss_mb,host_rss_mb:metrics.host_rss_mb,open_fds:metrics.open_fds,memory_pressure:host?.memory_pressure??null,env_keys:await readDaemonEnvKeys(paths),generations,crashes:readHostCrashRecords(paths.dir).length,shard:parseShardSocket(options.socket),session_rows:includeWorkers?listing:[],claims_live:claims.filter(claim=>claim.live).length,claims:includeWorkers?claims:[]}}async function readSessionCounts(socket,includeWorkers){return countSessions(await readSessionListing(socket,includeWorkers))}async function readSessionListing(socket,includeWorkers,timeoutMs=STATUS_PROBE_TIMEOUT_MS){let reply=await requestOnSocket(socket,{type:"list_sessions",[OBSERVE_REQUEST_FIELD]:!0,...includeWorkers?{include_workers:!0}:{}},timeoutMs);return parseSessionRows(reply)}function countSessions(rows){let attached=rows.filter(row=>row.attachments>0).length,retained=rows.length-attached;return{total:rows.length,interactive:rows.filter(row=>row.kind!=="worker").length,worker:rows.filter(row=>row.kind==="worker").length,retained,foreign_attached:attached,foreign_retained:retained}}function hostSummary(host){return host===void 0?null:{protocolVersion:host.protocolVersion,serverVersion:host.serverVersion,capabilities:host.capabilities,instanceId:host.instanceId??null,generation:host.generation??null,engineVersion:host.engineVersion??null,launchProfileId:host.launch_profile?.profile_id??null}}var UNOBSERVED_METRICS={rss_mb:null,host_rss_mb:null,open_fds:null,zombies:null};var STATUS_ALL_MAX_IN_FLIGHT=64;async function readAllHostStatus(options){let endpoints=await listHostEndpoints(options.agentDir),read=options._test?.readEndpoint??(endpoint=>endpointStatus(endpoint,options)),rows=new Array(endpoints.length),next=0,worker=async()=>{for(let index=next++;index<endpoints.length;index=next++){let endpoint=endpoints[index];endpoint!==void 0&&(rows[index]=await read(endpoint))}};return await Promise.all(Array.from({length:Math.min(STATUS_ALL_MAX_IN_FLIGHT,endpoints.length)},worker)),rows}async function endpointStatus(endpoint,options){let located={dir:endpoint.dir,identity:endpoint.identity};return endpoint.socket===null?{...await unaddressableStatus(endpoint.dir),socket:null,...located}:{...await readHostStatus({socket:endpoint.socket,agentDir:options.agentDir,includeWorkers:options.includeWorkers},{prune:!1,...options.timeoutMs!==void 0?{timeoutMs:options.timeoutMs}:{}}),...located}}async function unaddressableStatus(dir){let paths=hostDaemonDirectoryPaths(dir),generations=await readGenerationRows(paths,{includeDead:!0}),claims=await readClaimRows(paths,generations);return{reachable:!1,pid:null,instanceId:null,generation:null,engineVersion:null,capabilities:[],launchProfile:null,sessions:{total:0,interactive:0,worker:0,retained:0,foreign_attached:0,foreign_retained:0},zombies:null,rss_mb:null,host_rss_mb:null,open_fds:null,memory_pressure:null,env_keys:[],generations,crashes:readHostCrashRecords(dir).length,shard:null,session_rows:[],claims_live:claims.filter(claim=>claim.live).length,claims:[]}}var HOST_EXIT_OK=0,HOST_EXIT_ERROR=1,HOST_EXIT_USAGE=2,HOST_EXIT_REFUSED=3,HOST_EXIT_FALLBACK=4,PROBE_TIMEOUT_MS=1e4;async function runHostRequest(request){switch(request.action){case"ensure":return ensureOutcome(request.target,request.spec,request.policy);case"status":return request.all===!0?statusAllOutcome(request.target,request.includeWorkers):statusOutcome(request.target,request.includeWorkers);case"stop":return stopOutcome(request.target,request.drain,request.force);case"handoff":return handoffOutcome(request.target,request.spec);case"shard_path":return shardPathOutcome(request.kind,request.owner,request.root);case"gc":return{exitCode:HOST_EXIT_OK,payload:{...await gcHostEndpoints(request.agentDir)}};default:return assertNever(request)}}async function ensureOutcome(target,spec,policy){let before=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS);if(policy==="fallback"){let decision=decideHostAction(decisionClient(),before,"fallback");if(decision.action==="fallback")return refusal("fallback",before,{reason:decision.reason,socket:target.socket})}let ensured;try{ensured=await ensureHost({socket:target.socket,agentDir:target.agentDir,hostArgs:spec.hostArgs,env:daemonEnvOverrides(process.env,spec.env),policy:spec.policy,upgrade:policy==="upgrade"?"if-engine-differs":"never"})}catch(error){if(!(error instanceof HostEnsureRefusedError))throw error;return refusal("refuse",before,{reason:error.reason,socket:target.socket})}let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS).finally(ensured.release);return ensured.reused||await recordEnvScope(target,spec),{exitCode:HOST_EXIT_OK,payload:{action:ensureAction(ensured.reused,before,host),...identityPayload(target.socket,ensured.pid,host),reused:ensured.reused}}}function ensureAction(reused,before,after){return reused?"reuse":before!==void 0&&before.instanceId!==after?.instanceId?"handoff":"start"}async function statusOutcome(target,includeWorkers){let status=await readHostStatus({socket:target.socket,agentDir:target.agentDir,includeWorkers});return{exitCode:status.reachable?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{...status}}}async function statusAllOutcome(target,includeWorkers){let endpoints=await readAllHostStatus({agentDir:target.agentDir,includeWorkers});return{exitCode:endpoints.some(endpoint=>endpoint.reachable)?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{endpoints}}}function shardPathOutcome(kind,owner,root){let key=shardKey(kind,owner);return{exitCode:HOST_EXIT_OK,payload:{kind,key,socket:shardSocketPathForKey(root,kind,key)}}}async function stopOutcome(target,drain,force){let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS),sessions=await readSessionCounts(target.socket,!0),occupied=sessions.foreign_attached+sessions.foreign_retained>0;if(!drain&&!force&&occupied)return refusal("refuse",host,{reason:"sessions_live",socket:target.socket,sessions});let result=await stopHost({socket:target.socket,agentDir:target.agentDir,drain,force});return result.action==="refuse"?refusal("refuse",host,{reason:result.reason,socket:target.socket,sessions}):{exitCode:HOST_EXIT_OK,payload:{action:result.action,socket:target.socket,pid:result.pid,sessions}}}async function handoffOutcome(target,spec){let before=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS),result=await handoffHost({socket:target.socket,agentDir:target.agentDir,hostArgs:spec.hostArgs,env:daemonEnvOverrides(process.env,spec.env),policy:spec.policy});if(result.action==="refuse")return refusal("refuse",before,{reason:upgradeRefusal(result.reason),socket:target.socket,detail:result.reason,upgradeable:result.upgradeable});await recordEnvScope(target,spec);let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS);return{exitCode:HOST_EXIT_OK,payload:{action:"handoff",...identityPayload(target.socket,result.pid,host),reused:!1}}}function upgradeRefusal(reason){return reason==="handoff_unsupported"?"upgrade_unsupported":reason}function identityPayload(socket,pid,host){return{socket,pid,instanceId:host?.instanceId??null,generation:host?.generation??null,engineVersion:host?.engineVersion??null,engineOrdinal:host?.engineOrdinal??null,capabilities:host?.capabilities??[],launchProfileId:host?.launch_profile?.profile_id??null,upgradeable:decideHostAction(decisionClient(),host,"upgrade").upgradeable}}function refusal(kind,host,body){return{exitCode:kind==="refuse"?HOST_EXIT_REFUSED:HOST_EXIT_FALLBACK,payload:{action:kind,...body,host:hostSummary(host)}}}async function recordEnvScope(target,spec){let paths=createHostDaemonPaths({socket:target.socket,agentDir:target.agentDir});await writeDaemonEnvKeys(paths,daemonEnvKeys(process.env,spec.env))}function decisionClient(){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:REQUIRED_HOST_CAPABILITIES,identity:engineBuildIdentity(),startedByUs:!1,platform:process.platform}}function assertNever(value){throw new Error(`unreachable host request: ${JSON.stringify(value)}`)}var SUBCOMMANDS=["ensure","status","stop","handoff","shard-path","gc"],POLICIES=["upgrade","fallback","never"],USAGE=`usage: ${APP_NAME} host <ensure|status|stop|handoff|shard-path|gc> [options]
|
|
2
|
+
import{HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,acquireHostEnsureLock,daemonEnvKeys,daemonEnvOverrides,decideHostAction,ensureHost,handoffHost,observeProtocolInfo,probeProtocolInfo,readDaemonEnvKeys,requestOnSocket,stopHost,writeDaemonEnvKeys}from"./chunk-LM2UMEX6.js";import{HOST_DAEMON_LAYOUT,OBSERVE_REQUEST_FIELD,ProcessIdentityUnreadableError,claimOwnerIsLive,createHostDaemonPaths,generationPaths,hostDaemonDirectoryPaths,parseDaemonPidFile,parseJson,parseShardSocket,processMatchesPidFile,pruneDeadGenerations,readFileOrUndefined,readGenerationRows,readHostCrashRecords,readHostProcessMetrics,readSessionPathClaims,readSocketSecret,resolveSocketTransportAddress,shardKey,shardSocketPathForKey,socketNamesDirectory,socketSecretPath}from"./chunk-Y4CH7LYI.js";import{engineBuildIdentity}from"./chunk-E5F5SVZF.js";import{isSessionRuntimeKind}from"./chunk-L4OOEWAT.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-PBWQK23Z.js";import{writeSync}from"node:fs";import{join as join4,resolve as resolve2}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{lstat as lstat2,rm}from"node:fs/promises";import{dirname as dirname3,join as join3}from"node:path";import{readdir}from"node:fs/promises";import{basename,join}from"node:path";var ENDPOINT_DIRECTORY_NAME=/^[0-9a-f]{16}$/;async function listHostEndpoints(agentDir){let flatDir=join(agentDir,"rpc-host-daemon");if(parseJson(await readFileOrUndefined(join(flatDir,"layout.json")).catch(()=>{}))?.layout!==HOST_DAEMON_LAYOUT)return[];let dirs=(await readdir(flatDir,{withFileTypes:!0}).catch(()=>[])).filter(entry=>entry.isDirectory()&&ENDPOINT_DIRECTORY_NAME.test(entry.name)).map(entry=>join(flatDir,entry.name)).sort(),endpoints=[];for(let dir of dirs)endpoints.push(await identifyEndpoint(dir));return endpoints}async function identifyEndpoint(dir){let paths=hostDaemonDirectoryPaths(dir),named=await socketNamedBy(paths.endpointFile,dir);if(named!==void 0)return{socket:named,dir,identity:"endpoint"};let booted=await socketNamedBy(paths.settingsFile,dir);if(booted!==void 0)return{socket:booted,dir,identity:"settings"};let generations=await readdir(paths.generationsDir).catch(()=>[]);for(let instanceId of generations.sort()){let recorded=await socketNamedBy(join(paths.generationsDir,instanceId,"settings.json"),dir);if(recorded!==void 0)return{socket:recorded,dir,identity:"generation-settings"}}return{socket:null,dir,identity:"unknown"}}async function socketNamedBy(file,dir){let socket=parseJson(await readFileOrUndefined(file).catch(()=>{}))?.socket;if(!(typeof socket!="string"||socket===""))return socketNamesDirectory(socket,basename(dir))?socket:void 0}import{lstat,readdir as readdir2}from"node:fs/promises";import{createConnection}from"node:net";import{basename as basename2,dirname as dirname2,join as join2}from"node:path";var SOCKET_PROBE_TIMEOUT_MS=2e3;async function endpointInUse(paths,socket){if(await anyGenerationLive(paths))return{inUse:"live_generation"};for(let claim of await readSessionPathClaims(paths.reservationsDir))if(await claimOwnerIsLive(claim.owner))return{inUse:"live_claim"};let silence=await socketSilence(socket);if(silence===void 0)return{inUse:"reachable"};let successors=(await socketSiblings(socket)).filter(name=>name.startsWith(`${basename2(socket)}.next-`));for(let successor of successors)if(await socketSilence(join2(dirname2(socket),successor))===void 0)return{inUse:"reachable"};return{inUse:void 0,silence}}async function socketSiblings(socket){let name=basename2(socket);return(await readdir2(dirname2(socket)).catch(()=>[])).filter(entry=>entry.startsWith(`${name}.next-`)||entry.startsWith(`${name}.shield-`))}async function anyGenerationLive(paths){for(let instanceId of await readdir2(paths.generationsDir).catch(()=>[])){let record=generationRecord(await readFileOrUndefined(generationPaths(paths,instanceId).pidFile));if(record!==void 0&&await recordIsLive(record))return!0}return!1}function generationRecord(text){if(text===void 0)return;let record=parseDaemonPidFile(text);if(record!==void 0)return record;let pid=parseJson(text)?.pid;return typeof pid=="number"&&Number.isInteger(pid)&&pid>0?{pid,processStartTime:null}:void 0}async function recordIsLive(record){try{return await processMatchesPidFile(record)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!0;throw error}}async function socketSilence(socket){let secret;return process.platform==="win32"&&(secret=await readSocketSecret(socketSecretPath(socket)).catch(()=>{}),secret===void 0)?"socket_absent":new Promise(resolveProbe=>{let connection=createConnection(resolveSocketTransportAddress(socket,process.platform,secret)),finish=value=>{clearTimeout(timeout),connection.destroy(),resolveProbe(value)},timeout=setTimeout(()=>finish(void 0),SOCKET_PROBE_TIMEOUT_MS);connection.once("connect",()=>finish(void 0)),connection.once("error",error=>{error.code==="ECONNREFUSED"?refusedBySocket(socket).then(finish):error.code==="ENOENT"?finish("socket_absent"):finish(void 0)})})}async function refusedBySocket(socket){if(process.platform==="win32"||socket.startsWith("\0"))return"socket_refused";try{return(await lstat(socket)).isSocket()?"socket_refused":void 0}catch(error){return error instanceof Error&&"code"in error&&error.code==="ENOENT"?"socket_absent":void 0}}var GC_LOCK_WAIT_MS=2e3;async function gcHostEndpoints(agentDir,options={}){let removed=[],kept=[],legacy=await legacyFlatDirectory(agentDir);legacy!==void 0&&kept.push({socket:null,dir:legacy,reason:"legacy_layout"});for(let endpoint of await listHostEndpoints(agentDir)){if(endpoint.socket===null){kept.push({socket:null,dir:endpoint.dir,reason:"unknown_identity"});continue}let entry={socket:endpoint.socket,dir:endpoint.dir};try{let outcome=await gcEndpoint(endpoint.socket,endpoint.dir,options);outcome.removed?outcome.skipped.length===0?removed.push({...entry,reason:outcome.reason}):removed.push({...entry,reason:outcome.reason,skipped:outcome.skipped}):kept.push({...entry,reason:outcome.reason})}catch(error){kept.push({...entry,reason:"failed",error:error instanceof Error?error.message:String(error)})}}return{removed,kept}}async function gcEndpoint(socket,dir,options){let release=await acquireEnsureLock(socket);if(release===void 0)return{removed:!1,reason:"locked"};try{await options._test?.afterLockAcquired?.(socket);let evidence=await endpointInUse(hostDaemonDirectoryPaths(dir),socket);if(evidence.inUse!==void 0)return{removed:!1,reason:evidence.inUse};let skipped=await removeEndpoint(socket,dir);return{removed:!0,reason:evidence.silence,skipped}}finally{await release()}}async function removeEndpoint(socket,dir){let skipped=[];for(let sibling of await socketSiblings(socket)){let path=join3(dirname3(socket),sibling),entry=await lstat2(path).catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});entry?.isDirectory()?skipped.push({path,type:"directory"}):entry!==void 0&&await rm(path,{force:!0})}return await rm(socket,{force:!0}),await rm(dir,{recursive:!0,force:!0}),skipped}async function acquireEnsureLock(socket){return acquireHostEnsureLock(socket,GC_LOCK_WAIT_MS).catch(()=>{})}async function legacyFlatDirectory(agentDir){let flatDir=join3(agentDir,"rpc-host-daemon");return parseJson(await readFileOrUndefined(join3(flatDir,"layout.json")).catch(()=>{}))?.layout===HOST_DAEMON_LAYOUT?void 0:await readFileOrUndefined(join3(flatDir,"host.pid")).catch(()=>{})!==void 0?flatDir:void 0}function parseSessionRows(reply){return!isRecord2(reply)||!Array.isArray(reply.sessions)?[]:reply.sessions.flatMap(entry=>isRecord2(entry)?[{id:typeof entry.sessionId=="string"?entry.sessionId:"",kind:typeof entry.kind=="string"?entry.kind:"interactive",session_path:typeof entry.sessionPath=="string"?entry.sessionPath:null,attachments:typeof entry.attachments=="number"?entry.attachments:0,context:stringRecord(entry.context)}]:[])}async function readClaimRows(paths,generations){let rows=[];for(let claim of await readSessionPathClaims(paths.reservationsDir)){let owner=claim.owner;rows.push({session_path:owner.sessionPath,owner_pid:owner.pid,instance_id:owner.instanceId,generation:generations.find(row=>row.instanceId===owner.instanceId)?.generation??null,attached:owner.attached??null,live:await claimOwnerIsLive(owner)})}return rows.sort((left,right)=>left.session_path.localeCompare(right.session_path))}function stringRecord(value){return isRecord2(value)?Object.fromEntries(Object.entries(value).filter(entry=>typeof entry[1]=="string")):null}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var STATUS_PROBE_TIMEOUT_MS=1e4;async function readHostStatus(options,read={}){let paths=createHostDaemonPaths({socket:options.socket,...options.agentDir?{agentDir:options.agentDir}:{}}),prune=read.prune!==!1,includeWorkers=options.includeWorkers===!0,timeoutMs=read.timeoutMs??STATUS_PROBE_TIMEOUT_MS,host=await observeProtocolInfo(options.socket,timeoutMs);prune&&await pruneDeadGenerations(paths);let generations=await readGenerationRows(paths,{includeDead:!prune}),current=generations.find(row=>row.current&&row.alive),metrics=current?await readHostProcessMetrics(current.pid):UNOBSERVED_METRICS,listing=host===void 0?[]:await readSessionListing(options.socket,includeWorkers,timeoutMs),claims=await readClaimRows(paths,generations);return{reachable:host!==void 0,socket:options.socket,pid:current?.pid??null,instanceId:host?.instanceId??current?.instanceId??null,generation:host?.generation??current?.generation??null,engineVersion:host?.engineVersion??current?.engineVersion??null,capabilities:host?.capabilities??[],launchProfile:host?.launch_profile??null,sessions:countSessions(listing),zombies:metrics.zombies,rss_mb:metrics.rss_mb,host_rss_mb:metrics.host_rss_mb,open_fds:metrics.open_fds,memory_pressure:host?.memory_pressure??null,env_keys:await readDaemonEnvKeys(paths),generations,crashes:readHostCrashRecords(paths.dir).length,shard:parseShardSocket(options.socket),session_rows:includeWorkers?listing:[],claims_live:claims.filter(claim=>claim.live).length,claims:includeWorkers?claims:[]}}async function readSessionCounts(socket,includeWorkers){return countSessions(await readSessionListing(socket,includeWorkers))}async function readSessionListing(socket,includeWorkers,timeoutMs=STATUS_PROBE_TIMEOUT_MS){let reply=await requestOnSocket(socket,{type:"list_sessions",[OBSERVE_REQUEST_FIELD]:!0,...includeWorkers?{include_workers:!0}:{}},timeoutMs);return parseSessionRows(reply)}function countSessions(rows){let attached=rows.filter(row=>row.attachments>0).length,retained=rows.length-attached;return{total:rows.length,interactive:rows.filter(row=>row.kind!=="worker").length,worker:rows.filter(row=>row.kind==="worker").length,retained,foreign_attached:attached,foreign_retained:retained}}function hostSummary(host){return host===void 0?null:{protocolVersion:host.protocolVersion,serverVersion:host.serverVersion,capabilities:host.capabilities,instanceId:host.instanceId??null,generation:host.generation??null,engineVersion:host.engineVersion??null,launchProfileId:host.launch_profile?.profile_id??null}}var UNOBSERVED_METRICS={rss_mb:null,host_rss_mb:null,open_fds:null,zombies:null};var STATUS_ALL_MAX_IN_FLIGHT=64;async function readAllHostStatus(options){let endpoints=await listHostEndpoints(options.agentDir),read=options._test?.readEndpoint??(endpoint=>endpointStatus(endpoint,options)),rows=new Array(endpoints.length),next=0,worker=async()=>{for(let index=next++;index<endpoints.length;index=next++){let endpoint=endpoints[index];endpoint!==void 0&&(rows[index]=await read(endpoint))}};return await Promise.all(Array.from({length:Math.min(STATUS_ALL_MAX_IN_FLIGHT,endpoints.length)},worker)),rows}async function endpointStatus(endpoint,options){let located={dir:endpoint.dir,identity:endpoint.identity};return endpoint.socket===null?{...await unaddressableStatus(endpoint.dir),socket:null,...located}:{...await readHostStatus({socket:endpoint.socket,agentDir:options.agentDir,includeWorkers:options.includeWorkers},{prune:!1,...options.timeoutMs!==void 0?{timeoutMs:options.timeoutMs}:{}}),...located}}async function unaddressableStatus(dir){let paths=hostDaemonDirectoryPaths(dir),generations=await readGenerationRows(paths,{includeDead:!0}),claims=await readClaimRows(paths,generations);return{reachable:!1,pid:null,instanceId:null,generation:null,engineVersion:null,capabilities:[],launchProfile:null,sessions:{total:0,interactive:0,worker:0,retained:0,foreign_attached:0,foreign_retained:0},zombies:null,rss_mb:null,host_rss_mb:null,open_fds:null,memory_pressure:null,env_keys:[],generations,crashes:readHostCrashRecords(dir).length,shard:null,session_rows:[],claims_live:claims.filter(claim=>claim.live).length,claims:[]}}var HOST_EXIT_OK=0,HOST_EXIT_ERROR=1,HOST_EXIT_USAGE=2,HOST_EXIT_REFUSED=3,HOST_EXIT_FALLBACK=4,PROBE_TIMEOUT_MS=1e4;async function runHostRequest(request){switch(request.action){case"ensure":return ensureOutcome(request.target,request.spec,request.policy);case"status":return request.all===!0?statusAllOutcome(request.target,request.includeWorkers):statusOutcome(request.target,request.includeWorkers);case"stop":return stopOutcome(request.target,request.drain,request.force);case"handoff":return handoffOutcome(request.target,request.spec);case"shard_path":return shardPathOutcome(request.kind,request.owner,request.root);case"gc":return{exitCode:HOST_EXIT_OK,payload:{...await gcHostEndpoints(request.agentDir)}};default:return assertNever(request)}}async function ensureOutcome(target,spec,policy){let before=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS);if(policy==="fallback"){let decision=decideHostAction(decisionClient(),before,"fallback");if(decision.action==="fallback")return refusal("fallback",before,{reason:decision.reason,socket:target.socket})}let ensured;try{ensured=await ensureHost({socket:target.socket,agentDir:target.agentDir,hostArgs:spec.hostArgs,env:daemonEnvOverrides(process.env,spec.env),policy:spec.policy,upgrade:policy==="upgrade"?"if-engine-differs":"never"})}catch(error){if(!(error instanceof HostEnsureRefusedError))throw error;return refusal("refuse",before,{reason:error.reason,socket:target.socket})}let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS).finally(ensured.release);return ensured.reused||await recordEnvScope(target,spec),{exitCode:HOST_EXIT_OK,payload:{action:ensureAction(ensured.reused,before,host),...identityPayload(target.socket,ensured.pid,host),reused:ensured.reused}}}function ensureAction(reused,before,after){return reused?"reuse":before!==void 0&&before.instanceId!==after?.instanceId?"handoff":"start"}async function statusOutcome(target,includeWorkers){let status=await readHostStatus({socket:target.socket,agentDir:target.agentDir,includeWorkers});return{exitCode:status.reachable?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{...status}}}async function statusAllOutcome(target,includeWorkers){let endpoints=await readAllHostStatus({agentDir:target.agentDir,includeWorkers});return{exitCode:endpoints.some(endpoint=>endpoint.reachable)?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{endpoints}}}function shardPathOutcome(kind,owner,root){let key=shardKey(kind,owner);return{exitCode:HOST_EXIT_OK,payload:{kind,key,socket:shardSocketPathForKey(root,kind,key)}}}async function stopOutcome(target,drain,force){let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS),sessions=await readSessionCounts(target.socket,!0),occupied=sessions.foreign_attached+sessions.foreign_retained>0;if(!drain&&!force&&occupied)return refusal("refuse",host,{reason:"sessions_live",socket:target.socket,sessions});let result=await stopHost({socket:target.socket,agentDir:target.agentDir,drain,force});return result.action==="refuse"?refusal("refuse",host,{reason:result.reason,socket:target.socket,sessions}):{exitCode:HOST_EXIT_OK,payload:{action:result.action,socket:target.socket,pid:result.pid,sessions}}}async function handoffOutcome(target,spec){let before=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS),result=await handoffHost({socket:target.socket,agentDir:target.agentDir,hostArgs:spec.hostArgs,env:daemonEnvOverrides(process.env,spec.env),policy:spec.policy});if(result.action==="refuse")return refusal("refuse",before,{reason:upgradeRefusal(result.reason),socket:target.socket,detail:result.reason,upgradeable:result.upgradeable});await recordEnvScope(target,spec);let host=await probeProtocolInfo(target.socket,PROBE_TIMEOUT_MS);return{exitCode:HOST_EXIT_OK,payload:{action:"handoff",...identityPayload(target.socket,result.pid,host),reused:!1}}}function upgradeRefusal(reason){return reason==="handoff_unsupported"?"upgrade_unsupported":reason}function identityPayload(socket,pid,host){return{socket,pid,instanceId:host?.instanceId??null,generation:host?.generation??null,engineVersion:host?.engineVersion??null,engineOrdinal:host?.engineOrdinal??null,capabilities:host?.capabilities??[],launchProfileId:host?.launch_profile?.profile_id??null,upgradeable:decideHostAction(decisionClient(),host,"upgrade").upgradeable}}function refusal(kind,host,body){return{exitCode:kind==="refuse"?HOST_EXIT_REFUSED:HOST_EXIT_FALLBACK,payload:{action:kind,...body,host:hostSummary(host)}}}async function recordEnvScope(target,spec){let paths=createHostDaemonPaths({socket:target.socket,agentDir:target.agentDir});await writeDaemonEnvKeys(paths,daemonEnvKeys(process.env,spec.env))}function decisionClient(){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:REQUIRED_HOST_CAPABILITIES,identity:engineBuildIdentity(),startedByUs:!1,platform:process.platform}}function assertNever(value){throw new Error(`unreachable host request: ${JSON.stringify(value)}`)}var SUBCOMMANDS=["ensure","status","stop","handoff","shard-path","gc"],POLICIES=["upgrade","fallback","never"],USAGE=`usage: ${APP_NAME} host <ensure|status|stop|handoff|shard-path|gc> [options]
|
|
3
3
|
|
|
4
4
|
ensure [--launch-spec <file>] [--policy upgrade|fallback|never] [--socket <path>]
|
|
5
5
|
status [--include-workers] [--all] [--socket <path>] (--all: every endpoint, ignores --socket)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{getApiKeyEnvVars}from"./chunk-
|
|
2
|
+
import{getApiKeyEnvVars}from"./chunk-TOCWAEQB.js";import{normalizeProviderId}from"./chunk-7X4ZMME4.js";var MAX_ENV_SLOT_INDEX=16;function primaryEnvVar(providerId){if(normalizeProviderId(providerId)==="anthropic-subscription")return"CLAUDE_CODE_OAUTH_TOKEN";let envVars=getApiKeyEnvVars(providerId);if(!(!envVars||envVars.length===0))return envVars.find(name=>name.endsWith("_API_KEY"))??envVars[0]}function discoverEnvSlots(providerId,env){let primary=primaryEnvVar(providerId);if(!primary)return[];let slots=[],base=env(primary);base&&slots.push({name:"env",envVarName:primary,key:base,source:"env"});for(let index=2;index<=MAX_ENV_SLOT_INDEX;index++){let envVarName=`${primary}_${index}`,value=env(envVarName);value&&slots.push({name:`env-${index}`,envVarName,key:value,source:"env"})}return slots}export{discoverEnvSlots};
|
|
@@ -20,9 +20,9 @@ ${source_default.bold("Commands:")}
|
|
|
20
20
|
Open TUI to enable/disable package resources (Tab switches scope)
|
|
21
21
|
${APP_NAME} models discover <provider>
|
|
22
22
|
Add an OpenAI-compatible provider's /models listing to models.json
|
|
23
|
-
${APP_NAME} app-server [--listen <url>]
|
|
23
|
+
${APP_NAME} app-server [--listen <url>] [--extension <path>]...
|
|
24
24
|
Serve agent sessions over the Codex app-server protocol
|
|
25
|
-
${APP_NAME} app-server daemon <start|stop|status|restart> [--listen <url>]
|
|
25
|
+
${APP_NAME} app-server daemon <start|stop|status|restart> [--listen <url>] [--extension <path>]...
|
|
26
26
|
Manage the app-server daemon
|
|
27
27
|
${APP_NAME} host <ensure|status|stop|handoff|shard-path|gc> [--launch-spec <file>]
|
|
28
28
|
Get, inspect or end the shared RPC daemon (one JSON line per call)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CUSTOM_UNSUPPORTED_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,RPC_CLIENT_CAPABILITIES_ENV,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY}from"./chunk-
|
|
2
|
+
import{CUSTOM_UNSUPPORTED_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,RPC_CLIENT_CAPABILITIES_ENV,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,hostLaunchProfile}from"./chunk-CEMOA3TF.js";import{DEFAULT_HOST_IDLE_EXIT_MS,HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,INTERNAL_SUPERVISOR_FLAG,MAX_SOCKET_PATH_BYTES,OBSERVE_REQUEST_FIELD,ProcessIdentityUnreadableError,canonicalEndpointPath,clearHostRegistration,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,ensureEndpointIdentity,generationBindPath,generationPaths,legacyHostIsLive,parseJson,processIsLive,processMatchesPidFile,provenOwner,readFileOrUndefined,readHostRegistration,readHostSettings,readProcessStartTime,readSocketSecret,releaseGeneration,resolveCliMainPath,resolveSocketTransportAddress,sameEndpoint,sendSocketHandshake,socketSecretPath,statSocketIdentity,waitForStartTime,writeGenerationRecord,writeHostRegistration,writeHostSettings,writeStateFile,writtenByThisProcess}from"./chunk-Y4CH7LYI.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,compareEngineOrdinal,engineBuildIdentity}from"./chunk-E5F5SVZF.js";import{ENV_AGENT_DIR,getAgentDir,isBunBinary}from"./chunk-PBWQK23Z.js";function parseHostProtocolInfo(data){if(!isRecord(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);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}}}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(!isRecord(value)||typeof value.profile_id!="string"||!isRecord(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 isRecord(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){super(`RPC socket ${socket} refused: ${reason} - ${refusalDetail(reason,host)}`),this.name="HostEnsureRefusedError",this.socket=socket,this.reason=reason}};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 on this endpoint; it is never signalled, 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 covers(client.launchProfile,host.launch_profile)?"profile_mismatch_attached":"profile_narrower_attached"}function covers(candidate,running){return candidate===void 0||running===void 0?!1:running.core.extensions.every(extension=>candidate.core.extensions.includes(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{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(!(!isRecord2(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(process.platform==="win32")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
4
|
`);if(newline===-1)return;let line=buffer.slice(0,newline);buffer=buffer.slice(newline+1);let answer=readAnswer(line);if(answer!==void 0)return finish(answer)}}),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(!(!isRecord2(parsed)||parsed.id!==PROBE_REQUEST_ID||parsed.success!==!0))return parsed.data??{}}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{existsSync}from"node:fs";import{basename,dirname,resolve}from"node:path";import{fileURLToPath}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...process.execArgv,sibling,...supervisorArgs]}:{command:process.execPath,args:[...process.execArgv,resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath(import.meta.url);if(basename(dirname(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve(dirname(modulePath),`host-lifecycle${extension}`);return existsSync(sibling)?sibling:void 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(!owner)return{action:"refuse",reason:"unknown_owner"};let host=await probeProtocolInfo(options.socket,options.timeoutMs??1e4);if(options.drain===!0)return!host?.capabilities.includes(GENERATION_HANDOFF_CAPABILITY)||process.platform==="win32"?{action:"refuse",reason:"drain_unsupported"}:(signalGeneration(owner.pid,"SIGUSR1"),{action:"drained",pid:owner.pid});let 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}}import{createHash}from"node:crypto";import{mkdir,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname as dirname2,join}from"node:path";import{stat}from"node:fs/promises";var LegacyLockArtifactError=class extends Error{constructor(lockPath){super(`Legacy lock directory is present at ${lockPath}`),this.code="ELEGACY_LOCK_ARTIFACT",this.name="LegacyLockArtifactError",this.lockPath=lockPath}},DEFAULT_RETRIES={retries:100,minTimeout:20,maxTimeout:100};async function openLockDatabase(lockPath){if(typeof globalThis.Bun<"u"){let{Database}=await import("bun:sqlite"),database2=new Database(lockPath,{create:!0});return{exec:sql=>database2.exec(sql),close:()=>database2.close(!1)}}let{DatabaseSync}=await import("node:sqlite"),database=new DatabaseSync(lockPath);return{exec:sql=>database.exec(sql),close:()=>database.close()}}async function acquireOwnershipSafeLock(lockPath,options={}){let retries=options.retries??DEFAULT_RETRIES,deadline=Date.now()+retries.retries*retries.maxTimeout;for(;;){await rejectLegacyDirectory(lockPath);let busyMs=Math.max(1,Math.min(retries.maxTimeout,deadline-Date.now())),database;try{database=await openLockDatabase(lockPath),database.exec(`PRAGMA busy_timeout = ${busyMs}; BEGIN EXCLUSIVE;`);let released=!1,held=database;return async()=>{if(!released){released=!0;try{held.exec("COMMIT;")}finally{held.close()}}}}catch(error){try{database?.close()}catch{}if(await rejectLegacyDirectory(lockPath),isBusy(error)&&Date.now()<deadline){await new Promise(resolve2=>setTimeout(resolve2,Math.min(retries.minTimeout,Math.max(1,deadline-Date.now()))));continue}throw error}}}async function rejectLegacyDirectory(lockPath){try{if((await stat(lockPath)).isDirectory())throw new LegacyLockArtifactError(lockPath)}catch(error){if(error instanceof LegacyLockArtifactError||error.code!=="ENOENT")throw error}}function isBusy(error){let message=error instanceof Error?error.message:String(error);return/busy|locked/i.test(message)||error?.code==="SQLITE_BUSY"}var LOCK_BUSY_WAIT_MS=100;function hostEnsureLockTarget(socket){return join(tmpdir(),"senpi-rpc-host-locks",createSocketLockName(socket))}async function acquireHostEnsureLock(socket,waitMs){let lockTarget=hostEnsureLockTarget(socket);return await mkdir(dirname2(lockTarget),{recursive:!0}),await writeFile(lockTarget,"",{flag:"a",mode:384}),acquireOwnershipSafeLock(`${lockTarget}.lock`,hostEnsureLockOptions(waitMs))}function hostEnsureLockOptions(waitMs){return{retries:{retries:Math.ceil(waitMs/LOCK_BUSY_WAIT_MS),minTimeout:20,maxTimeout:LOCK_BUSY_WAIT_MS}}}function createSocketLockName(socket){return createHash("sha256").update(socketLockAddress(socket),"utf8").digest("hex").slice(0,32)}function socketLockAddress(socket){return process.platform==="win32"||socket.startsWith("\0")?resolveSocketTransportAddress(socket,process.platform):canonicalEndpointPath(socket)}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,rm,writeFile as writeFile2}from"node:fs/promises";import{join as join2}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"]);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 join2(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]}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})}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=randomUUID(),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?.(argv)??defaultHostLaunch(argv),stderr=await open(paths.stderrLog,"a",384),spawned=spawn(launch.command,[...launch.args],{detached:!0,windowsHide:!0,env:successorHostEnvironment({agentDir:options.agentDir,env:options.env,paths,generation,instanceId}),stdio:["ignore","ignore",stderr.fd]});if(await stderr.close(),child=spawned,exited=new Promise(resolve2=>spawned.once("exit",()=>resolve2())),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 answer=await awaitSuccessor(options,host,exited);if(!answer){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 writeHostRegistration(paths,registration),child.unref(),signalGeneration(owner.pid,"SIGUSR1"),{action:"handoff",pid:child.pid,socket:options.socket,generation:answer.generation??generation,instanceId:answer.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(resolve2=>{timer=setTimeout(()=>resolve2(!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 answer=await probeProtocolInfo(options.socket,2e3);if(answer&&answer.instanceId!==void 0&&answer.instanceId!==previous.instanceId)return answer;if(childGone)return;await delay(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 delay(ms){return new Promise(resolve2=>setTimeout(resolve2,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"}var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}import{spawn as spawn2}from"node:child_process";import{randomUUID as randomUUID2}from"node:crypto";import{mkdir as mkdir2,open as open2,readdir,readFile,rm as rm2,writeFile as writeFile3}from"node:fs/promises";import{tmpdir as tmpdir2}from"node:os";import{dirname as dirname3,join as join3}from"node:path";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 EXISTING_HOST_PROBE_TIMEOUT_MS=1e4,DEFAULT_READINESS_TIMEOUT_MS=1e4,DEFAULT_STOP_TIMEOUT_MS=1e4,SIGKILL_GRACE_MS=2e3,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 mkdir2(dirname3(lockTarget),{recursive:!0}),await writeFile3(lockTarget,"",{flag:"a",mode:384}),await reapOrphanedInternalHostDirs();let release=await acquireOwnershipSafeLock(`${lockTarget}.lock`,lockOptions);try{return await options._test?.afterLockAcquired?.(),await ensureHostLocked(paths,socket,options)}finally{await release()}}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),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}if(await legacyHostIsLive(paths,probe))throw new HostEnsureRefusedError(socket,"legacy_host",protocol);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 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 registersSocket(registered,socket){return registered===void 0?!1:registered.socket===void 0||sameEndpoint(registered.socket,socket)}async function startHost(paths,socket,options,generation=0){let testOptions=options._test,instanceId=randomUUID2();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 open2(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=spawn2(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,delay3(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 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),delay3(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 delay3(50)}return await resolvePidFileOwnership(pidFile,readStartTime)==="gone"}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}async function reapOrphanedInternalHostDirs(){try{let entries=await readdir(tmpdir2(),{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 readFile(join3(tmpdir2(),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 readdir(join3(tmpdir2(),entry.name))).length===1&&!await processMatchesPidFile({pid:owner.pid,processStartTime:owner.processStartTime}).catch(error=>{if(error instanceof ProcessIdentityUnreadableError)return!0;throw error})&&await rm2(join3(tmpdir2(),entry.name),{recursive:!0,force:!0})}catch{}}))}catch{}}async function appendStderr(paths,message){try{let stderr=(await readFile(paths.stderrLog,"utf8")).trim();return stderr?`${message}
|
|
5
5
|
${stderr}`:message}catch(error){if(isNodeErrorCode(error,"ENOENT"))return message;throw error}}function normalizeSocketPath(value){return value.startsWith("unix://")?value.slice(7):value}function delay3(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}function assertNever2(value){throw new Error(`unreachable host decision: ${JSON.stringify(value)}`)}export{daemonEnvOverrides,daemonEnvKeys,writeDaemonEnvKeys,readDaemonEnvKeys,parseHostProtocolInfo,HOST_PROTOCOL_VERSION,GENERATION_HANDOFF_CAPABILITY,REQUIRED_HOST_CAPABILITIES,HostEnsureRefusedError,decideHostAction,acquireOwnershipSafeLock,acquireHostEnsureLock,probeHost,probeProtocolInfo,observeProtocolInfo,requestOnSocket,PINNED_HOST_CLIENT_CAPABILITIES,stopHost,handoffHost,runAsHostGenerationProcess,ensureHost};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{getShellConfig}from"./chunk-ASAQQ6VM.js";import{getOverflowPatterns}from"./chunk-LEAJXPT2.js";import{normalizeProviderError}from"./chunk-BBK6SSYT.js";import{extract429RetryAfterMs}from"./chunk-BPX6QWPD.js";import{PROVIDER_NOT_CONFIGURED_PREFIX}from"./chunk-7X4ZMME4.js";import{spawn}from"child_process";function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{child.kill("SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(child.kill("SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){return env?.[name]||process.env[name]||void 0}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0)return;resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env){let resolvedValue=await resolveConfigValueUncached(config,env);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error"),status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}function rendezvousOrder(key,slots,hasher){return[...slots].map(slot=>({slot,score:hasher(`${key}\0${slot.name}`)})).sort((left,right)=>right.score>left.score?1:right.score<left.score?-1:0).map(({slot})=>slot)}var DEFAULT_SLOT_BLOCK_MS=6e4,MAX_SLOT_BLOCK_MS=2880*60*1e3;var COOLDOWN_BASE_MS=DEFAULT_SLOT_BLOCK_MS,COOLDOWN_CAP_MS=MAX_SLOT_BLOCK_MS,RETRY_SAME_MAX_ATTEMPTS=2;function rateLimitCooldown(failureCount,serverHintMs,policy={}){let cap=policy.capMs??COOLDOWN_CAP_MS,base=policy.baseMs??COOLDOWN_BASE_MS,backoff=Math.min(cap,base*2**Math.max(0,failureCount)),floored=serverHintMs===void 0?backoff:Math.max(backoff,serverHintMs);return{cooldownMs:Math.min(cap,floored),retryAfterWasCapped:floored>cap}}var INVALID_KEY_TEXT=/invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i,ACCOUNT_SCOPED_403_TEXT=/account|credential|token|api[ _-]?key|organization|subscription/i,RATE_LIMIT_TEXT=/rate[ _-]?limit|too many requests|resource_exhausted/i,BILLING_TEXT=/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i,OVERLOAD_TEXT=/overloaded/i,NETWORK_TEXT=/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i,WEBSOCKET_REQUEST_FAULT_TEXT=/websocket closed 100[89]\b/i,WEBSOCKET_TRANSPORT_FAULT_TEXT=/websocket (?:closed|error|connect timeout|liveness timeout)/i,FAIL_FAST_TEXT=/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i,ABORT_TEXT=/\baborted?\b/i;function isAbort(error,message){return error instanceof Error&&error.name==="AbortError"?!0:ABORT_TEXT.test(message)}function isOverflowText(text){return getOverflowPatterns().some(pattern=>pattern.test(text))}function classifyCredentialFailure(error,context={}){let normalized=normalizeProviderError(error),text=normalized.messageCarriesBody?normalized.message:`${normalized.message} ${normalized.body??""}`,status=normalized.status,failureCount=context.failureCount??0;if(isAbort(error,text))return{kind:"fail_request"};if(text.includes(PROVIDER_NOT_CONFIGURED_PREFIX))return{kind:"failover",block:{reason:"auth_error"}};if(status===401||INVALID_KEY_TEXT.test(text))return{kind:"failover",block:{reason:"auth_error"}};if(status===403)return ACCOUNT_SCOPED_403_TEXT.test(text)?{kind:"failover",block:{reason:"auth_error"}}:{kind:"fail_request"};if(status===402||BILLING_TEXT.test(text))return{kind:"failover",block:{reason:"account_disabled"}};if(status===429||RATE_LIMIT_TEXT.test(text)){let hint=extract429RetryAfterMs({status:status??429,bodyText:text});return{kind:"failover",block:{reason:"rate_limit",...rateLimitCooldown(failureCount,hint,{baseMs:context.cooldownBaseMs,capMs:context.cooldownCapMs})}}}return isOverflowText(text)||status===400||status===404||FAIL_FAST_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_REQUEST_FAULT_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_TRANSPORT_FAULT_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===529||OVERLOAD_TEXT.test(text)||status!==void 0&&status>=500&&status<600?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===408||NETWORK_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:{kind:"fail_request"}}var CredentialFailoverError=class extends Error{constructor(action,original,options={}){let detail=original instanceof Error?original.message:String(original);super(detail,{cause:original}),this.name="CredentialFailoverError",this.action=action,this.original=original,this.retryAt=options.retryAt}};function isAvailable(slot,now){return!(slot.blockReason==="auth_error"||slot.blockReason==="account_disabled"||slot.blockedUntil!==void 0&&slot.blockedUntil>now)}function soonestRetryAt(slots,now){let deadlines=slots.map(slot=>slot.blockedUntil).filter(value=>value!==void 0&&value>now);return deadlines.length===0?void 0:Math.min(...deadlines)}async function settle(stream){let iterator=stream[Symbol.asyncIterator]();try{await iterator.return?.(void 0)}catch{}}async function*runCredentialFailover(options){let now=options.now??Date.now,classify=options.classify??classifyCredentialFailure,attempted=new Set,retriesBySlot=new Map,lastError,lastOriginal,lastTerminalEvent,startAnnounced=!1;for(;;){let slots=await options.listSlots(),candidates=slots.filter(slot2=>!attempted.has(slot2.name)&&isAvailable(slot2,now()));if(candidates.length===0){if(lastTerminalEvent!==void 0){yield lastTerminalEvent;return}let retryAt=soonestRetryAt(slots,now());throw lastError!==void 0&&lastOriginal!==void 0?new CredentialFailoverError(lastError.action,lastOriginal,retryAt===void 0?{}:{retryAt}):new CredentialFailoverError({kind:"fail_request"},new Error("No credential slots available"),retryAt===void 0?{}:{retryAt})}let slot=options.select(candidates),committedOutput=!1,terminalEvent,attemptStream;try{attemptStream=await options.runAttempt(slot);for await(let event of attemptStream){let failure=options.errorFromEvent?.(event);if(failure!==void 0)throw terminalEvent=event,failure;if(options.isStreamStart?.(event)){if(startAnnounced)continue;startAnnounced=!0}committedOutput||=options.isCommittedOutput(event),yield event}await options.onSuccess?.(slot);return}catch(error){attemptStream&&await settle(attemptStream);let failureCount=(slot.failureCount??0)+(retriesBySlot.get(slot.name)??0),action=classify(error,{failureCount});if(lastOriginal=error,lastTerminalEvent=terminalEvent,action.kind==="retry_same"&&!committedOutput){let used=(retriesBySlot.get(slot.name)??0)+1;if(retriesBySlot.set(slot.name,used),used<action.maxAttempts)continue;if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}if(action.kind!=="failover"){if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}await options.persistBlock(slot,action.block),attempted.add(slot.name);let failure=new CredentialFailoverError(action,error);if(lastError=failure,await options.onRotate?.({slot,block:action.block,attempt:attempted.size,committedOutput}),committedOutput){if(terminalEvent!==void 0){yield terminalEvent;return}throw failure}}}}export{sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent,rendezvousOrder,classifyCredentialFailure,CredentialFailoverError,runCredentialFailover};
|
|
2
|
+
import{getShellConfig}from"./chunk-ASAQQ6VM.js";import{getOverflowPatterns}from"./chunk-TOCWAEQB.js";import{normalizeProviderError}from"./chunk-BBK6SSYT.js";import{extract429RetryAfterMs}from"./chunk-BPX6QWPD.js";import{PROVIDER_NOT_CONFIGURED_PREFIX}from"./chunk-7X4ZMME4.js";import{spawn}from"child_process";function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{child.kill("SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(child.kill("SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){return env?.[name]||process.env[name]||void 0}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0)return;resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env){let resolvedValue=await resolveConfigValueUncached(config,env);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error"),status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}function rendezvousOrder(key,slots,hasher){return[...slots].map(slot=>({slot,score:hasher(`${key}\0${slot.name}`)})).sort((left,right)=>right.score>left.score?1:right.score<left.score?-1:0).map(({slot})=>slot)}var DEFAULT_SLOT_BLOCK_MS=6e4,MAX_SLOT_BLOCK_MS=2880*60*1e3;var COOLDOWN_BASE_MS=DEFAULT_SLOT_BLOCK_MS,COOLDOWN_CAP_MS=MAX_SLOT_BLOCK_MS,RETRY_SAME_MAX_ATTEMPTS=2;function rateLimitCooldown(failureCount,serverHintMs,policy={}){let cap=policy.capMs??COOLDOWN_CAP_MS,base=policy.baseMs??COOLDOWN_BASE_MS,backoff=Math.min(cap,base*2**Math.max(0,failureCount)),floored=serverHintMs===void 0?backoff:Math.max(backoff,serverHintMs);return{cooldownMs:Math.min(cap,floored),retryAfterWasCapped:floored>cap}}var INVALID_KEY_TEXT=/invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i,ACCOUNT_SCOPED_403_TEXT=/account|credential|token|api[ _-]?key|organization|subscription/i,RATE_LIMIT_TEXT=/rate[ _-]?limit|too many requests|resource_exhausted/i,BILLING_TEXT=/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i,OVERLOAD_TEXT=/overloaded/i,NETWORK_TEXT=/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i,WEBSOCKET_REQUEST_FAULT_TEXT=/websocket closed 100[89]\b/i,WEBSOCKET_TRANSPORT_FAULT_TEXT=/websocket (?:closed|error|connect timeout|liveness timeout)/i,FAIL_FAST_TEXT=/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i,ABORT_TEXT=/\baborted?\b/i;function isAbort(error,message){return error instanceof Error&&error.name==="AbortError"?!0:ABORT_TEXT.test(message)}function isOverflowText(text){return getOverflowPatterns().some(pattern=>pattern.test(text))}function classifyCredentialFailure(error,context={}){let normalized=normalizeProviderError(error),text=normalized.messageCarriesBody?normalized.message:`${normalized.message} ${normalized.body??""}`,status=normalized.status,failureCount=context.failureCount??0;if(isAbort(error,text))return{kind:"fail_request"};if(text.includes(PROVIDER_NOT_CONFIGURED_PREFIX))return{kind:"failover",block:{reason:"auth_error"}};if(status===401||INVALID_KEY_TEXT.test(text))return{kind:"failover",block:{reason:"auth_error"}};if(status===403)return ACCOUNT_SCOPED_403_TEXT.test(text)?{kind:"failover",block:{reason:"auth_error"}}:{kind:"fail_request"};if(status===402||BILLING_TEXT.test(text))return{kind:"failover",block:{reason:"account_disabled"}};if(status===429||RATE_LIMIT_TEXT.test(text)){let hint=extract429RetryAfterMs({status:status??429,bodyText:text});return{kind:"failover",block:{reason:"rate_limit",...rateLimitCooldown(failureCount,hint,{baseMs:context.cooldownBaseMs,capMs:context.cooldownCapMs})}}}return isOverflowText(text)||status===400||status===404||FAIL_FAST_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_REQUEST_FAULT_TEXT.test(text)?{kind:"fail_request"}:WEBSOCKET_TRANSPORT_FAULT_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===529||OVERLOAD_TEXT.test(text)||status!==void 0&&status>=500&&status<600?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:status===408||NETWORK_TEXT.test(text)?{kind:"retry_same",maxAttempts:RETRY_SAME_MAX_ATTEMPTS}:{kind:"fail_request"}}var CredentialFailoverError=class extends Error{constructor(action,original,options={}){let detail=original instanceof Error?original.message:String(original);super(detail,{cause:original}),this.name="CredentialFailoverError",this.action=action,this.original=original,this.retryAt=options.retryAt}};function isAvailable(slot,now){return!(slot.blockReason==="auth_error"||slot.blockReason==="account_disabled"||slot.blockedUntil!==void 0&&slot.blockedUntil>now)}function soonestRetryAt(slots,now){let deadlines=slots.map(slot=>slot.blockedUntil).filter(value=>value!==void 0&&value>now);return deadlines.length===0?void 0:Math.min(...deadlines)}async function settle(stream){let iterator=stream[Symbol.asyncIterator]();try{await iterator.return?.(void 0)}catch{}}async function*runCredentialFailover(options){let now=options.now??Date.now,classify=options.classify??classifyCredentialFailure,attempted=new Set,retriesBySlot=new Map,lastError,lastOriginal,lastTerminalEvent,startAnnounced=!1;for(;;){let slots=await options.listSlots(),candidates=slots.filter(slot2=>!attempted.has(slot2.name)&&isAvailable(slot2,now()));if(candidates.length===0){if(lastTerminalEvent!==void 0){yield lastTerminalEvent;return}let retryAt=soonestRetryAt(slots,now());throw lastError!==void 0&&lastOriginal!==void 0?new CredentialFailoverError(lastError.action,lastOriginal,retryAt===void 0?{}:{retryAt}):new CredentialFailoverError({kind:"fail_request"},new Error("No credential slots available"),retryAt===void 0?{}:{retryAt})}let slot=options.select(candidates),committedOutput=!1,terminalEvent,attemptStream;try{attemptStream=await options.runAttempt(slot);for await(let event of attemptStream){let failure=options.errorFromEvent?.(event);if(failure!==void 0)throw terminalEvent=event,failure;if(options.isStreamStart?.(event)){if(startAnnounced)continue;startAnnounced=!0}committedOutput||=options.isCommittedOutput(event),yield event}await options.onSuccess?.(slot);return}catch(error){attemptStream&&await settle(attemptStream);let failureCount=(slot.failureCount??0)+(retriesBySlot.get(slot.name)??0),action=classify(error,{failureCount});if(lastOriginal=error,lastTerminalEvent=terminalEvent,action.kind==="retry_same"&&!committedOutput){let used=(retriesBySlot.get(slot.name)??0)+1;if(retriesBySlot.set(slot.name,used),used<action.maxAttempts)continue;if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}if(action.kind!=="failover"){if(terminalEvent!==void 0){yield terminalEvent;return}throw new CredentialFailoverError(action,error)}await options.persistBlock(slot,action.block),attempted.add(slot.name);let failure=new CredentialFailoverError(action,error);if(lastError=failure,await options.onRotate?.({slot,block:action.block,attempt:attempted.size,committedOutput}),committedOutput){if(terminalEvent!==void 0){yield terminalEvent;return}throw failure}}}}export{sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent,rendezvousOrder,classifyCredentialFailure,CredentialFailoverError,runCredentialFailover};
|
|
@@ -141,7 +141,7 @@ ${end.comment}`:end.comment}this.doc.range[2]=end.offset;break}default:this.erro
|
|
|
141
141
|
`)}function extractUserMessageText(msg){if(msg.role!=="user")return"";let content=msg.content;return typeof content=="string"?content.trim():content.filter(c=>c.type==="text").map(c=>c.text).join(`
|
|
142
142
|
`).trim()}function hasUserMessageImages(msg){return msg.role==="user"&&Array.isArray(msg.content)&&msg.content.some(item=>item.type==="image")}function buildCursorRootPromptContent(content){if(typeof content=="string"){let text=content.trim();return text?[{type:"text",text}]:[]}let parts=[];for(let item of content)if(item.type==="text"){let text=item.text.trim();text&&parts.push({type:"text",text})}else parts.push({type:"image",image:`data:${item.mimeType};base64,${item.data}`,mediaType:item.mimeType});return parts}function cursorUserContentKey(content){if(typeof content=="string")return content.trim();let hash=createHash("sha256");for(let item of content)hash.update(item.type),item.type==="text"?hash.update(item.text):(hash.update(item.mimeType),hash.update(item.data));return hash.digest("hex")}function buildCursorAssistantContent(msg){let content=[];for(let item of msg.content)item.type==="text"?item.text&&content.push({type:"text",text:item.text}):item.type==="toolCall"&&content.push({type:"tool-call",toolCallId:item.id,toolName:item.name,args:item.arguments});return content}function findLastUserMessageIndex(messages){for(let i=messages.length-1;i>=0;i--)if(messages[i].role==="user")return i;return-1}function buildRootPromptMessagesJson(messages,systemPromptIds,blobStore,activeUserMessageIndex=findLastUserMessageIndex(messages)){let entries=[...systemPromptIds],pushJson=obj=>{let bytes=new TextEncoder().encode(JSON.stringify(obj));entries.push(storeCursorBlob(blobStore,bytes))};for(let i=0;i<messages.length&&i!==activeUserMessageIndex;i++){let msg=messages[i];if(msg.role==="user"){let content=buildCursorRootPromptContent(msg.content);if(content.length===0)continue;pushJson({role:"user",content})}else if(msg.role==="assistant"){let content=buildCursorAssistantContent(msg);if(content.length===0)continue;pushJson({role:"assistant",content})}else msg.role==="toolResult"&&pushJson({role:"tool",id:msg.toolCallId,content:[{type:"tool-result",toolName:msg.toolName,toolCallId:msg.toolCallId,result:toolResultToText(msg),...msg.isError?{isError:!0}:{}}]})}return entries}function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;let prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function isJsonValue(value){if(value===null||typeof value=="string"||typeof value=="boolean")return!0;if(typeof value=="number")return Number.isFinite(value);if(Array.isArray(value))return value.every(isJsonValue);if(!isPlainRecord(value))return!1;for(let key in value)if(!isJsonValue(value[key]))return!1;return!0}function encodeCursorMcpArguments(toolCall){let encoded={};for(let name in toolCall.arguments){let value=toolCall.arguments[name];if(value!==void 0){if(!isJsonValue(value))throw new Error(`Cursor tool argument ${toolCall.name}.${name} is not JSON-serializable`);encoded[name]=toBinary(ValueSchema,fromJson(ValueSchema,value))}}return encoded}function createCursorMcpResult(result){return result.isError?create(McpToolResultSchema,{result:{case:"error",value:create(McpToolErrorSchema,{error:toolResultToText(result)})}}):create(McpToolResultSchema,{result:{case:"success",value:create(McpSuccessSchema,{content:result.content.map(item=>item.type==="text"?create(McpToolResultContentItemSchema,{content:{case:"text",value:create(McpTextContentSchema,{text:item.text})}}):create(McpToolResultContentItemSchema,{content:{case:"image",value:create(McpImageContentSchema,{data:Uint8Array.from(Uint8Array.from(atob(item.data),c=>c.charCodeAt(0))),mimeType:item.mimeType})}}))})}})}function createCursorToolCallStep(toolCall,result){let mcpCall=create(McpToolCallSchema,{args:create(McpArgsSchema,{name:toolCall.name,args:encodeCursorMcpArguments(toolCall),toolCallId:toolCall.id,providerIdentifier:"pi-agent",toolName:toolCall.name}),...result?{result:createCursorMcpResult(result)}:{}});return create(ConversationStepSchema,{message:{case:"toolCall",value:create(ToolCallSchema,{tool:{case:"mcpToolCall",value:mcpCall},toolCallId:toolCall.id})}})}function buildConversationTurns(messages,blobStore,activeUserMessageIndex=findLastUserMessageIndex(messages)){let turns=[],historyEnd=activeUserMessageIndex>=0?activeUserMessageIndex:messages.length,toolResults=new Map,pairedToolCallIds=new Set;for(let index=0;index<historyEnd;index++){let message=messages[index];if(message.role==="toolResult")toolResults.set(message.toolCallId,message);else if(message.role==="assistant")for(let item of message.content)item.type==="toolCall"&&pairedToolCallIds.add(item.id)}let i=0;for(;i<messages.length;){let msg=messages[i];if(msg.role!=="user"){i++;continue}if(i===activeUserMessageIndex)break;let userText=extractUserMessageText(msg);if(userText.length===0&&!hasUserMessageImages(msg)){i++;continue}let userMessage=createCursorUserMessage(msg.content,userText,deterministicUuid(`u:${turns.length}:${cursorUserContentKey(msg.content)}`)),userMessageBlobId=storeCursorBlob(blobStore,toBinary(UserMessageSchema,userMessage)),stepBlobIds=[];for(i++;i<messages.length&&messages[i].role!=="user";){let stepMsg=messages[i];if(stepMsg.role==="assistant")for(let item of stepMsg.content){let step;if(item.type==="text"){if(!item.text)continue;step=create(ConversationStepSchema,{message:{case:"assistantMessage",value:create(AssistantMessageSchema,{text:item.text})}})}else{if(item.type==="thinking")continue;if(item.type==="toolCall")step=createCursorToolCallStep(item,toolResults.get(item.id));else continue}stepBlobIds.push(storeCursorBlob(blobStore,toBinary(ConversationStepSchema,step)))}else if(stepMsg.role==="toolResult"&&!pairedToolCallIds.has(stepMsg.toolCallId)){let text=toolResultToText(stepMsg);if(text){let prefix=stepMsg.isError?"[Tool Error]":"[Tool Result]",step=create(ConversationStepSchema,{message:{case:"assistantMessage",value:create(AssistantMessageSchema,{text:`${prefix}
|
|
143
143
|
${text}`})}});stepBlobIds.push(storeCursorBlob(blobStore,toBinary(ConversationStepSchema,step)))}}i++}let agentTurn=create(AgentConversationTurnStructureSchema,{userMessage:userMessageBlobId,steps:stepBlobIds}),turn=create(ConversationTurnStructureSchema,{turn:{case:"agentConversationTurn",value:agentTurn}});turns.push(storeCursorBlob(blobStore,toBinary(ConversationTurnStructureSchema,turn)))}return turns}function createCursorUserMessage(content,text,messageId=randomUUID()){let images=typeof content=="string"?[]:extractImages(content);return create(UserMessageSchema,{text,messageId,...images.length>0?{selectedContext:create(SelectedContextSchema,{selectedImages:images})}:{}})}function extractImages(content){return content.filter(item=>item.type==="image").map(image=>create(SelectedImageSchema,{uuid:randomUUID(),mimeType:image.mimeType,dataOrBlobId:{case:"data",value:Uint8Array.from(atob(image.data),c=>c.charCodeAt(0))}}))}function measureCursorModelInputSerializedBytes(messages,activeUserMessageIndex=findLastUserMessageIndex(messages)){let blobStore=new Map,total=0;for(let blobId of buildRootPromptMessagesJson(messages,[],blobStore,activeUserMessageIndex))total+=readCursorBlob(blobStore,blobId).byteLength;return total}function measureCursorHistorySerializedBytes(messages,activeUserMessageIndex=findLastUserMessageIndex(messages)){return buildCursorHistoryWireBytesForTest(messages,activeUserMessageIndex).reduce((total,bytes)=>total+bytes.byteLength,0)}function buildCursorHistoryWireBytesForTest(messages,activeUserMessageIndex=findLastUserMessageIndex(messages)){let blobStore=new Map;return buildRootPromptMessagesJson(messages,[],blobStore,activeUserMessageIndex),buildConversationTurns(messages,blobStore,activeUserMessageIndex),[...blobStore.values()]}function piReadArgs(path,offset,limit){return limit!==void 0&&Math.floor(limit)<=0?null:{path,offset:offset!==void 0?Math.max(1,Math.floor(offset)):void 0,limit:limit!==void 0?Math.floor(limit):void 0}}function piLsPath(basePath){return basePath||"."}function piLimit(limit){return limit===void 0?void 0:Math.max(1,Math.floor(limit))}function piTimeout(timeout){return timeout!==void 0&&timeout>=0?timeout:void 0}function composeShellCommand(command,workingDirectory){return workingDirectory?`cd ${`'${workingDirectory.replace(/'/g,"'\\''")}'`} && { ${command}
|
|
144
|
-
}`:command}function omitUndefinedArgs(args){let out={};for(let key of Object.keys(args)){let value=args[key];value!==void 0&&(out[key]=value)}return out}var warmers=new Map;function registerPromptCacheWarmer(api,warmer){warmers.set(api,warmer)}function getPromptCacheWarmer(api){return warmers.get(api)}async function warmPromptCache(model,context,options={}){if(isOpenAIResponsesPromptCacheModel(model)){if((options.cacheRetention??model.cacheRetention)==="none")return{supported:!1};let warmer=getPromptCacheWarmer(model.api);if(warmer===void 0)return{supported:!1};let{usage,usageRaw:usageRaw2}=await warmer(model,context,options);return{supported:!0,usage:{input:usage.input,output:usage.output,cacheRead:usage.cacheRead,cacheWrite:usage.cacheWrite,cost:usage.cost},usageRaw:usageRaw2}}if(model.api!=="anthropic-messages"||!isAnthropicApiBaseUrl(model.baseUrl))return{supported:!1};let anthropicModel=model,[{default:Anthropic},{buildAnthropicWarmPromptCacheParams}]=await Promise.all([import("./sdk-2OVOFKEU.js"),import("./anthropic-messages-
|
|
144
|
+
}`:command}function omitUndefinedArgs(args){let out={};for(let key of Object.keys(args)){let value=args[key];value!==void 0&&(out[key]=value)}return out}var warmers=new Map;function registerPromptCacheWarmer(api,warmer){warmers.set(api,warmer)}function getPromptCacheWarmer(api){return warmers.get(api)}async function warmPromptCache(model,context,options={}){if(isOpenAIResponsesPromptCacheModel(model)){if((options.cacheRetention??model.cacheRetention)==="none")return{supported:!1};let warmer=getPromptCacheWarmer(model.api);if(warmer===void 0)return{supported:!1};let{usage,usageRaw:usageRaw2}=await warmer(model,context,options);return{supported:!0,usage:{input:usage.input,output:usage.output,cacheRead:usage.cacheRead,cacheWrite:usage.cacheWrite,cost:usage.cost},usageRaw:usageRaw2}}if(model.api!=="anthropic-messages"||!isAnthropicApiBaseUrl(model.baseUrl))return{supported:!1};let anthropicModel=model,[{default:Anthropic},{buildAnthropicWarmPromptCacheParams}]=await Promise.all([import("./sdk-2OVOFKEU.js"),import("./anthropic-messages-QOQJCY3F.js")]),headers=providerHeadersToRecord(options.headers),client=new Anthropic({apiKey:options.apiKey??null,baseURL:anthropicModel.baseUrl,dangerouslyAllowBrowser:!0,fetch:options.fetch,defaultHeaders:{...anthropicModel.headers,...headers}}),params=buildAnthropicWarmPromptCacheParams(anthropicModel,context,options),transformed=await options.onPayload?.(params,anthropicModel,{model:anthropicModel,headers});transformed!==void 0&&(params=transformed);let sanitized={...params};delete sanitized.stream,delete sanitized.thinking,delete sanitized.output_config,delete sanitized.tool_choice,sanitized.max_tokens=0;let usageRaw=(await client.beta.messages.create(sanitized,{maxRetries:0,...options.signal?{signal:options.signal}:{},...options.timeoutMs!==void 0?{timeout:options.timeoutMs}:{}})).usage;return{supported:!0,usage:{input:usageRaw.input_tokens,output:usageRaw.output_tokens,cacheRead:usageRaw.cache_read_input_tokens??0,cacheWrite:usageRaw.cache_creation_input_tokens??0},usageRaw}}var DEFAULT_API="faux",DEFAULT_PROVIDER="faux",DEFAULT_MODEL_ID="faux-1",DEFAULT_MODEL_NAME="Faux Model",DEFAULT_BASE_URL="http://localhost:0",DEFAULT_MIN_TOKEN_SIZE=3,DEFAULT_MAX_TOKEN_SIZE=5,DEFAULT_USAGE={input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}};function fauxText(text){return{type:"text",text}}function fauxThinking(thinking){return{type:"thinking",thinking}}function fauxToolCall(name,arguments_,options={}){return{type:"toolCall",id:options.id??randomId("tool"),name,arguments:arguments_}}function normalizeFauxAssistantContent(content){return typeof content=="string"?[fauxText(content)]:Array.isArray(content)?content:[content]}function fauxAssistantMessage(content,options={}){return{role:"assistant",content:normalizeFauxAssistantContent(content),api:DEFAULT_API,provider:DEFAULT_PROVIDER,model:DEFAULT_MODEL_ID,usage:DEFAULT_USAGE,stopReason:options.stopReason??"stop",...options.stopDetails===void 0?{}:{stopDetails:options.stopDetails},...options.deferred===void 0?{}:{deferred:options.deferred},...options.errorMessage===void 0?{}:{errorMessage:options.errorMessage},...options.abortSource===void 0?{}:{abortSource:options.abortSource},...options.responseId===void 0?{}:{responseId:options.responseId},timestamp:options.timestamp??Date.now()}}function estimateTokens(text){return Math.ceil(text.length/4)}function randomId(prefix){return`${prefix}:${Date.now()}:${Math.random().toString(36).slice(2)}`}function cloneStreamOptionsForLog(options){if(options)return{...options}}function cloneContextForLog(context){return{...context,messages:structuredClone(context.messages),tools:context.tools?.map(tool=>({name:tool.name,description:tool.description,parameters:structuredClone(tool.parameters),...tool.freeform?{freeform:structuredClone(tool.freeform)}:{}}))}}function contentToText(content){return typeof content=="string"?content:content.map(block=>block.type==="text"?block.text:`[image:${block.mimeType}:${block.data.length}]`).join(`
|
|
145
145
|
`)}function assistantContentToText(content){return content.map(block=>block.type==="text"?block.text:block.type==="thinking"?block.thinking:block.type==="providerNative"?"":`${block.name}:${JSON.stringify(block.arguments)}`).join(`
|
|
146
146
|
`)}function toolResultToText2(message){return[message.toolName,...message.content.map(block=>contentToText([block]))].join(`
|
|
147
147
|
`)}function messageToText(message){return message.role==="user"?contentToText(message.content):message.role==="assistant"?assistantContentToText(message.content):message.role==="configurationUpdate"?"":toolResultToText2(message)}function serializeContext(context){let parts=[];context.systemPrompt&&parts.push(`system:${context.systemPrompt}`);for(let message of context.messages)parts.push(`${message.role}:${messageToText(message)}`);return context.tools?.length&&parts.push(`tools:${JSON.stringify(context.tools)}`),parts.join(`
|