@code-yeongyu/senpi 2026.9.17-2 → 2026.9.17-4

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.
Files changed (177) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/bundle/chunks/{app-server-command-XSPV6BRF.js → app-server-command-RTISWAJY.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-PLUQUK3T.js → chunk-IM4UIHPI.js} +15 -15
  4. package/dist/bundle/chunks/{chunk-ESZHT7IE.js → chunk-IMTGM3RJ.js} +1 -1
  5. package/dist/bundle/chunks/chunk-OQGI752B.js +2 -0
  6. package/dist/bundle/chunks/{chunk-Z56RXBL6.js → chunk-QDR3GME3.js} +2 -2
  7. package/dist/bundle/chunks/{chunk-ZPO5FWHM.js → chunk-QILSJ5PQ.js} +2 -2
  8. package/dist/bundle/chunks/{chunk-IGKWKAMN.js → chunk-XHTF6VKZ.js} +4 -3
  9. package/dist/bundle/chunks/chunk-YD5QZXAK.js +8 -0
  10. package/dist/bundle/chunks/{cli-main-L7WQP5V6.js → cli-main-TO3O4TUE.js} +1 -1
  11. package/dist/bundle/chunks/{help-fast-path-O6MBSNMK.js → help-fast-path-LFGHCIWO.js} +1 -1
  12. package/dist/bundle/chunks/{host-lifecycle-AI7NH6ZO.js → host-lifecycle-YPVGQSGS.js} +1 -1
  13. package/dist/bundle/chunks/{interactive-host-runtime-DKJKH5DU.js → interactive-host-runtime-KZLF3AZD.js} +1 -1
  14. package/dist/bundle/chunks/{interactive-mode-FUW5LNKL.js → interactive-mode-ARGRH6QZ.js} +1 -1
  15. package/dist/bundle/chunks/multi-session-host-HIZZTSYU.js +20 -0
  16. package/dist/bundle/chunks/{package-manager-cli-J26DB6GM.js → package-manager-cli-544JIWNJ.js} +1 -1
  17. package/dist/bundle/chunks/rotation-stream-FSZVBG2T.js +2 -0
  18. package/dist/bundle/chunks/{rpc-mode-A3U63XX7.js → rpc-mode-S3IEBFEB.js} +1 -1
  19. package/dist/bundle/chunks/session-worker.js +71 -68
  20. package/dist/bundle/cli.js +1 -1
  21. package/dist/bundle/index.js +1 -1
  22. package/dist/bundle/rpc-entry.js +1 -1
  23. package/dist/cli/args.d.ts +19 -1
  24. package/dist/cli/args.d.ts.map +1 -1
  25. package/dist/cli/args.js +27 -1
  26. package/dist/cli/args.js.map +1 -1
  27. package/dist/core/agent-session-runtime.d.ts +14 -1
  28. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  29. package/dist/core/agent-session-runtime.js.map +1 -1
  30. package/dist/core/auth-storage.js +2 -2
  31. package/dist/core/auth-storage.js.map +1 -1
  32. package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
  33. package/dist/core/credential-pool/rotation-stream.js +10 -5
  34. package/dist/core/credential-pool/rotation-stream.js.map +1 -1
  35. package/dist/core/extensions/builtin/mcp/index.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/mcp/index.js +11 -0
  37. package/dist/core/extensions/builtin/mcp/index.js.map +1 -1
  38. package/dist/core/extensions/builtin/mcp/service.d.ts +9 -0
  39. package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
  40. package/dist/core/extensions/builtin/mcp/service.js +14 -1
  41. package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
  42. package/dist/core/extensions/builtin/mcp/startup-race.d.ts +20 -0
  43. package/dist/core/extensions/builtin/mcp/startup-race.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/mcp/startup-race.js +38 -1
  45. package/dist/core/extensions/builtin/mcp/startup-race.js.map +1 -1
  46. package/dist/core/extensions/index.d.ts +2 -2
  47. package/dist/core/extensions/index.d.ts.map +1 -1
  48. package/dist/core/extensions/index.js +1 -1
  49. package/dist/core/extensions/index.js.map +1 -1
  50. package/dist/core/extensions/loader.d.ts +9 -4
  51. package/dist/core/extensions/loader.d.ts.map +1 -1
  52. package/dist/core/extensions/loader.js +20 -9
  53. package/dist/core/extensions/loader.js.map +1 -1
  54. package/dist/core/extensions/types.d.ts +37 -0
  55. package/dist/core/extensions/types.d.ts.map +1 -1
  56. package/dist/core/extensions/types.js +8 -0
  57. package/dist/core/extensions/types.js.map +1 -1
  58. package/dist/core/footer-data-provider.d.ts +2 -1
  59. package/dist/core/footer-data-provider.d.ts.map +1 -1
  60. package/dist/core/footer-data-provider.js +21 -35
  61. package/dist/core/footer-data-provider.js.map +1 -1
  62. package/dist/core/model-registry.d.ts.map +1 -1
  63. package/dist/core/model-registry.js +3 -2
  64. package/dist/core/model-registry.js.map +1 -1
  65. package/dist/core/model-runtime.d.ts +4 -2
  66. package/dist/core/model-runtime.d.ts.map +1 -1
  67. package/dist/core/model-runtime.js +9 -5
  68. package/dist/core/model-runtime.js.map +1 -1
  69. package/dist/core/provider-api-key-auth.js +3 -3
  70. package/dist/core/provider-api-key-auth.js.map +1 -1
  71. package/dist/core/provider-composer.d.ts +9 -3
  72. package/dist/core/provider-composer.d.ts.map +1 -1
  73. package/dist/core/provider-composer.js +7 -4
  74. package/dist/core/provider-composer.js.map +1 -1
  75. package/dist/core/resolve-config-command.d.ts +10 -0
  76. package/dist/core/resolve-config-command.d.ts.map +1 -0
  77. package/dist/core/resolve-config-command.js +106 -0
  78. package/dist/core/resolve-config-command.js.map +1 -0
  79. package/dist/core/resolve-config-value.d.ts +4 -8
  80. package/dist/core/resolve-config-value.d.ts.map +1 -1
  81. package/dist/core/resolve-config-value.js +16 -105
  82. package/dist/core/resolve-config-value.js.map +1 -1
  83. package/dist/core/resource-loader.d.ts +7 -1
  84. package/dist/core/resource-loader.d.ts.map +1 -1
  85. package/dist/core/resource-loader.js +13 -9
  86. package/dist/core/resource-loader.js.map +1 -1
  87. package/dist/main.d.ts +5 -3
  88. package/dist/main.d.ts.map +1 -1
  89. package/dist/main.js +25 -11
  90. package/dist/main.js.map +1 -1
  91. package/dist/modes/rpc/child-reaper-syscalls.d.ts +18 -0
  92. package/dist/modes/rpc/child-reaper-syscalls.d.ts.map +1 -0
  93. package/dist/modes/rpc/child-reaper-syscalls.js +136 -0
  94. package/dist/modes/rpc/child-reaper-syscalls.js.map +1 -0
  95. package/dist/modes/rpc/child-reaper.d.ts +56 -0
  96. package/dist/modes/rpc/child-reaper.d.ts.map +1 -0
  97. package/dist/modes/rpc/child-reaper.js +140 -0
  98. package/dist/modes/rpc/child-reaper.js.map +1 -0
  99. package/dist/modes/rpc/custom-capability.d.ts +16 -0
  100. package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
  101. package/dist/modes/rpc/custom-capability.js +16 -0
  102. package/dist/modes/rpc/custom-capability.js.map +1 -1
  103. package/dist/modes/rpc/host-memory-sampler.d.ts +48 -0
  104. package/dist/modes/rpc/host-memory-sampler.d.ts.map +1 -0
  105. package/dist/modes/rpc/host-memory-sampler.js +72 -0
  106. package/dist/modes/rpc/host-memory-sampler.js.map +1 -0
  107. package/dist/modes/rpc/loop-lag-watchdog.d.ts +51 -0
  108. package/dist/modes/rpc/loop-lag-watchdog.d.ts.map +1 -0
  109. package/dist/modes/rpc/loop-lag-watchdog.js +78 -0
  110. package/dist/modes/rpc/loop-lag-watchdog.js.map +1 -0
  111. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  112. package/dist/modes/rpc/multi-session-host.js +34 -0
  113. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  114. package/dist/modes/rpc/rpc-client.d.ts +4 -2
  115. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  116. package/dist/modes/rpc/rpc-client.js +2 -1
  117. package/dist/modes/rpc/rpc-client.js.map +1 -1
  118. package/dist/modes/rpc/rpc-input-validation.d.ts +28 -0
  119. package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
  120. package/dist/modes/rpc/rpc-input-validation.js +63 -0
  121. package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
  122. package/dist/modes/rpc/rpc-mode.d.ts +18 -5
  123. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  124. package/dist/modes/rpc/rpc-mode.js +18 -5
  125. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  126. package/dist/modes/rpc/rpc-types.d.ts +79 -2
  127. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  128. package/dist/modes/rpc/rpc-types.js +6 -0
  129. package/dist/modes/rpc/rpc-types.js.map +1 -1
  130. package/dist/modes/rpc/session-attribution.d.ts +57 -0
  131. package/dist/modes/rpc/session-attribution.d.ts.map +1 -0
  132. package/dist/modes/rpc/session-attribution.js +132 -0
  133. package/dist/modes/rpc/session-attribution.js.map +1 -0
  134. package/dist/modes/rpc/session-binding.d.ts.map +1 -1
  135. package/dist/modes/rpc/session-binding.js +19 -8
  136. package/dist/modes/rpc/session-binding.js.map +1 -1
  137. package/dist/modes/rpc/session-command-router.d.ts +26 -3
  138. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  139. package/dist/modes/rpc/session-command-router.js +95 -19
  140. package/dist/modes/rpc/session-command-router.js.map +1 -1
  141. package/dist/modes/rpc/session-event-fanout.d.ts +2 -0
  142. package/dist/modes/rpc/session-event-fanout.d.ts.map +1 -1
  143. package/dist/modes/rpc/session-event-fanout.js +6 -0
  144. package/dist/modes/rpc/session-event-fanout.js.map +1 -1
  145. package/dist/modes/rpc/session-event-writer.d.ts +29 -0
  146. package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
  147. package/dist/modes/rpc/session-event-writer.js +57 -0
  148. package/dist/modes/rpc/session-event-writer.js.map +1 -1
  149. package/dist/modes/rpc/session-registry.d.ts +42 -9
  150. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  151. package/dist/modes/rpc/session-registry.js +49 -3
  152. package/dist/modes/rpc/session-registry.js.map +1 -1
  153. package/dist/modes/rpc/worker-session-registry.d.ts +2 -10
  154. package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -1
  155. package/dist/modes/rpc/worker-session-registry.js +6 -2
  156. package/dist/modes/rpc/worker-session-registry.js.map +1 -1
  157. package/docs/rpc.md +126 -20
  158. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
  159. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  160. package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/javascript.wasm +0 -0
  161. package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/provenance.json +22 -0
  162. package/node_modules/@earendil-works/pi-agent-core/assets/tree-sitter/web-tree-sitter.wasm +0 -0
  163. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  164. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  165. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  166. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  167. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  168. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
  169. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  170. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  171. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  172. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  173. package/package.json +7 -7
  174. package/dist/bundle/chunks/chunk-3Q5PD4KW.js +0 -8
  175. package/dist/bundle/chunks/chunk-YLYLKL7X.js +0 -2
  176. package/dist/bundle/chunks/multi-session-host-SMNZXFPT.js +0 -18
  177. package/dist/bundle/chunks/rotation-stream-SCVFIQ2O.js +0 -2
@@ -1,2 +0,0 @@
1
- import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
- import{getShellConfig}from"./chunk-KPSJKRO6.js";import{getOverflowPatterns}from"./chunk-WHS3V662.js";import{normalizeProviderError}from"./chunk-TEPMHNKQ.js";import{PROVIDER_NOT_CONFIGURED_PREFIX}from"./chunk-B2F5G2RY.js";import{extract429RetryAfterMs}from"./chunk-7DGJYBYJ.js";import{execSync,spawnSync}from"child_process";var commandResultCache=new Map,COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],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):executeCommandUncached(reference.config,env):resolveTemplate(reference.parts,env)}function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin",result=spawnSync(shell,commandFromStdin?args:[...args,command],{encoding:"utf-8",input:commandFromStdin?command:void 0,timeout:1e4,stdio:[commandFromStdin?"pipe":"ignore","pipe","ignore"],shell:!1,windowsHide:!0,...env===void 0?{}:{env:{...process.env,...env}}});return result.error?result.error.code==="ENOENT"?{executed:!1,value:void 0}:{executed:!0,value:void 0}:result.status!==0?{executed:!0,value:void 0}:{executed:!0,value:(result.stdout??"").trim()||void 0}}catch{return{executed:!1,value:void 0}}}function executeWithDefaultShell(command,env){try{return execSync(command,{encoding:"utf-8",timeout:1e4,stdio:["ignore","pipe","ignore"],...env===void 0?{}:{env:{...process.env,...env}}}).trim()||void 0}catch{return}}function sleepBlocking(milliseconds){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,milliseconds)}function executeCommandOnce(commandConfig,env){let command=commandConfig.slice(1);return process.platform==="win32"?(()=>{let configuredResult=executeWithConfiguredShell(command,env);return configuredResult.executed?configuredResult.value:executeWithDefaultShell(command,env)})():executeWithDefaultShell(command,env)}function executeCommandUncached(commandConfig,env){for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=executeCommandOnce(commandConfig,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&sleepBlocking(backoffMs)}}function executeCommand(commandConfig){if(commandResultCache.has(commandConfig))return commandResultCache.get(commandConfig);let result=executeCommandUncached(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env){let reference=parseConfigValueReference(config);return reference.type==="command"?executeCommandUncached(reference.config,env):resolveTemplate(reference.parts,env)}function resolveConfigValueOrThrow(config,description,env){let resolvedValue=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}`)}function resolveHeadersOrThrow(headers,description,env){if(!headers)return;let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}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 TURN_RETRY_SUPPRESSION_PREFIX="senpi:no-turn-retry:",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,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"}: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(`${options.suppressTurnRetry?TURN_RETRY_SUPPRESSION_PREFIX:""}${detail}`,{cause:original}),this.name="CredentialFailoverError",this.action=action,this.original=original,this.suppressTurnRetry=options.suppressTurnRetry,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;for(;;){let slots=await options.listSlots(),candidates=slots.filter(slot2=>!attempted.has(slot2.name)&&isAvailable(slot2,now()));if(candidates.length===0){let retryAt=soonestRetryAt(slots,now());throw lastError!==void 0&&lastOriginal!==void 0?new CredentialFailoverError(lastError.action,lastOriginal,{suppressTurnRetry:lastError.suppressTurnRetry,...retryAt===void 0?{}:{retryAt}}):new CredentialFailoverError({kind:"fail_request"},new Error("No credential slots available"),{suppressTurnRetry:!1,...retryAt===void 0?{}:{retryAt}})}let slot=options.select(candidates),committedOutput=!1,attemptStream;try{attemptStream=await options.runAttempt(slot);for await(let event of attemptStream){let failure=options.errorFromEvent?.(event);if(failure!==void 0)throw failure;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,action.kind==="retry_same"&&!committedOutput){let used=(retriesBySlot.get(slot.name)??0)+1;if(retriesBySlot.set(slot.name,used),used<action.maxAttempts)continue;throw new CredentialFailoverError(action,error,{suppressTurnRetry:!1})}if(action.kind!=="failover")throw new CredentialFailoverError(action,error,{suppressTurnRetry:committedOutput});await options.persistBlock(slot,action.block),attempted.add(slot.name);let failure=new CredentialFailoverError(action,error,{suppressTurnRetry:committedOutput});if(lastError=failure,await options.onRotate?.({slot,block:action.block,attempt:attempted.size,committedOutput}),committedOutput)throw failure}}}export{getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,TURN_RETRY_SUPPRESSION_PREFIX,rendezvousOrder,classifyCredentialFailure,CredentialFailoverError,runCredentialFailover};
@@ -1,18 +0,0 @@
1
- import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
- import{AgentSessionRuntime,ProviderScope,bindToProviderScope,createAgentSessionRuntime,runWithProviderScope}from"./chunk-PLUQUK3T.js";import"./chunk-OZINB5JY.js";import{SessionManager}from"./chunk-Z56RXBL6.js";import{PUBLIC_SOCKET_IDENTITY_FILE,SOCKET_SECRET_FILE_ENV,armHostWatchdog,authenticateSocket,ensureSocketSecret,parseIdleExitMs,readHostWatchdogConfigFromBrandEnv,readSocketIdentityFile,resolveSocketTransportAddress,shieldSocketDuringClose,socketSecretPath,statSocketIdentity,unlinkOwnedSocket,waitForSocketIdentityFile}from"./chunk-ESZHT7IE.js";import{RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OPEN_FAILED,RPC_ERROR_SESSION_CLOSING,RPC_ERROR_UNKNOWN_SESSION,SessionEventWriter,buildRpcSessionState,createRpcConnectionHandler,rpcCommandShapeError}from"./chunk-3Q5PD4KW.js";import{AUTO_TITLE_SESSIONS_CAPABILITY,MAX_RPC_LINE_CHARACTERS,MEDIA_PLACEHOLDERS_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,attachJsonlLineReader,parseClientCapabilities}from"./chunk-ZPO5FWHM.js";import"./chunk-B5GQRD32.js";import"./chunk-2WKZYYAR.js";import{flushRawStdout,takeOverStdout,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-Z7IRPMTE.js";import"./chunk-WINYWZE2.js";import"./chunk-4QHFEW27.js";import"./chunk-U7N2NMGI.js";import"./chunk-SGTGQNNP.js";import"./chunk-ZQNNIPKX.js";import"./chunk-EAAHPEGN.js";import"./chunk-YAMKKQV7.js";import"./chunk-ESYNSFBY.js";import"./chunk-YLYLKL7X.js";import"./chunk-34UXOYIZ.js";import{killTrackedDetachedChildren}from"./chunk-KPSJKRO6.js";import"./chunk-WHS3V662.js";import"./chunk-EN5HLCZK.js";import"./chunk-VYQOYVDV.js";import"./chunk-QL422WQ7.js";import"./chunk-K7HIYM6P.js";import"./chunk-HHQCPUMK.js";import"./chunk-ZG74NES2.js";import"./chunk-JKCCH24R.js";import"./chunk-T6SHTZ3M.js";import"./chunk-EFXPIEEC.js";import"./chunk-7DDKXS2Q.js";import"./chunk-U456RL4N.js";import"./chunk-TEPMHNKQ.js";import"./chunk-B2F5G2RY.js";import"./chunk-7DGJYBYJ.js";import"./chunk-L2ZPNLYD.js";import"./chunk-D2D2LIVO.js";import"./chunk-6R7UI4IY.js";import"./chunk-AHUSODXB.js";import"./chunk-PVXEILUA.js";import"./chunk-HMUSFTXZ.js";import"./chunk-4G2VXEY3.js";import"./chunk-IGKWKAMN.js";import"./chunk-GXONGRGB.js";import"./chunk-6QGV3IWD.js";import"./chunk-K22YTJFL.js";import{VERSION,envValue,isBunBinary}from"./chunk-PW6XRLS6.js";import"./chunk-KZ4SIPGM.js";import"./chunk-JXWJOIH4.js";import{access,chmod,mkdir,unlink}from"node:fs/promises";import{createConnection,createServer}from"node:net";import{dirname as dirname2,join}from"node:path";function enqueueRecords(writer,sessionId,chunk){for(let line of chunk.split(`
3
- `))line&&writer.enqueue(sessionId,JSON.parse(line))}async function createRpcSessionBinding(sessionId,entry,writer,requestClose,options={}){if(entry.worker)return entry.worker.bind(sessionId,writer,requestClose,options);if(!entry.runtime)throw new Error("Session runtime was not created");let runtimeHost=new Proxy({},{get(_target,property){if(property==="switchSession"&&entry.switchSession)return entry.switchSession;if(property==="setRebindSession")return callback=>{entry.rebindSession=callback,entry.runtime?.setRebindSession(callback)};let runtime=entry.runtime;if(!runtime)throw new Error("Session runtime was not created");let value=Reflect.get(runtime,property,runtime);return typeof value=="function"?value.bind(runtime):value}}),handler=await runWithProviderScope(entry.scope,async()=>{let taggedSink={writeRaw:bindToProviderScope(chunk=>enqueueRecords(writer,sessionId,chunk)),waitForBackpressure:bindToProviderScope(async()=>{})};return createRpcConnectionHandler(runtimeHost,taggedSink,{sessionId,shutdownHandler:bindToProviderScope(requestClose),disposeRuntime:!1,eventFlushScheduler:flush=>flush(),...options})});return await handler.ready,{handle:command=>runWithProviderScope(entry.scope,()=>handler.handleInputLine(JSON.stringify(command))),cancelPendingExtensionUiRequests:()=>runWithProviderScope(entry.scope,()=>handler.cancelPendingExtensionUiRequests()),rerenderComponents:()=>runWithProviderScope(entry.scope,()=>handler.rerenderComponents()),dispose:()=>runWithProviderScope(entry.scope,()=>handler.dispose())}}import{existsSync,realpathSync}from"node:fs";import{basename,dirname,isAbsolute,resolve}from"node:path";function reportDetachedFailure(handle,cause){process.stderr.write(`senpi rpc session ${handle} teardown failed: ${String(cause)}
4
- `)}function beginSessionClose(host,handle,onRole,options){let entry=host.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing")return onRole?.(!1),entry;if(entry.state!=="open")throw new RpcSessionRegistryError("unknown_session");return entry.attachments-=1,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry):(entry.state="closing",onRole?.(!0),entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),entry)}function closeSession(host,handle){return beginSessionClose(host,handle).state!=="closing"?Promise.resolve():closeMarkedSession(host,handle)}function closeMarkedSession(host,handle){host.sync();let entry=host.get(handle);if(entry?.state!=="closing")throw new RpcSessionRegistryError("unknown_session");let completion=entry.closeCompletion;if(!completion)return Promise.resolve();if(entry.closeStarted)return completion;entry.closeStarted=!0;let previousLifecycle=entry.lifecycleMutex,releaseTimer,released=!1,disposePromise,scopeClosed=!1,disposeOnce=()=>disposePromise||(disposePromise=Promise.resolve(entry.runtime?.dispose()),disposePromise),closeScopeOnce=async()=>{scopeClosed||(scopeClosed=!0,await entry.scope.close?.())},release=()=>{released||(released=!0,releaseTimer&&clearTimeout(releaseTimer),entry.state="closed",host.delete(handle),entry.reservationKey&&host.releaseReservation(entry.reservationKey))},graceful=(async()=>{await previousLifecycle;try{await entry.runtime?.session.abort()}catch(cause){reportDetachedFailure(handle,cause)}try{await entry.runtime?.session.waitForIdle()}catch(cause){reportDetachedFailure(handle,cause)}try{await disposeOnce()}catch(cause){reportDetachedFailure(handle,cause)}try{await closeScopeOnce()}catch(cause){reportDetachedFailure(handle,cause)}})(),settled=!1,finish=()=>{settled||(settled=!0,release(),entry.closeResolve?.())};return releaseTimer=setTimeout(()=>{disposeOnce().catch(cause=>reportDetachedFailure(handle,cause)),closeScopeOnce().catch(cause=>reportDetachedFailure(handle,cause)),graceful.catch(cause=>reportDetachedFailure(handle,cause)),finish()},host.closeGraceMs),graceful.then(finish,cause=>{reportDetachedFailure(handle,cause),finish()}),completion}var RpcSessionRegistryError=class extends Error{constructor(code,reason){super(code==="open_failed"&&reason?`${code}: ${reason}`:code),this.code=code,this.name="RpcSessionRegistryError"}};function canonicalPath(path){let absolutePath=resolve(path);return existsSync(absolutePath)?realpathSync(absolutePath):`${realpathSync(dirname(absolutePath))}/${basename(absolutePath)}`}function frozenProfile(profile){return Object.freeze({...profile,...profile.creationModel?{creationModel:Object.freeze({...profile.creationModel})}:{}})}var RpcSessionRegistry=class{constructor(options){this.entries=new Map,this.reservations=new Set,this.nextHandle=0,this.options=options,this.now=options.now??Date.now,this.closeGraceMs=options.closeGraceMs??1e4,this.teardownHost={closeGraceMs:this.closeGraceMs,get:handle=>this.entries.get(handle),delete:handle=>this.entries.delete(handle),releaseReservation:key=>this.reservations.delete(key),sync:()=>this.syncRuntimeMetadata()}}get size(){return this.entries.size}async openSession(profile,options){this.validateProfile(profile),this.syncRuntimeMetadata();let sessionPath=profile.sessionPath?canonicalPath(profile.sessionPath):void 0;if(sessionPath&&this.reservations.has(sessionPath)){let existing=[...this.entries].find(([,entry3])=>entry3.reservationKey===sessionPath&&entry3.state==="open");if(!existing)throw new RpcSessionRegistryError("session_path_in_use");let[handle2,entry2]=existing;if(entry2.attachments+=1,options?.retainOnDisconnect&&(entry2.retainOnDisconnect=!0),!entry2.durableSessionId)throw new RpcSessionRegistryError("session_path_in_use");return entry2.lastCommandAt=this.now(),{sessionId:handle2,durableSessionId:entry2.durableSessionId,sessionPath:entry2.sessionPath,attached:!0}}sessionPath&&this.reservations.add(sessionPath);let isResume=sessionPath!==void 0&&existsSync(sessionPath),sessionStartEvent=isResume?{type:"session_start",reason:"resume"}:void 0,storedProfile=frozenProfile({...profile,...sessionPath?{sessionPath}:{}}),runtimeProfile=isResume?frozenProfile({...storedProfile,creationModel:void 0,initialThinkingLevel:void 0}):storedProfile,handle=`rpc-${++this.nextHandle}`,entry={state:"opening",scope:new ProviderScope,profile:storedProfile,sessionPath,reservationKey:sessionPath,cwd:storedProfile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:this.now(),lifecycleMutex:Promise.resolve()};entry.switchSession=(sessionPath2,options2)=>{let operation=entry.lifecycleMutex.then(async()=>{if(entry.state!=="open"||!entry.runtime)throw new RpcSessionRegistryError("unknown_session");let runtime=entry.runtime,cwdOverride=options2?.cwdOverride,cwdChanged=cwdOverride!==void 0&&runtime.session.sessionManager.getCwd()!==cwdOverride,result=await runtime.switchSession(sessionPath2,options2);if(result.cancelled||!cwdChanged)return result;let replacement=new AgentSessionRuntime(runtime.session,runtime.services,this.options.createRuntime,[...runtime.diagnostics],runtime.modelFallbackMessage,runtime.launchProfile);return replacement.setRebindSession(entry.rebindSession),entry.runtime=replacement,this.syncRuntimeMetadata(),result});return entry.lifecycleMutex=operation.then(()=>{},()=>{}),operation},this.entries.set(handle,entry);try{let manager=sessionPath?SessionManager.open(sessionPath,void 0,storedProfile.cwd):SessionManager.create(storedProfile.cwd);return entry.runtime=await runWithProviderScope(entry.scope,()=>createAgentSessionRuntime(this.options.createRuntime,{cwd:manager.getCwd(),agentDir:this.options.agentDir,sessionManager:manager,sessionStartEvent,launchProfile:runtimeProfile})),entry.durableSessionId=manager.getSessionId(),entry.sessionPath??=manager.getSessionFile(),entry.state="open",{sessionId:handle,durableSessionId:entry.durableSessionId,sessionPath:entry.sessionPath}}catch(error2){try{await entry.runtime?.dispose()}catch{}finally{try{await entry.scope.close?.()}finally{this.entries.delete(handle),sessionPath&&this.reservations.delete(sessionPath)}}throw error2 instanceof RpcSessionRegistryError?error2:new RpcSessionRegistryError("open_failed",error2 instanceof Error?error2.message:void 0)}}peek(handle){return this.entries.get(handle)}getForCommand(handle,command){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return entry.lastCommandAt=this.now(),entry}beginClose(handle,onRole,options){return beginSessionClose(this.teardownHost,handle,onRole,options)}async close(handle){return closeSession(this.teardownHost,handle)}async closeMarked(handle){return closeMarkedSession(this.teardownHost,handle)}list(){return this.syncRuntimeMetadata(),[...this.entries].map(([sessionId,entry])=>({sessionId,durableSessionId:entry.durableSessionId,sessionPath:entry.sessionPath,cwd:entry.cwd,name:entry.runtime?.session.sessionManager.getSessionName(),attachments:Math.max(0,entry.attachments),status:entry.state==="quarantined"?"closing":entry.state}))}syncRuntimeMetadata(){for(let entry of this.entries.values()){let manager=entry.runtime?.session.sessionManager;if(!manager)continue;let currentPath=manager.getSessionFile();if(currentPath!==entry.sessionPath){let currentKey=currentPath?canonicalPath(currentPath):void 0;entry.reservationKey&&this.reservations.delete(entry.reservationKey),currentKey&&this.reservations.add(currentKey),entry.reservationKey=currentKey,entry.sessionPath=currentPath}entry.durableSessionId=manager.getSessionId(),entry.cwd=manager.getCwd()}}validateProfile(profile){if(!isAbsolute(profile.cwd)||profile.sessionPath!==void 0&&!isAbsolute(profile.sessionPath))throw new RpcSessionRegistryError("invalid_path")}};var controls=new Set(["get_protocol_info","open_session","close_session","list_sessions"]);function error(id,command,code){return{id,type:"response",command,success:!1,error:code}}var SessionCommandRouter=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(this.bindings=new Map,this.sessionsByConnection=new Map,this.opensByConnection=new Map,this.releasedConnections=new Set,this.widths=new Map,this.pendingCapabilities=new Map,this.finalizations=new Map,this.registry=registry,this.writer=writer,this.defaults=defaults,this.createBinding=createBinding,this.connectionOptions=connectionOptions,this.idleNow=idle?.now??Date.now,this.idleEvictionMs=idle?.idleEvictionMs??Number.POSITIVE_INFINITY,this.emptyExitMs=idle?.emptyExitMs??Number.POSITIVE_INFINITY,this.onEmptyExit=idle?.onEmptyExit,this.canExitWhenEmpty=idle?.canExitWhenEmpty,Number.isFinite(this.idleEvictionMs)||Number.isFinite(this.emptyExitMs)){let tickMs=Math.max(20,Math.min(5e3,Math.min(this.idleEvictionMs,this.emptyExitMs)/4));this.sweepTimer=setInterval(()=>this.sweepIdleSessions(),tickMs),this.sweepTimer.unref?.()}}async handle(command){if(command.type==="get_protocol_info"){let capabilities=new Set(["multi_session",AUTO_TITLE_SESSIONS_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,...this.connectionOptions?.capabilities??[]]);return{id:command.id,type:"response",command:"get_protocol_info",success:!0,data:{protocolVersion:1,serverVersion:VERSION,capabilities:[...capabilities],mode:"multi"}}}if(command.type==="list_sessions")return{id:command.id,type:"response",command:"list_sessions",success:!0,data:{sessions:this.registry.list()}};if(command.type==="open_session")return this.openWithBarrier(command);if(command.type==="close_session")return this.close(command);if(command.type==="set_client_info"&&!command.sessionId){let connection=this.writer.currentConnection();return connection!==void 0&&(this.pendingCapabilities.set(connection,command.capabilities??[]),this.writer.setConnectionCapabilities(connection,command.capabilities??[])),{id:command.id,type:"response",command:"set_client_info",success:!0}}if(!controls.has(command.type)){if(!command.sessionId)return error(command.id,command.type,RPC_ERROR_MISSING_SESSION_ID);try{this.registry.getForCommand(command.sessionId,command.type);let binding=this.bindings.get(command.sessionId);if(!binding)return error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION);await binding.handle(command);return}catch(cause){return error(command.id,command.type,this.code(cause))}}}async dispose(){this.stopSweep(),await Promise.all([...this.bindings.entries()].map(async([sessionId,binding])=>{let claim=this.tryClaimClose(sessionId,{drainAttachments:!0});claim&&(claim.finalizer?await this.finalizeClose(sessionId,binding):await this.finalizations.get(sessionId)?.promise)})),this.bindings.clear()}sweepIdleSessions(){let now=this.idleNow();if(Number.isFinite(this.idleEvictionMs))for(let{sessionId,status}of this.registry.list()){if(status!=="open")continue;let entry=this.registry.peek(sessionId);if(entry){if(entry.worker?.busy||entry.runtime?.session.isSessionBusy){entry.lastCommandAt=now;continue}now-entry.lastCommandAt>=this.idleEvictionMs&&this.evictIdleSession(sessionId)}}Number.isFinite(this.emptyExitMs)&&(this.registry.size===0&&(this.canExitWhenEmpty?.()??!0)?this.emptySince===void 0?this.emptySince=now:now-this.emptySince>=this.emptyExitMs&&(this.stopSweep(),this.onEmptyExit?.()):this.emptySince=void 0)}async evictIdleSession(sessionId){let claim=this.tryClaimClose(sessionId,{drainAttachments:!0});if(!claim)return;let binding=this.bindings.get(sessionId);binding?.cancelPendingExtensionUiRequests?.(),this.forgetSessionOwnership(sessionId),claim.finalizer?await this.finalizeClose(sessionId,binding,()=>this.writer.closeSession(sessionId,{type:"response",command:"close_session",success:!0,data:{}})):await this.finalizations.get(sessionId)?.promise,this.writer.forgetSession(sessionId)}forgetSessionOwnership(sessionId){for(let[connection,owned]of this.sessionsByConnection)owned.delete(sessionId),owned.size===0&&this.sessionsByConnection.delete(connection);this.widths.delete(sessionId)}stopSweep(){this.sweepTimer!==void 0&&(clearInterval(this.sweepTimer),this.sweepTimer=void 0)}openWithBarrier(command){let owner=this.writer.currentConnection();if(owner===void 0)return this.open(command);let resolveBarrier,barrier=new Promise(resolve2=>{resolveBarrier=resolve2}),opens=this.opensByConnection.get(owner)??new Set;return opens.add(barrier),this.opensByConnection.set(owner,opens),this.open(command,owner).finally(()=>{resolveBarrier(),opens.delete(barrier),opens.size===0&&this.opensByConnection.delete(owner)})}async open(command,owner){let opened;try{opened=await this.registry.openSession({cwd:command.cwd??this.defaults.cwd,sessionPath:command.sessionPath,permissionPreset:command.permissionPreset??this.defaults.permissionPreset,creationModel:command.provider&&command.modelId?{provider:command.provider,modelId:command.modelId}:this.defaults.creationModel,initialThinkingLevel:command.thinkingLevel??this.defaults.initialThinkingLevel},{retainOnDisconnect:command.retain_on_disconnect===!0});let openedSession=opened,entry=this.registry.getForCommand(openedSession.sessionId,"open_session");if(owner!==void 0&&(this.writer.hasRegisteredConnectionCapabilities(owner)||this.writer.setConnectionCapabilities(owner,this.pendingCapabilities.get(owner)??this.connectionOptions?.capabilities??[]),this.writer.attachConnectionToSession(owner,openedSession.sessionId)),owner!==void 0){let owned=this.sessionsByConnection.get(owner)??new Map;owned.set(openedSession.sessionId,(owned.get(openedSession.sessionId)??0)+1),this.sessionsByConnection.set(owner,owned)}this.bindings.has(openedSession.sessionId)||(this.bindings.set(openedSession.sessionId,await this.createBinding(openedSession.sessionId,entry,this.writer,()=>{this.close({type:"close_session",sessionId:openedSession.sessionId})},{...this.connectionOptions,capabilities:owner!==void 0?this.pendingCapabilities.get(owner)??this.connectionOptions?.capabilities??[]:this.connectionOptions?.capabilities,sharedWidth:{getWidth:()=>{let widths=this.widths.get(openedSession.sessionId);return widths?.size?Math.min(...widths.values()):80},setWidth:(connectionId,width)=>{if(connectionId!==void 0){let widths=this.widths.get(openedSession.sessionId)??new Map;widths.set(connectionId,width),this.widths.set(openedSession.sessionId,widths)}},clearWidth:connectionId=>{let widths=this.widths.get(openedSession.sessionId);connectionId!==void 0&&widths?.delete(connectionId)},setCapabilities:(connectionId,capabilities)=>{if(connectionId!==void 0){this.writer.setConnectionCapabilities(connectionId,capabilities),this.pendingCapabilities.set(connectionId,[...capabilities]);for(let binding of this.bindings.values())binding.rerenderComponents?.()}},hasRenderedComponents:sessionId=>this.writer.hasCapableConnection(sessionId),connectionId:()=>this.writer.currentConnection(),onChange:()=>{for(let binding of this.bindings.values())binding.rerenderComponents?.()}}})),entry.worker&&(entry.worker.bindingReady=!0),entry.worker&&entry.worker.exited.then(async()=>{await this.finalizations.get(openedSession.sessionId)?.promise,this.bindings.delete(openedSession.sessionId),this.forgetSessionOwnership(openedSession.sessionId),this.writer.forgetSession(openedSession.sessionId)})),owner!==void 0&&this.releasedConnections.has(owner)&&(this.releaseOwnerAttachment(owner,openedSession.sessionId),await this.releaseOwnedSession(openedSession.sessionId));let state=entry.worker?.snapshot?.state??(entry.runtime?buildRpcSessionState(entry.runtime.session):void 0);if(!state)throw new Error("Session state was not created");this.writer.enqueue(opened.sessionId,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:opened.sessionId,state,...opened.attached?{attached:!0}:{}}});return}catch(cause){if(opened)try{await this.registry.close(opened.sessionId)}catch{}return error(command.id,"open_session",this.code(cause))}}async releaseConnection(connectionId){this.releasedConnections.add(connectionId),this.writer.clearConnectionCapabilities(connectionId);for(let sessionId of this.sessionsByConnection.get(connectionId)?.keys()??[])this.writer.detachConnectionFromSession(connectionId,sessionId);for(let widths of this.widths.values())widths.delete(connectionId);for(let binding of this.bindings.values())binding.rerenderComponents?.();let opens=this.opensByConnection.get(connectionId),owned=this.sessionsByConnection.get(connectionId);if(this.sessionsByConnection.delete(connectionId),owned===void 0){opens&&await Promise.all([...opens]),this.releasedConnections.delete(connectionId);return}await Promise.all([...owned].map(async([sessionId,count])=>{for(let attachment=0;attachment<count;attachment++){let live=this.registry.peek(sessionId),retained=live?.retainOnDisconnect===!0,session=live?.state==="open"?live.runtime?.session:void 0;if(!retained&&live?.state==="open"&&live.worker?.snapshot?.streaming){let unsubscribe=live.worker.subscribeSettled(()=>{unsubscribe(),this.releaseOwnedSession(sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred worker release ${sessionId} failed: ${String(cause)}
5
- `)})});continue}if(!retained&&session?.isStreaming){let released=!1,unsubscribe=session.subscribe(event=>{event.type!=="agent_settled"&&event.type!=="agent_idle"||released||(released=!0,unsubscribe(),this.releaseOwnedSession(sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}
6
- `)}))});continue}await this.releaseOwnedSession(sessionId)}})),opens&&await Promise.all([...opens]),this.releasedConnections.delete(connectionId)}async releaseOwnedSession(sessionId){let claim=this.tryClaimClose(sessionId,{drainAttachments:!1,detach:!0});if(!claim)return;if(!claim.finalizer){await this.finalizations.get(sessionId)?.promise;return}let binding=this.bindings.get(sessionId);binding?.cancelPendingExtensionUiRequests?.(),await this.finalizeClose(sessionId,binding)}claimClose(sessionId,options){let finalizer=!0,onRole=isFinalizer=>{finalizer=isFinalizer,isFinalizer&&!this.finalizations.has(sessionId)&&this.finalizations.set(sessionId,this.createFinalization())},entry=this.registry.beginClose(sessionId,onRole,{detach:options.detach});for(;options.drainAttachments&&entry.state==="open";)entry=this.registry.beginClose(sessionId,onRole);return{finalizer:finalizer&&entry.state==="closing"}}tryClaimClose(sessionId,options){try{return this.claimClose(sessionId,options)}catch{return}}async close(command){let response={id:command.id,type:"response",command:"close_session",success:!0,data:{}},reply=this.writer.reserveCloseResponse(command.sessionId,response);if(!reply)return;let claim;try{claim=this.claimClose(command.sessionId,{drainAttachments:!1})}catch(cause){return reply.release(),error(command.id,"close_session",this.code(cause))}try{let owner=this.writer.currentConnection();owner!==void 0&&this.releaseOwnerAttachment(owner,command.sessionId),claim.finalizer?await this.finalizeClose(command.sessionId,this.bindings.get(command.sessionId),()=>reply.complete(!0)):(await this.finalizations.get(command.sessionId)?.promise,reply.complete(!1));return}finally{reply.release()}}releaseOwnerAttachment(owner,sessionId){this.widths.get(sessionId)?.delete(owner),this.writer.detachConnectionFromSession(owner,sessionId);for(let binding of this.bindings.values())try{binding.rerenderComponents?.()}catch(cause){process.stderr.write(`senpi rpc rerender after close of session ${sessionId} failed: ${String(cause)}
7
- `)}let owned=this.sessionsByConnection.get(owner),count=owned?.get(sessionId);!owned||count===void 0||(count===1?owned.delete(sessionId):owned.set(sessionId,count-1),owned.size===0&&this.sessionsByConnection.delete(owner))}async finalizeClose(sessionId,binding,terminal){let finalization=this.finalizations.get(sessionId)??this.createFinalization();this.finalizations.set(sessionId,finalization);try{try{await binding?.dispose()}catch(cause){process.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}
8
- `)}this.bindings.delete(sessionId);try{await this.registry.closeMarked(sessionId)}catch(cause){process.stderr.write(`senpi rpc close for session ${sessionId} failed: ${String(cause)}
9
- `)}await this.registry.peek(sessionId)?.closeCompletion,terminal?.()}finally{finalization.resolve(),this.finalizations.delete(sessionId)}}createFinalization(){let resolveFinalization;return{promise:new Promise(resolve2=>{resolveFinalization=resolve2}),resolve:()=>resolveFinalization?.()}}code(cause){return cause instanceof RpcSessionRegistryError?cause.code===RPC_ERROR_OPEN_FAILED?cause.message:cause.code:cause instanceof Error&&[RPC_ERROR_UNKNOWN_SESSION,RPC_ERROR_SESSION_CLOSING].includes(cause.message)?cause.message:cause instanceof Error&&cause.message?`${RPC_ERROR_OPEN_FAILED}: ${cause.message}`:RPC_ERROR_UNKNOWN_SESSION}};function socketSink(socket){let needsDrain=!1,cut=!1;return{writeRaw(chunk){!cut&&!socket.destroyed&&(needsDrain=!socket.write(chunk))},close(){if(cut||(cut=!0,socket.destroyed))return;socket.end();let grace=setTimeout(()=>socket.destroy(),5e3);grace.unref(),socket.once("close",()=>clearTimeout(grace))},waitForBackpressure(){return socket.destroyed||!needsDrain?Promise.resolve():(needsDrain=!1,new Promise(resolve2=>{let done=()=>{socket.off("drain",done),socket.off("close",done),resolve2()};socket.once("drain",done),socket.once("close",done)}))}}}import{isAbsolute as isAbsolute2}from"node:path";var SESSION_WORKER_LIMITS={workers:20,requests:64,controlRequests:4,controlBytes:1048576,requestBytes:16777216,outputBytes:16777216,reservations:64,openMs:3e4,controlMs:5e3},WORKER_CREDIT_CODES={granted:1,conflict:2,limit:3};var RESERVATION_DENIAL_CODES={conflict:"session_path_in_use",limit:"session_reservation_limit"},SessionPathReservations=class{constructor(){this.owners=new Map}owner(path){return this.owners.get(path)}count(handle){let count=0;for(let owner of this.owners.values())owner===handle&&count++;return count}reserve(handle,path,live){let owner=this.owners.get(path);return owner?owner===handle?"granted":"conflict":this.count(handle)>=SESSION_WORKER_LIMITS.reservations&&(!live||(this.reconcile(handle,live),this.count(handle)>=SESSION_WORKER_LIMITS.reservations))?"limit":(this.owners.set(path,handle),"granted")}reconcile(handle,live){for(let[path,owner]of this.owners)owner!==handle||path===live.sessionPath||live.livePaths.includes(path)||this.owners.delete(path)}releaseAll(handle){for(let[path,owner]of this.owners)owner===handle&&this.owners.delete(path)}};import{fileURLToPath}from"node:url";import{Worker}from"node:worker_threads";var SessionWorkerRequests=class{constructor(send,timeout){this.pending=new Map,this.serial=0,this.closed=!1,this.openingDeadline=Date.now()+SESSION_WORKER_LIMITS.openMs,this.send=send,this.timeout=timeout}get activeCount(){return this.pending.size}request(message){if(this.closed)return Promise.reject(new Error("session_closing"));let control=message.type==="command"&&"type"in message.command&&typeof message.command.type=="string"&&["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(message.command.type),bytes=Buffer.byteLength(JSON.stringify(message)),count=0,pendingBytes=0;for(let pending of this.pending.values())pending.control===control&&(count++,pendingBytes+=pending.bytes);let maxCount=control?SESSION_WORKER_LIMITS.controlRequests:SESSION_WORKER_LIMITS.requests,maxBytes=control?SESSION_WORKER_LIMITS.controlBytes:SESSION_WORKER_LIMITS.requestBytes;if(count>=maxCount||pendingBytes+bytes>maxBytes)return Promise.reject(new Error("session_worker_request_limit"));let request=++this.serial;return new Promise((resolve2,reject)=>{let timer=message.type==="command"&&!control?void 0:setTimeout(this.timeout,control?SESSION_WORKER_LIMITS.controlMs:Math.max(0,this.openingDeadline-Date.now()));this.pending.set(request,{resolve:resolve2,reject,bytes,control,timer});try{this.send({...message,request})}catch(cause){this.pending.delete(request),clearTimeout(timer),reject(cause instanceof Error?cause:new Error(String(cause)))}})}receive(message){let pending=this.pending.get(message.request);pending&&(clearTimeout(pending.timer),this.pending.delete(message.request),message.type==="result"&&message.error?pending.reject(new Error(message.error)):pending.resolve(message))}close(error2){this.closed=!0;for(let pending of this.pending.values())clearTimeout(pending.timer),pending.reject(error2);this.pending.clear()}};function acknowledgeGrant(signal,grant){let state=new Int32Array(signal);Atomics.store(state,0,WORKER_CREDIT_CODES[grant]),Atomics.notify(state,0)}function acknowledge(signal,granted){acknowledgeGrant(signal,granted?"granted":"conflict")}function respondDisplay(signal,display){let values=new Float64Array(signal);values[1]=display.width,values[2]=display.revision,Atomics.store(new Int32Array(signal),1,display.rendered?1:0),acknowledge(signal,!0)}var compiledWorkerEntry=typeof SENPI_RPC_SESSION_WORKER_ENTRY=="string"?SENPI_RPC_SESSION_WORKER_ENTRY:"./src/modes/rpc/session-worker.ts",SessionWorkerClient=class{constructor(callbacks){this.worker=new Worker(isBunBinary?fileURLToPath(new URL(compiledWorkerEntry,import.meta.url)).replaceAll("\\","/"):new URL(import.meta.url.endsWith(".ts")?"./session-worker.ts":"./session-worker.js",import.meta.url)),this.bindingReady=!1,this.requests=new SessionWorkerRequests(message=>this.worker.postMessage(message),()=>this.fail("session_worker_request_timeout")),this.stopped=!1,this.displayRevision=0,this.options={},this.listeners=new Set,this.controls=new Set,this.callbacks=callbacks,this.exited=new Promise(resolve2=>{this.worker.once("exit",()=>{!this.stopped&&!this.closeTimer&&this.fail("session_worker_exited"),this.stopped=!0,this.closeTimer&&clearTimeout(this.closeTimer),this.requests.close(new Error("session_worker_exited")),this.listeners.clear(),callbacks.exit(),this.publishTerminalFailure(),resolve2()})}),this.worker.on("message",message=>this.receive(message)),this.worker.on("error",error2=>this.fail(error2 instanceof Error?error2.message:String(error2)))}async prepare(configuration,profile){let result=await this.request({type:"prepare",configuration,profile});if(result.type!=="prepared")throw new Error("Invalid worker prepare response");return result.sessionPath}async commit(){let result=await this.request({type:"commit"});if(result.type!=="ready")throw new Error("Invalid worker commit response");return this.snapshot=result.snapshot,result.snapshot}async bind(sessionId,writer,requestClose,options){return this.sessionId=sessionId,this.writer=writer,this.requestClose=requestClose,this.options=options,await this.request({type:"bind",sessionId,display:this.display(),connection:writer.currentConnection()}),{handle:async command=>{await this.request({type:"command",command,connection:writer.currentConnection(),display:this.display()})},cancelPendingExtensionUiRequests:()=>this.post({type:"cancel_ui"}),rerenderComponents:()=>this.post({type:"display",display:this.display()}),dispose:async()=>{this.post({type:"cancel_ui"})}}}get busy(){return this.requests.activeCount>0||this.snapshot?.busy===!0}subscribeSettled(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}close(graceMs){return this.stopped||this.closeTimer?this.exited:(this.post({type:"close"}),this.closeTimer=setTimeout(()=>this.quarantine(),graceMs),this.exited)}quarantine(){this.stopped=!0,this.requests.close(new Error("session_closing")),this.worker.terminate()}display(){return{revision:++this.displayRevision,width:this.options.sharedWidth?.getWidth()??80,rendered:this.options.sharedWidth?.hasRenderedComponents?.(this.sessionId??"")??!1,capabilities:this.options.capabilities??[]}}request(message){return this.requests.request(message)}post(message){if(!this.stopped){if(message.type==="display"||message.type==="cancel_ui"){if(this.controls.has(message.type)){message.type==="display"&&(this.latestDisplay=message);return}this.controls.add(message.type)}this.worker.postMessage(message)}}receive(message){if(this.stopped){"signal"in message&&acknowledge(message.signal,!1);return}switch(message.type){case"prepared":case"ready":case"result":{this.requests.receive(message);return}case"reserve":acknowledgeGrant(message.signal,this.callbacks.reserve(message.path));return;case"snapshot":if(this.snapshot=message.snapshot,this.callbacks.reconcile(message.snapshot.liveSessionPaths),acknowledge(message.signal,!0),message.settled)for(let listener of[...this.listeners])listener();return;case"control_done":{if(this.controls.delete(message.control),message.control==="display"&&this.latestDisplay){let latest=this.latestDisplay;this.latestDisplay=void 0,this.post(latest)}return}case"output":{let writer=this.writer,sessionId=this.sessionId;if(!writer||!sessionId||this.stopped){acknowledge(message.signal,!1);return}message.snapshot?(this.snapshot=message.snapshot,this.callbacks.reconcile(message.snapshot.liveSessionPaths)):this.snapshot&&(this.snapshot={...this.snapshot,...message.activity,state:{...this.snapshot.state,isStreaming:message.activity.streaming}});let enqueue=()=>writer.enqueue(sessionId,message.record)?writer.waitForSessionBackpressure(sessionId):(acknowledge(message.signal,!1),this.fail("session_output_overflow_or_closed"),Promise.reject(new Error("session_output_overflow_or_closed")));(message.connection===void 0?enqueue():writer.withConnection(message.connection,enqueue)).then(()=>acknowledge(message.signal,!0),cause=>{acknowledge(message.signal,!1),this.fail(cause instanceof Error?cause.message:String(cause))});return}case"width":this.options.sharedWidth?.setWidth(message.connection,message.width),this.options.sharedWidth?.onChange?.(),respondDisplay(message.signal,this.display());return;case"capabilities":this.options.sharedWidth?.setCapabilities?.(message.connection,message.capabilities),respondDisplay(message.signal,this.display());return;case"request_close":this.requestClose?.();return;case"failure":this.fail(message.error);return}}fail(error2){this.stopped||(this.callbacks.failure(error2),this.terminalFailure=error2,this.writer&&this.sessionId&&this.writer.enqueue(this.sessionId,{type:"session_error",error:error2}),this.quarantine())}publishTerminalFailure(){let error2=this.terminalFailure,writer=this.writer,sessionId=this.sessionId;error2===void 0||!writer||!sessionId||(this.terminalFailure=void 0,writer.closeSession(sessionId,{type:"response",command:"close_session",success:!1,error:error2}))}};var WorkerSessionRegistry=class{constructor(options){this.entries=new Map,this.reservations=new SessionPathReservations,this.serial=0,this.options=options,this.closeGraceMs=options.closeGraceMs,this.now=options.now}get size(){return this.entries.size}async openSession(profile,options){if(!isAbsolute2(profile.cwd)||profile.sessionPath!==void 0&&!isAbsolute2(profile.sessionPath))throw new RpcSessionRegistryError("invalid_path");if(profile.sessionPath){let key=this.knownReservationKey(profile.sessionPath),owner=key?this.reservations.owner(key):void 0;if(key&&owner)return this.attach(owner,key,options)}if(this.size>=SESSION_WORKER_LIMITS.workers)throw new Error("too_many_sessions");let handle=`rpc-${++this.serial}`,entry={state:"opening",scope:new ProviderScope,profile:Object.freeze({...profile}),cwd:profile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:this.now(),lifecycleMutex:Promise.resolve()},worker=new SessionWorkerClient({reserve:path=>this.reserve(handle,path),reconcile:livePaths=>this.reconcile(handle,livePaths),exit:()=>{this.entries.get(handle)===entry&&(entry.state="closed",this.entries.delete(handle),this.reservations.releaseAll(handle),entry.closeResolve?.())},failure:error2=>{entry.state="quarantined",process.stderr.write(`senpi rpc session ${handle} quarantined: ${error2}
10
- `)}});entry.worker=worker,this.entries.set(handle,entry);try{let path=await worker.prepare(this.options.configuration,profile),owner=this.reservations.owner(path);if(owner){let attached=this.attach(owner,path,options);return entry.state="quarantined",worker.quarantine(),attached}let grant=this.reserve(handle,path);if(grant!=="granted")throw new RpcSessionRegistryError(RESERVATION_DENIAL_CODES[grant]);entry.reservationKey=path,entry.requestedPathKey=profile.sessionPath?path:void 0,entry.sessionPath=path;let snapshot=await worker.commit();if(entry.state!=="opening")throw new RpcSessionRegistryError("session_closing");return entry.durableSessionId=snapshot.state.sessionId,entry.cwd=snapshot.state.cwd,entry.state="open",this.openResult(handle,entry)}catch(cause){throw entry.state="quarantined",worker.quarantine(),cause}}peek(handle){return this.entries.get(handle)}getForCommand(handle,command){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="quarantined"||entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return entry.lastCommandAt=this.now(),entry}beginClose(handle,onRole,options){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"||entry.state==="quarantined")return onRole?.(!1),entry;if(entry.state!=="open"&&entry.state!=="opening")throw new RpcSessionRegistryError("unknown_session");return entry.attachments--,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry):(entry.state="closing",entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),onRole?.(!0),entry)}close(handle){return this.beginClose(handle).state==="closing"?this.closeMarked(handle):Promise.resolve()}async closeMarked(handle){let entry=this.entries.get(handle);if(entry?.state!=="closing"||!entry.worker)throw new RpcSessionRegistryError("unknown_session");if(entry.closeStarted)return entry.closeCompletion;entry.closeStarted=!0;let timer;await Promise.race([entry.worker.close(this.closeGraceMs),new Promise(resolve2=>{timer=setTimeout(()=>{entry.state!=="closed"&&(entry.state="quarantined"),resolve2()},this.closeGraceMs)})]),timer&&clearTimeout(timer)}list(){return[...this.entries].map(([sessionId,entry])=>{let state=entry.worker?.snapshot?.state;return{sessionId,durableSessionId:state?.sessionId??entry.durableSessionId,sessionPath:state?.sessionFile??entry.sessionPath,cwd:state?.cwd??entry.cwd,name:state?.sessionName,attachments:Math.max(0,entry.attachments),status:entry.state==="quarantined"?"closing":entry.state}})}knownReservationKey(path){if(this.reservations.owner(path))return path;for(let entry of this.entries.values()){if(entry.profile.sessionPath===path&&entry.requestedPathKey&&this.reservations.owner(entry.requestedPathKey))return entry.requestedPathKey;let snapshot=entry.worker?.snapshot;if(snapshot?.state.sessionFile===path)return snapshot.sessionPath}}attach(owner,path,options){let entry=this.entries.get(owner);if(entry?.state!=="open"||!entry.worker?.bindingReady||entry.worker.snapshot?.sessionPath!==path)throw new RpcSessionRegistryError("session_path_in_use");let result=this.openResult(owner,entry);return entry.attachments++,options?.retainOnDisconnect&&(entry.retainOnDisconnect=!0),entry.lastCommandAt=this.now(),{...result,attached:!0}}reservationCount(handle){return this.reservations.count(handle)}reserve(handle,path){let entry=this.entries.get(handle);return entry?this.reservations.owner(path)===handle?"granted":entry.state!=="opening"&&entry.state!=="open"?"conflict":this.reservations.reserve(handle,path,this.liveWorkerPaths(entry)):"conflict"}reconcile(handle,livePaths){let entry=this.entries.get(handle);if(entry?.state!=="open")return;let sessionPath=entry.worker?.snapshot?.sessionPath;this.reservations.reconcile(handle,{livePaths,sessionPath}),sessionPath&&(entry.reservationKey=sessionPath,entry.sessionPath=sessionPath)}liveWorkerPaths(entry){let snapshot=entry.state==="open"?entry.worker?.snapshot:void 0;if(snapshot)return{livePaths:snapshot.liveSessionPaths,sessionPath:snapshot.sessionPath}}openResult(handle,entry){let state=entry.worker?.snapshot?.state;if(!state)throw new RpcSessionRegistryError("open_failed");return{sessionId:handle,durableSessionId:state.sessionId,sessionPath:state.sessionFile}}};var RPC_SESSION_IDLE_EVICTION_MS_ENV="SENPI_RPC_SESSION_IDLE_EVICTION_MS",RPC_HOST_EMPTY_EXIT_MS_ENV="SENPI_RPC_HOST_EMPTY_EXIT_MS",RPC_CLOSE_GRACE_MS_ENV="SENPI_RPC_CLOSE_GRACE_MS",DEFAULT_SESSION_IDLE_EVICTION_MS=30*6e4,DEFAULT_HOST_EMPTY_EXIT_MS=15*6e4,WINDOWS_SHUTDOWN_HARD_EXIT_MS=2e3;function resolveHostIdlePolicy(env,overrides={}){return{now:overrides.now??Date.now,idleEvictionMs:overrides.idleEvictionMs??parseIdleExitMs(env[RPC_SESSION_IDLE_EVICTION_MS_ENV])??DEFAULT_SESSION_IDLE_EVICTION_MS,emptyExitMs:overrides.emptyExitMs??parseIdleExitMs(env[RPC_HOST_EMPTY_EXIT_MS_ENV])??DEFAULT_HOST_EMPTY_EXIT_MS}}async function runMultiSessionHost(options){return options.listen===void 0||options.listen==="stdio://"?runStdioHost(options):runSocketHost(options,resolveSocketPath(options.listen,options.agentDir))}function createHostCore(options,writer,capabilities=parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")),idle={}){let policy=resolveHostIdlePolicy(process.env,idle),router=new SessionCommandRouter(options.workerConfiguration?new WorkerSessionRegistry({configuration:options.workerConfiguration,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4}):new RpcSessionRegistry({agentDir:options.agentDir,createRuntime:options.createRuntime,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4}),writer,options,options.createBinding,{capabilities},{now:policy.now,idleEvictionMs:policy.idleEvictionMs,emptyExitMs:policy.emptyExitMs,onEmptyExit:idle.onEmptyExit,canExitWhenEmpty:idle.canExitWhenEmpty});return{router,handle:async line=>{let parsed;try{parsed=JSON.parse(line)}catch(cause){await writer.enqueueControl(parseError(`Failed to parse command: ${errorMessage(cause)}`));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError){await writer.enqueueControl(parseError(shapeError));return}let response=await router.handle(parsed);response&&await writer.enqueueControl(response)}}}async function runStdioHost(options){takeOverStdout();let sink={writeRaw:writeRawStdout,waitForBackpressure:waitForRawStdoutBackpressure},writer=new SessionEventWriter(sink.writeRaw,sink.waitForBackpressure),{router,handle}=createHostCore(options,writer,void 0,{onEmptyExit:()=>{shutdown(0)}}),shuttingDown=!1,shutdown=async(exitCode=0)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0,detach(),await router.dispose(),await writer.flush(),await flushRawStdout(),process.exit(exitCode)},onEnd=()=>{shutdown()};process.stdin.on("end",onEnd);let reportInputFailure=cause=>{process.stderr.write(`senpi rpc stdio request failed: ${errorMessage(cause)}
11
- `)},detachReader=attachJsonlLineReader(process.stdin,line=>{handle(line).catch(reportInputFailure)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.enqueueControl(parseError(oversizedLineError())).catch(reportInputFailure)}}),detach=()=>{detachReader(),process.stdin.off("end",onEnd)};return registerShutdownSignals(shutdown),new Promise(()=>{})}async function runSocketHost(options,socketPath){await prepareSocketPath(socketPath);let writer=new SessionEventWriter(()=>{}),connections=new Map,{router,handle}=createHostCore(options,writer,parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")).filter(capability=>capability!=="rendered_components"),{onEmptyExit:()=>{shutdown(0)},canExitWhenEmpty:()=>connections.size===0}),nextConnection=0,shuttingDown=!1,secret=process.platform==="win32"?await ensureSocketSecret(process.env[SOCKET_SECRET_FILE_ENV]??socketSecretPath(socketPath)):void 0,watchdogConfig=readHostWatchdogConfigFromBrandEnv(),supervisorPublicSocketPath=process.platform==="win32"||socketPath.startsWith("\0")?void 0:watchdogConfig?.publicSocket,supervisorPublicOwnerFile=supervisorPublicSocketPath&&watchdogConfig?.scratchDir?join(watchdogConfig.scratchDir,PUBLIC_SOCKET_IDENTITY_FILE):void 0,boundIdentity,supervisorPublicIdentity,server=createServer(socket=>{let accept=()=>{let id=`socket-${++nextConnection}`,sink=socketSink(socket);writer.registerConnection(id,sink);let detachReader=attachJsonlLineReader(socket,line=>{writer.withConnection(id,()=>handle(line)).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
12
- `)})},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.withConnection(id,()=>writer.enqueueControl(parseError(oversizedLineError()))).catch(cause=>process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
13
- `))}}),detached=!1,detach=()=>{detached||(detached=!0,detachReader(),writer.unregisterConnection(id),connections.delete(id),router.releaseConnection(id).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} release failed: ${errorMessage(cause)}
14
- `)}))};connections.set(id,{id,sink,detach,close:()=>socket.destroy()}),socket.once("close",detach),socket.once("error",()=>detach())};secret?authenticateSocket(socket,secret,accept):accept()});server.on("error",cause=>{shuttingDown||process.stderr.write(`senpi rpc socket listener failed: ${errorMessage(cause)}
15
- `)});let shutdown=async(exitCode=0,watchdogCleanup)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0;try{for(let connection of connections.values())connection.detach(),connection.close();await shieldSocketDuringClose(socketPath,()=>process.platform==="win32"?Promise.race([closeServer(server),delay(WINDOWS_SHUTDOWN_HARD_EXIT_MS)]):closeServer(server)),await router.dispose(),await writer.flush(),await unlinkOwnedSocket(socketPath,boundIdentity,hostLog),supervisorPublicSocketPath&&await unlinkOwnedSocket(supervisorPublicSocketPath,supervisorPublicIdentity,hostLog),watchdogCleanup&&await watchdogCleanup}finally{process.exit(exitCode)}};registerShutdownSignals(shutdown);let watchdog=watchdogConfig&&supervisorPublicOwnerFile?{...watchdogConfig,beforeCleanup:async()=>{supervisorPublicIdentity??=await readSocketIdentityFile(supervisorPublicOwnerFile)}}:watchdogConfig;return armHostWatchdog(watchdog,(reason,cleanup)=>{process.stderr.write(`senpi rpc host: ${reason}; shutting down
16
- `),shutdown(0,cleanup),setImmediate(killTrackedDetachedChildren)}),boundIdentity=await listen(server,socketPath,secret),supervisorPublicOwnerFile&&(supervisorPublicIdentity=await waitForSocketIdentityFile(supervisorPublicOwnerFile)),process.stderr.write(`senpi rpc listening on ${formatSocketAddress(socketPath)}
17
- `),new Promise(()=>{})}function delay(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}function parseError(error2){return{type:"response",command:"parse",success:!1,error:error2}}function oversizedLineError(){return`RPC input line exceeds ${MAX_RPC_LINE_CHARACTERS} characters.`}function errorMessage(cause){return cause instanceof Error?cause.message:String(cause)}function resolveSocketPath(value,agentDir){if(value==="unix://")return join(agentDir,"rpc","rpc.sock");if(value.startsWith("unix://")){let path=value.slice(7);return path.length===0?join(agentDir,"rpc","rpc.sock"):path.startsWith("@")&&process.platform==="linux"?`\0${path.slice(1)}`:path}return value}function formatSocketAddress(socketPath){return socketPath.startsWith("\0")?`unix://@${socketPath.slice(1)}`:`unix://${socketPath}`}async function prepareSocketPath(socketPath){if(!(process.platform==="win32"||socketPath.startsWith("\0"))){await mkdir(dirname2(socketPath),{recursive:!0,mode:448});try{await access(socketPath)}catch(cause){if(isNodeErrorCode(cause,"ENOENT"))return;throw cause}if(await probeSocket(socketPath))throw new Error(`${socketPath}: address already in use by a live server.`);await unlink(socketPath)}}function probeSocket(socketPath){return new Promise(resolve2=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform)),settle=live=>{socket.destroy(),resolve2(live)};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1)),socket.setTimeout(1e3,()=>settle(!1))})}function listen(server,socketPath,secret){return new Promise((resolve2,reject)=>{server.once("error",reject),server.listen(resolveSocketTransportAddress(socketPath,process.platform,secret),async()=>{server.off("error",reject);try{if(process.platform!=="win32"&&!socketPath.startsWith("\0"))return await chmod(socketPath,384),resolve2(await statSocketIdentity(socketPath));resolve2(void 0)}catch(cause){reject(cause)}})})}function closeServer(server){return new Promise((resolve2,reject)=>{server.close(cause=>cause?reject(cause):resolve2())})}function hostLog(message){process.stderr.write(`senpi rpc host: ${message}
18
- `)}function isNodeErrorCode(cause,code){return cause instanceof Error&&"code"in cause&&cause.code===code}function registerShutdownSignals(shutdown){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{killTrackedDetachedChildren(),shutdown(signal==="SIGHUP"?129:143)})}export{DEFAULT_HOST_EMPTY_EXIT_MS,DEFAULT_SESSION_IDLE_EVICTION_MS,RPC_CLOSE_GRACE_MS_ENV,RPC_HOST_EMPTY_EXIT_MS_ENV,RPC_SESSION_IDLE_EVICTION_MS_ENV,createHostCore,resolveHostIdlePolicy,runMultiSessionHost};
@@ -1,2 +0,0 @@
1
- import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
- import{classifyCredentialFailure,rendezvousOrder,resolveConfigValue,runCredentialFailover}from"./chunk-YLYLKL7X.js";import{discoverEnvSlots}from"./chunk-34UXOYIZ.js";import"./chunk-KPSJKRO6.js";import"./chunk-WHS3V662.js";import"./chunk-EN5HLCZK.js";import{acquireHalfOpenLease}from"./chunk-VYQOYVDV.js";import"./chunk-QL422WQ7.js";import"./chunk-K7HIYM6P.js";import"./chunk-HHQCPUMK.js";import"./chunk-ZG74NES2.js";import"./chunk-JKCCH24R.js";import"./chunk-T6SHTZ3M.js";import"./chunk-EFXPIEEC.js";import"./chunk-7DDKXS2Q.js";import"./chunk-U456RL4N.js";import"./chunk-TEPMHNKQ.js";import{listSlots}from"./chunk-B2F5G2RY.js";import"./chunk-7DGJYBYJ.js";import"./chunk-L2ZPNLYD.js";import"./chunk-D2D2LIVO.js";import"./chunk-6R7UI4IY.js";import"./chunk-4G2VXEY3.js";import"./chunk-K22YTJFL.js";import"./chunk-PW6XRLS6.js";import"./chunk-KZ4SIPGM.js";import"./chunk-JXWJOIH4.js";import{createHash,randomUUID}from"node:crypto";var sha256SlotHasher=input=>createHash("sha256").update(input).digest().readBigUInt64BE(0);function overlayState(slot,state){return state?{...slot,...state.blockedUntil===void 0?{}:{blockedUntil:state.blockedUntil},...state.blockReason===void 0?{}:{blockReason:state.blockReason},...state.failureCount===void 0?{}:{failureCount:state.failureCount},...state.lease===void 0?{}:{lease:state.lease}}:slot}async function listRotationSlots(sources,options={}){let acquireLeases=options.acquireLeases!==!1,{providerId,credential,env,repository}=sources,policySlots=Object.entries(sources.policy?.slots??{}).flatMap(([name,ref])=>{let envVarName=ref.env??`models.json:${name}`,key=ref.env!==void 0?env(ref.env):ref.value!==void 0?resolveConfigValue(ref.value,{}):void 0;return key?[{name,envVarName,key,source:"env"}]:[]});if(credential){let state=await repository.listSlots(providerId,"stored"),slots=[];for(let slot of listSlots(credential)){let persisted=state[slot.name],storedRevision=await repository.storedCredentialRevision(providerId,slot.name,{key:slot.key,access:slot.access,refresh:slot.refresh}),applicable=persisted?.credentialRevision===storedRevision?persisted:void 0;if(acquireLeases&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=(sources.now??Date.now)()){if(!await acquireHalfOpenLease(repository,providerId,"stored",slot.name,{now:(sources.now??Date.now)()}))continue;let leasedState=(await repository.listSlots(providerId,"stored"))[slot.name];slots.push(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},leasedState?.credentialRevision===storedRevision?leasedState:void 0));continue}slots.push(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},applicable))}if(policySlots.length===0)return slots;let namedSources={...sources,credential:void 0,policy:{...sources.policy,slots:{}}},namedSlots=await listEnvRotationSlots(namedSources,policySlots,acquireLeases);return[...slots,...namedSlots]}let envSlots=[...discoverEnvSlots(providerId,env),...policySlots];return listEnvRotationSlots(sources,envSlots,acquireLeases)}async function listEnvRotationSlots(sources,envSlots,acquireLeases=!0){if(envSlots.length===0)return[];let{providerId,repository}=sources,state=await repository.listSlots(providerId,"env"),slots=[];for(let slot of envSlots){let persisted=state[slot.name],revision=await repository.envCredentialRevision(slot.envVarName,slot.key),applicable=persisted?.credentialRevision===revision?persisted:void 0;if(acquireLeases&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=(sources.now??Date.now)()){if(!await acquireHalfOpenLease(repository,providerId,"env",slot.name,{now:(sources.now??Date.now)()}))continue;applicable=(await repository.listSlots(providerId,"env"))[slot.name]}slots.push(overlayState({name:slot.name,lane:"env",envKey:slot.key,envVarName:slot.envVarName},applicable))}return slots}function blockPatch(block,current,now,credentialRevision,policy){let base={failureCount:(current?.failureCount??0)+1,...credentialRevision===void 0?{}:{credentialRevision},...current?.lastSuccessAt===void 0?{}:{lastSuccessAt:current.lastSuccessAt}};return block.reason==="rate_limit"?{...base,blockedUntil:now+Math.min(policy?.cooldownCapMs??block.cooldownMs,block.cooldownMs),blockReason:"rate_limit"}:{...base,blockReason:block.reason}}function errorFromEvent(event){if(event.type!=="error")return;let message=event.error.errorMessage??"provider stream error";return new Error(message)}function streamWithCredentialRotation(options){let{sources,runAttempt}=options,hasher=options.hasher??sha256SlotHasher,affinityKey=options.affinityKey??randomUUID(),useAffinity=sources.policy?.affinity!==!1,now=sources.now??Date.now;return runCredentialFailover({listSlots:()=>listRotationSlots(sources),select:candidates=>{let pinned=candidates.find(candidate=>candidate.pinned===!0);if(pinned)return pinned;let winner=(useAffinity?rendezvousOrder(affinityKey,candidates,hasher):candidates)[0];if(!winner)throw new Error("credential rotation selected from an empty candidate set");return winner},runAttempt,isCommittedOutput:event=>event.type!=="start",errorFromEvent,classify:(error,context)=>classifyCredentialFailure(error,{...context,cooldownBaseMs:sources.policy?.cooldownBaseMs,cooldownCapMs:sources.policy?.cooldownCapMs}),onSuccess:async slot=>{await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>current?{...current,lastSuccessAt:now(),lease:void 0,blockedUntil:void 0,blockReason:void 0}:void 0)},persistBlock:async(slot,block)=>{let revision=slot.lane==="env"&&slot.envVarName!==void 0&&slot.envKey!==void 0?await sources.repository.envCredentialRevision(slot.envVarName,slot.envKey):slot.storedRevision;await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>blockPatch(block,current,now(),revision,sources.policy))},now})}export{listRotationSlots,sha256SlotHasher,streamWithCredentialRotation};