aws-runtime-bridge 1.9.140 → 1.9.142

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.
@@ -1,4 +1,4 @@
1
- import{EventEmitter as X}from"node:events";import V from"node:fs/promises";import U from"node:path";import{fileURLToPath as Z,pathToFileURL as tt}from"node:url";import{v4 as R}from"uuid";import{getBridgeInstancePluginsDir as et,getBridgeInstanceSkillsDir as ot,getBridgeTemplateConfigFile as x,getBridgeTemplateSkillsDir as st}from"../config.js";import{getReleasedAcodeEntryPath as it}from"../services/acode-package.js";import{syncAgentSkillFarm as F}from"../services/agent-capability-sync.js";import{agentPtyManager as at}from"../services/agent-pty-manager.js";import{getBrowserTools as v,closeBrowserSession as nt,registerListenerWakeHook as rt,unregisterListenerWakeHook as q}from"../services/browser-session-manager.js";import{getDesktopTools as D,getDesktopToolsIfReady as ut}from"../services/desktop-mcp-manager.js";import{redactForLog as B}from"../services/instance-ai-config-service.js";import{BROWSER_FEATURE_KEY as W,DESKTOP_FEATURE_KEY as O,getAgentToolPermissions as lt,isFeatureEnabled as P,resolveAgentToolPermissions as dt}from"../services/instance-features.js";import{pluginManager as L}from"../services/plugin-manager.js";import{subAgentManager as ct}from"../services/sub-agent-manager-instance.js";import{recordAgentFileChange as mt}from"../services/workspaceTaskChangeWatcher.js";import{getInstanceAiConfigDebugLogger as E}from"../utils/instance-ai-config-debug-logger.js";import{isMessagePollingIdleCommand as $,isPollMessageToolDescriptor as pt}from"./acode-tool-names.js";import{IdlePollLoop as gt}from"./idle-poll-loop.js";import{resolveAcodeProviderConfig as ft}from"./instance-ai-config-resolver.js";import{getCanonicalMcpDetail as N,getToolActionInfo as ht}from"./types.js";const Tt=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...u){Tt&&console.log(...u)}const At=process.env.ACODE_TOKEN_DEBUG==="1";function C(...u){At&&console.log("[TokenDebug][Adapter]",...u)}const H=["Continue the AgentsWork message loop now.","You MUST call the exact MCP tool named aws-mcp__poll_message as your next action and wait for the next assigned message or task.","Do not answer in plain text before calling aws-mcp__poll_message.","After handling any received work, reply through the appropriate aws-mcp messaging tool, then continue listening again."].join(" "),_t=5e3;function M(u,t){const e=process.env[u];if(e===void 0||e.trim()==="")return t;const o=Number(e.trim());return Number.isFinite(o)&&o>=0?Math.floor(o):t}const K=M("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),St=5*6e4,yt=M("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),bt=250,kt=2e3,j=M("ACODE_SUBMIT_TIMEOUT_MS",12e4),Q=3e3,Ct="\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002";function wt(){return U.resolve(it())}function Pt(u){return tt(U.resolve(u)).href}const G=128e3,w={"claude-4":{contextLimit:2e5,maxOutput:8192},"claude-sonnet-4":{contextLimit:2e5,maxOutput:8192},"claude-3-5-sonnet":{contextLimit:2e5,maxOutput:8192},"claude-3-opus":{contextLimit:2e5,maxOutput:8192},"claude-3-haiku":{contextLimit:2e5,maxOutput:8192},"claude-2":{contextLimit:1e5,maxOutput:4096},"gpt-4o":{contextLimit:128e3,maxOutput:16384},"gpt-4-turbo":{contextLimit:128e3,maxOutput:4096},"gpt-4":{contextLimit:8192,maxOutput:4096},"gpt-3.5-turbo":{contextLimit:16384,maxOutput:4096},o1:{contextLimit:2e5,maxOutput:1e5},"o3-mini":{contextLimit:2e5,maxOutput:1e5},"gemini-2.0-flash":{contextLimit:1048576,maxOutput:8192},"gemini-2.5-pro":{contextLimit:1048576,maxOutput:8192},"gemini-1.5-pro":{contextLimit:2097152,maxOutput:8192},"gemini-1.5-flash":{contextLimit:1048576,maxOutput:8192},deepseek:{contextLimit:64e3,maxOutput:8192},"deepseek-chat":{contextLimit:64e3,maxOutput:8192},"deepseek-reasoner":{contextLimit:64e3,maxOutput:8192},"qwen-max":{contextLimit:32e3,maxOutput:8192},"qwen-plus":{contextLimit:128e3,maxOutput:8192},"qwen-turbo":{contextLimit:1e6,maxOutput:8192},"glm-4":{contextLimit:128e3,maxOutput:4096},"yi-":{contextLimit:2e5,maxOutput:4096},"llama-3":{contextLimit:8192,maxOutput:4096},"llama-2":{contextLimit:4096,maxOutput:4096},mistral:{contextLimit:32e3,maxOutput:4096},mixtral:{contextLimit:32e3,maxOutput:4096},codestral:{contextLimit:256e3,maxOutput:8192},grok:{contextLimit:131072,maxOutput:4096},"nova-":{contextLimit:2e5,maxOutput:8192}};function Lt(u){if(!u)return G;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.contextLimit;const o=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),s=o[0]!==void 0?w[o[0]]:void 0;return s?s.contextLimit:G}const J=4096;function $t(u){if(!u)return J;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.maxOutput;const o=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),s=o[0]!==void 0?w[o[0]]:void 0;return s?s.maxOutput:J}function xt(u){if(!u||typeof u!="object")return;const t=u,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&o===0)return;let s=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),a=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(s===0&&a===0){const n=h(t.cache_read_input_tokens),r=h(t.cache_creation_input_tokens);n>0||r>0?(s=n,a=r+h(t.input_tokens),i=!0):(s=h(t.cache_hit_tokens),a=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(s===0&&a===0){const n=h(t.prompt_tokens_details?.cached_tokens);n>0&&(s=n,a=e>n?e-n:0,i=!0)}return{inputTokens:e,outputTokens:o,...s>0||a>0?{cacheHitTokens:s,cacheMissTokens:a}:{},...i?{hasCache:!0}:{}}}function h(...u){for(const t of u){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function z(u){return h(u.estimatedContextTokens,u.contextTokens,u.context_tokens,u.contextUsedTokens,u.context_used_tokens)}function Dt(u){return u==="stderr"||u==="mixed"?u:"stdout"}function Ot(u){if(!u||typeof u!="object"||Array.isArray(u))return;const t={};for(const[e,o]of Object.entries(u))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Et(u){return u.failed===!0}function Y(u,t,e){if(!u)return e?`${t}/${e}`:t;const o=`${t}__`;return u.startsWith(o)?N(`${t}__${u.slice(o.length)}`):N(u.replace("/","__"))}function Mt(u){return u==="read_file"||u==="edit_file"||u==="write_file"||u==="bash"}function It(u){const t=Ut(u);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof u=="string"&&u.trim().length>0}function Ut(u){if(u&&typeof u=="object"&&!Array.isArray(u))return u;if(!(typeof u!="string"||!u.trim()))try{const t=JSON.parse(u);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class se extends X{constructor(){super(),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map,L.setOnPluginsChanged(t=>{this.syncPluginCommands(t)})}async syncPluginCommands(t){try{const e=await L.getPluginCommands(t);for(const o of this.sessions.values())o.config.agentId===t&&o.runtime.addPluginCommands?.(e)}catch(e){l(`[acode-adapter] syncPluginCommands failed for agent ${t}:`,e.message)}}async startSession(t,e){const o=e.mcpConfigPath||x(),{resolved:s,configContextLimit:a,supportsImage:i}=await this.resolveAcodeProvider(e,o),n=s.model,r=a??Lt(n),d=$t(n),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:r,maxOutput:d,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,n,e,s,i),autoPollActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const c=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,c),rt(e.agentId,c);try{await m.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){p.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),q(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const o=Date.now();l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l("[ACode] \u25B6\uFE0F sendMessage STARTED"),l(`[ACode] Session: ${t}`),l(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");const s=this.requireSession(t),a=s.adapterSession.status;l(`[ACode] Previous status: ${a}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:R(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${a} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const n=Date.now();await s.runtime.submit(e);const r=Date.now()-n;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${r}ms`),l(`[ACode] Current status after submit: ${s.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${s.adapterSession.status}`);const d=Date.now()-o;l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l(`[ACode] \u2705 sendMessage COMPLETED in ${d}ms`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(n){const r=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${r}ms:`,n instanceof Error?n.message:String(n)),this.cancelSubmitTimeoutDetection(s),l("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,n,{recover:!0}),l(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}submitToolPermissionDecision(t,e,o){const s=this.sessions.get(t);if(!s)return!1;s.pendingToolAuthRequests?.delete(e);const a=s.runtime.submitToolPermissionDecision?.(e,o)??!1;return a&&this.startSubmitTimeoutDetection(t,s,"submitToolPermissionDecision"),a}getPendingToolAuthRequests(t){const e=this.sessions.get(t);return e?.pendingToolAuthRequests?Array.from(e.pendingToolAuthRequests.entries()).map(([o,s])=>({requestId:o,capability:s.capability,detail:s.detail,requestedAt:s.requestedAt})):[]}async sendQuestionAnswer(t,e){const o=this.sessions.get(t);if(!o)return;const s=o.pendingQuestionToolCallId;if(!s){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}o.pendingQuestionToolCallId=void 0,o.pendingQuestions=void 0,o.runtime.submitQuestionAnswer&&o.runtime.submitQuestionAnswer(s,e),this.startSubmitTimeoutDetection(t,o,"sendQuestionAnswer")}async abortCurrentTurn(t){await this.requireSession(t).runtime.abort()}async resetContext(t){const e=this.requireSession(t);if(this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.autoPollActive=!1,e.autoPollObservedPollingTool=!1,e.autoPollObservedAssistantText=!1,e.autoPollObservedAnyTool=!1,e.stopAutoPollAfterCurrentTurn=!1,e.idlePollLoop?.stop(),!e.runtime.resetContext)throw new Error("ACode runtime does not support context reset");await e.runtime.resetContext(),e.adapterSession.messages=[];const o=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:o.contextLimit,maxOutput:o.maxOutput,inputLimit:o.inputLimit,compactionThreshold:o.compactionThreshold,cacheHitTokens:o.cacheHitTokens,cacheMissTokens:o.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const o=e.config.agentId;o&&(q(o,this.listenerWakeHooks.get(t)),nt(o)),this.listenerWakeHooks.delete(t),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const o=e.config.mcpConfigPath||x(),{resolved:s,supportsImage:a}=await this.resolveAcodeProvider(e.config,o);return s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0}catch{return}}resolveAgentSkillsDir(t){if(t){try{const e=F(t);if(e)return e}catch(e){l(`[acode-adapter] skill farm sync failed for agent ${t}:`,e.message)}return ot(t)}return st()}async applyAgentFeatures(t){if(!t)return;const e=P(t,O),o=P(t,W);for(const[a,i]of this.sessions){if(i.config.agentId!==t)continue;const n=i.runtime;try{if(e){const r=await D(t,await this.resolveAgentAiInfo(t)),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} desktop tools hot-added for agent ${t}`)}else{const r=n.removeBuiltInToolsByPrefix?.("desktop_")??0;r>0&&l(`[acode-adapter] session ${a}: ${r} desktop tools hot-removed for agent ${t}`)}}catch(r){l(`[acode-adapter] session ${a}: desktop feature hot-sync failed for agent ${t}:`,r.message)}if(o)try{const r=await v(t,i.config.scopeKey,typeof i.config.browserAllowPrivate=="boolean"?{allowPrivate:i.config.browserAllowPrivate}:void 0),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} browser tools hot-added for agent ${t}`)}catch(r){l(`[acode-adapter] session ${a}: browser feature hot-sync failed for agent ${t}:`,r.message)}}this.syncMcpToolsForAgent(t);try{F(t)}catch(a){l(`[acode-adapter] skill farm hot-sync failed for agent ${t}:`,a.message)}try{await L.applyCapabilities(t)}catch(a){l(`[acode-adapter] plugin capability hot-sync failed for agent ${t}:`,a.message)}const s=dt(t);for(const[a,i]of this.sessions)if(i.config.agentId===t)try{i.runtime.setToolPermissionPolicy?.(s)}catch(n){l(`[acode-adapter] session ${a}: tool permission policy hot-sync failed for agent ${t}:`,n.message)}}syncMcpToolsForAgent(t){if(t){for(const[e,o]of this.sessions)if(o.config.agentId===t)try{o.runtime.requestMcpToolsRefresh?.()}catch(s){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,s.message)}}}getPendingQuestion(t){const e=this.sessions.get(t);if(e?.pendingQuestionToolCallId)return{toolCallId:e.pendingQuestionToolCallId,questions:e.pendingQuestions??[]}}cleanup(){for(const t of this.sessions.keys())this.terminateSession(t)}setIdleCommands(t,e){const o=this.sessions.get(t);if(o){if(o.idleCommands=e,this.cancelScheduledAutoPoll(o),e.idleInputCommand&&$(e.idleInputCommand)){this.getIdlePollLoop(o).start();return}o.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(o).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await V.readFile(t,"utf-8"),o=JSON.parse(e),a=o.provider?.default,i=a?.options,n=h(o.contextLimit),r={},d={},p=a?.models;if(p&&typeof p=="object"){for(const[m,c]of Object.entries(p))if(c&&typeof c=="object"){const g=h(c.contextLimit);g>0&&(r[m.trim()]=g);const f=c.modalities?.input,_=Array.isArray(f)&&f.includes("image")||c.supportsImageInput===!0;d[m.trim()]=_===!0}}return{...a?.model?{model:a.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...n>0?{contextLimit:n}:{},...Object.keys(r).length>0?{modelContextLimits:r}:{},...Object.keys(d).length>0?{modelImageSupport:d}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return E().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${o}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const o=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,s=E();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?B(t.instanceAiConfig):null,configPath:e}});const a={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...o?{model:o}:{}},i=await this.loadAcodeProviderSection(e);let n=i.contextLimit;if(!n&&i.modelContextLimits){const d=o||t.instanceAiConfig?.model||i.model;d&&i.modelContextLimits[d]&&(n=i.modelContextLimits[d])}const r=ft(a,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:B(a),globalConfigModel:i?.model??null,resolvedModel:r.model,resolvedBaseURL:r.baseURL??null,resolvedApiKey:r.apiKey?"[set]":null,configContextLimit:n,resolvedSource:r.source}}),{resolved:r,configPath:e,perSessionModel:o,configContextLimit:n,supportsImage:i.modelImageSupport?.[r.model]===!0}}async createRuntime(t,e,o,s,a){const i=await this.loadRuntimeConstructor(),n=o.mcpConfigPath||x();let r=[];try{r=await v(o.agentId,o.scopeKey,typeof o.browserAllowPrivate=="boolean"?{allowPrivate:o.browserAllowPrivate}:void 0)}catch(c){l(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,c.message)}let d=[];if(P(o.agentId??"",W)&&(d=r),o.agentId&&P(o.agentId,O))try{const c=s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0,g=await D(o.agentId,c);g.length>0&&(d=[...d,...g])}catch(c){l(`[acode-adapter] desktop tools injection skipped for agent ${o.agentId}:`,c.message)}const p=new i({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:n,skillsDir:this.resolveAgentSkillsDir(o.agentId),pluginsDir:o.agentId?et(o.agentId):void 0,model:e,systemPrompt:typeof o.systemPrompt=="string"?o.systemPrompt:void 0,globalPrompt:typeof o.globalPrompt=="string"?o.globalPrompt:void 0,rolePrompt:typeof o.rolePrompt=="string"?o.rolePrompt:void 0,memory:typeof o.memory=="string"?o.memory:void 0,env:o.envOverrides,subAgentManager:ct,terminalManager:at,pluginBridge:o.agentId?L.forAgent(o.agentId):void 0,commandDirs:[Z(new URL("../services/builtin-commands/",import.meta.url))],...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:c=>mt({...c,agentId:o.agentId,workspacePath:o.workingDirectory}),extraBuiltInTools:d,...o.agentId?{toolPermissionPolicy:lt(o.agentId)??void 0}:{},subAgentSuiteTools:r,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(o.agentId)});return E().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:o.instanceAiConfig?.model||null,perInstanceBaseURL:o.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:o.instanceAiConfig?.apiKey?"[set]":null,configPath:n}}),p.on("event",c=>this.forwardAcodeEvent(c)),p}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!P(t,O))return[];if(e.length===0)return ut();if(!e.some(a=>{const i=a.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const s=await this.resolveAgentAiInfo(t);return D(t,s)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=wt(),e=await import(Pt(t));if(!e.ACodeRuntime)throw new Error(`ACode runtime export not found: ${t}`);return this.runtimeConstructor=e.ACodeRuntime,this.runtimeConstructor}requireSession(t){const e=this.sessions.get(t);if(!e)throw new Error("ACode session not found");return e}startInitialPromptTurn(t,e){const o=this.sessions.get(t);o&&(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,o,"startInitialPromptTurn"),o.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(o),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(s=>{const a=this.sessions.get(t);a&&(this.cancelSubmitTimeoutDetection(a),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:R(),sessionId:t.sessionId,role:"assistant",content:o,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:o});return}if(t.type==="thinking_delta"){const o=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:o});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:Dt(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const o=z(t.data),s=t.data.lastUsage,a=h(s?.inputTokens),i=h(s?.outputTokens),n=h(s?.cacheHitTokens),r=h(s?.cacheMissTokens),d=!!(s&&(a>0||i>0));let p;if(d&&(a>0&&(e.adapterSession.totalUsage.inputTokens=a),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(s?.cacheHitTokens!==void 0||s?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=n,e.adapterSession.totalUsage.cacheMissTokens=r),p={...e.adapterSession.totalUsage},C(`ai_request lastUsage applied: ${JSON.stringify(s)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!d&&o>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=o,p={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const c={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};p&&(c.usage=p),C(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(p??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,c),this.startDataFlowWatchdog(t.sessionId,e),e.adapterSession.status==="thinking"&&e.watchdogSubmitStartTime&&(e.watchdogSubmitStartTime=Date.now()),this.emitProviderEvent(t,"ai_request",{model:typeof t.data.model=="string"?t.data.model:void 0,endpoint:typeof t.data.endpoint=="string"?t.data.endpoint:void 0,requestMethod:typeof t.data.requestMethod=="string"?t.data.requestMethod:void 0,requestUrl:typeof t.data.requestUrl=="string"?t.data.requestUrl:void 0,requestHeaders:Ot(t.data.requestHeaders),stream:typeof t.data.stream=="boolean"?t.data.stream:void 0,messageCount:typeof t.data.messageCount=="number"?t.data.messageCount:void 0,toolCount:typeof t.data.toolCount=="number"?t.data.toolCount:void 0,lastUserMessagePreview:typeof t.data.lastUserMessagePreview=="string"?t.data.lastUserMessagePreview:void 0,requestBody:typeof t.data.requestBody=="string"?t.data.requestBody:void 0});return}if(t.type==="turn_complete"){const o=xt(t.data.usage);if(o){const a=e.adapterSession.totalUsage.inputTokens,i=a>0&&o.inputTokens<Math.floor(a*.2)&&!o.hasCache;C(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(o)} currentInput=${a} threshold20pct=${Math.floor(a*.2)} isFallbackUsage=${i}`),i?o.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=o.outputTokens):(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens),(o.cacheHitTokens||o.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=o.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=o.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${o.cacheHitTokens||0}, miss=${o.cacheMissTokens||0})`)),C(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else C(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const s=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Et(t.data)){l(`[ACode] Recovering from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&e.autoPollActive){l(`[ACode] Recovering from aborted turn_complete (session: ${t.sessionId}), using R2 2s backoff instead of immediate rearm`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(this.cancelDataFlowWatchdog(e),this.emitProviderEvent(t,"turn_complete",{usage:e.adapterSession.totalUsage,responseBody:typeof t.data.responseBody=="string"?t.data.responseBody:void 0,finishReason:typeof t.data.finishReason=="string"?t.data.finishReason:void 0}),e.adapterSession.status="waiting_input",this.emit("status-change",t.sessionId,"waiting_input",{usage:e.adapterSession.totalUsage}),C(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",s=Array.isArray(t.data.questions)?t.data.questions:[];o&&(e.pendingQuestionToolCallId=o,e.pendingQuestions=s),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:o||void 0,questions:s});return}if(t.type==="tool_permission_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.requestId=="string"?t.data.requestId:"";o&&(e.pendingToolAuthRequests||(e.pendingToolAuthRequests=new Map),e.pendingToolAuthRequests.set(o,{capability:String(t.data.capability||""),detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation},requestedAt:Date.now()})),this.emit("tool-permission-request",{sessionId:t.sessionId,requestId:o,capability:String(t.data.capability||""),agentId:e.config.agentId,detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation}});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>pt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const A=Array.isArray(t.data.servers)?t.data.servers:[],y=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),b={kind:"mcp",mcpServers:A,mcpTools:y};e.cachedMcpCapabilities=b,e.lastMcpCapabilities=b,e.lastCombinedCapabilities={kind:"combined",mcpServers:A,mcpTools:y,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${A.length} servers, ${y.length} tools`,{sessionId:t.sessionId,servers:A,toolNames:y.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const k={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:k,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(k)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${Q}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},Q);return}const o=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${o}, server=${typeof t.data.server=="string"?t.data.server:"?"}, tool=${typeof t.data.tool=="string"?t.data.tool:"?"}, toolUseId=${typeof t.data.toolUseId=="string"?t.data.toolUseId.slice(0,16)+"\u2026":"none"}, failed=${t.data.failed===!0}, session=${t.sessionId}, status=${e.adapterSession.status}`);const s=typeof t.data.server=="string"?t.data.server:"mcp",a=typeof t.data.tool=="string"?t.data.tool:"",i=s&&a?`${s}__${a}`:a||s,n=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,r=ht(i,n);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,r.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const d=Mt(r.actionType)?r.actionDetail||Y(void 0,s,a):Y(r.actionDetail,s,a),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=n?JSON.stringify(n,null,2):void 0,c={toolName:d,rawToolName:i,actionType:r.actionType,actionLabel:r.actionLabel,actionDetail:d,...m?{actionInput:m}:{},...n?{toolInput:n}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...c,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=r.actionType==="idle"&&!It(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,r.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const _=r.actionType==="idle";this.emit("status-change",t.sessionId,f,_||f==="thinking"?void 0:c);return}const g=r.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,r.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...c}),this.emitProviderEvent(t,"tool_use_start",c),this.emit("status-change",t.sessionId,g,c);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),a=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,n=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const c=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:c.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),r=e.cachedMcpCapabilities??e.lastMcpCapabilities,d=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:r?.mcpServers??[],mcpTools:r?.mcpTools??[],skills:s,skillsDir:a,skillGroups:n};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:p,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(p)}),e.lastCombinedCapabilities=p,l(`[cap-diag] Combined capabilities emitted ${d?"(startup merge)":"(runtime refresh)"}: ${(r?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:r?.mcpServers??[],skillsDir:a}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const o=z(t.data),s=h(t.data.contextLimit)||void 0,a=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,n=h(t.data.compactionThreshold)||void 0;let r=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,r=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,r=!0),a!==void 0&&(e.adapterSession.totalUsage.maxOutput=a,r=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,r=!0),n!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=n,r=!0),r&&this.emit("status-change",t.sessionId,e.adapterSession.status,{usage:e.adapterSession.totalUsage});return}if(t.type==="exit_plan_mode"){e.adapterSession.status="waiting_input";const o=typeof t.data.plan=="string"?t.data.plan:void 0;this.emitProviderEvent(t,"exit_plan_mode",{toolInput:t.data.toolInput&&typeof t.data.toolInput=="object"?t.data.toolInput:void 0,text:o||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:o||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const o=t.data,s=o.action,a=s==="start",i=s==="end",n=s==="phase",r=o.parentId,d=o.compactionId;let p,m;if(a){const g=String(o.sizeKB??o.sizeBeforeKB??"?"),f=String(o.messageCount??o.messageCountBefore??"?"),_=o.estimatedTokens,A=o.actualInputTokens?`input=${o.actualInputTokens}`:"",y=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",b=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",_!==void 0?m=`\u538B\u7F29\u524D: ~${_} tokens, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${y}`:"")+b:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${y}`:"")+b}else if(n)p=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(o.phaseDetail??"");else{const g=o.tokensBefore,f=o.tokensAfter,_=o.freedTokens,A=String(o.sizeBeforeKB??"?"),y=String(o.sizeAfterKB??"?"),b=String(o.freedKB??"?"),T=String(o.strategy??"?"),k=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${_??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):m=`\u91CA\u653E: ${b}KB, ${A}KB \u2192 ${y}KB, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}a&&(e.adapterSession.status="compacting");const c={actionType:"context_compaction",actionLabel:p,actionDetail:m};if(a&&d)c.actionId=d;else if((n||i)&&d)if(c.parentId=d,n){const g=String(o.phase??"unknown");c.actionId=`${d}-phase-${g}`}else c.actionId=`${d}-end`;n&&r&&!c.parentId&&(c.parentId=r),i&&(e.adapterSession.totalUsage.inputTokens=h(o.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,e.config.agentId&&L.markAgentCompacted(e.config.agentId),c.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",c),this.emit("status-change",t.sessionId,"compacting",c);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,o){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:o})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(e.idleCommands?.idleInputCommand){this.getIdlePollLoop(e).start();return}this.scheduleAutoPoll(t)}}getIdlePollLoop(t){if(t.idlePollLoop)return t.idlePollLoop;const e=t.adapterSession.sessionId;return t.idlePollLoop=new gt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>$(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,s)=>this.submitAutoPollPrompt(e,s?o:Ct,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.submitAutoPollPrompt(e,o)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const a=(s.autoPollToken??0)+1;s.autoPollToken=a,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,s.autoPollQueuedAt=Date.now(),s.autoPollLastActivityAt=Date.now(),s.idleToolActiveAt=void 0,o?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,s,"submitAutoPollPrompt"),s.runtime.submit(e).catch(i=>{this.emitRuntimeError(t,i)}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==a){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${a}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=bt){const o=this.sessions.get(t);!o||o.autoPollActive||o.autoPollTimer||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=setTimeout(()=>{const s=this.sessions.get(t);!s||s.autoPollActive||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=void 0,this.submitAutoPollPrompt(t,H,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeError(t,e,o){const s=this.sessions.get(t);s&&(s.adapterSession.status="error",this.emitRuntimeErrorEvent(t,e),this.emit("status-change",t,"error"),o?.recover&&this.recoverTurnFailure(t,s))}emitRuntimeErrorEvent(t,e){const o=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:o,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(o=>o.role==="assistant").map(o=>o.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.pendingToolAuthRequests?.size&&e.pendingToolAuthRequests.clear(),e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const n=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${n.toolName??"unknown"}) \u5173\u95ED\u65F6\u95F4\u7EBF\u6761\u76EE\uFF0C\u907F\u514D\u6C38\u4E45\u5361\u5728\u5DE5\u5177\u6267\u884C\u72B6\u6001`),this.emit("event",{type:"tool_use_end",sessionId:t,timestamp:new Date().toISOString(),data:{...n,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const o=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(o>0){const n=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${n} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&$(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;if(e.autoPollTimer||e.failedTurnRecoveryScheduled){e.adapterSession.status!=="waiting_input"&&(e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}));return}this.cancelScheduledAutoPoll(e),e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}),e.failedTurnRecoveryScheduled=!0,e.autoPollTimer=setTimeout(()=>{const n=this.sessions.get(t);if(!n||n.autoPollActive||this.isTerminalStatus(n.adapterSession.status)){n&&(n.failedTurnRecoveryScheduled=!1);return}n.autoPollTimer=void 0,n.failedTurnRecoveryScheduled=!1,n.idleCommands?.idleInputCommand?this.getIdlePollLoop(n).start():this.submitAutoPollPrompt(t,H,{keepWaitingStatus:!0})},kt)}recoverResolvedTurnWithoutTerminalEvent(t){l(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){l(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(l(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){l(`[ACode] Skipping recovery: status is ${e.adapterSession.status} (not thinking/tool_using)`);return}console.warn(`[ACode] \u26A0\uFE0F Detected stuck state: ${e.adapterSession.status} after submit resolved! Recovering to waiting_input. If runtime.submit() is still pending (e.g., built-in tool execution not interruptible by abort()), the submitQueue is deadlocked and subsequent auto-poll/user submits will never execute.`),l("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,a=!!(o&&$(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",a),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,o){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const s=this.sessions.get(t);if(!s){this.cancelSubmitTimeoutDetection(e);return}const a=s.adapterSession.status,i=Date.now();if(a==="waiting_input"){if(s.autoPollActive&&s.autoPollLastActivityAt&&s.idleToolActiveAt===void 0&&i-s.autoPollLastActivityAt>=yt){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-s.autoPollLastActivityAt)/1e3)}s (source: ${o}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,s,o,"stuck_autopoll",i-s.autoPollLastActivityAt);return}s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(a==="tool_using"){const d=i-(s.watchdogLastDataFlowTime||i);if(d>=St){const p=String(s.pendingToolEventData?.rawToolName??"");if((s.pendingToolAuthRequests?.size??0)>0){const m=s.pendingToolAuthRequests?.size??0;console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but ${m} tool permission request(s) awaiting user decision (session: ${t}), skipping recovery`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(p.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but await_complete is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(d/1e3)}s (source: ${o}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),s.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(d/1e3)}s): detached tool ${p} to background (session: ${t}); waiting for the real tool_result to continue the turn`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,s,o,"tool_using_slow",d);return}s.watchdogSubmitStartTime=i;return}if(a!=="thinking")return;const n=i-(s.watchdogSubmitStartTime||i),r=i-(s.watchdogLastDataFlowTime||i);if(K>0&&r>=K){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(r/1e3)}s (source: ${o}, session: ${t}, status: ${a}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",r);return}if(j>0&&n>=j){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(n/1e3)}s (source: ${o}, session: ${t}, status: ${a}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",n);return}},_t)}executeWatchdogRecovery(t,e,o,s,a){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(a/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${s}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
1
+ import{EventEmitter as X}from"node:events";import V from"node:fs/promises";import U from"node:path";import{fileURLToPath as Z,pathToFileURL as tt}from"node:url";import{v4 as R}from"uuid";import{getBridgeInstancePluginsDir as et,getBridgeInstanceSkillsDir as ot,getBridgeTemplateConfigFile as x,getBridgeTemplateSkillsDir as st}from"../config.js";import{getReleasedAcodeEntryPath as it}from"../services/acode-package.js";import{syncAgentSkillFarm as F}from"../services/agent-capability-sync.js";import{agentPtyManager as at}from"../services/agent-pty-manager.js";import{getBrowserTools as v,closeBrowserSession as nt,registerListenerWakeHook as rt,unregisterListenerWakeHook as q}from"../services/browser-session-manager.js";import{getDesktopTools as D,getDesktopToolsIfReady as ut}from"../services/desktop-mcp-manager.js";import{redactForLog as B}from"../services/instance-ai-config-service.js";import{BROWSER_FEATURE_KEY as W,DESKTOP_FEATURE_KEY as O,getAgentToolPermissions as lt,isFeatureEnabled as P,resolveAgentToolPermissions as dt}from"../services/instance-features.js";import{pluginManager as L}from"../services/plugin-manager.js";import{subAgentManager as ct}from"../services/sub-agent-manager-instance.js";import{recordAgentFileChange as mt}from"../services/workspaceTaskChangeWatcher.js";import{getInstanceAiConfigDebugLogger as E}from"../utils/instance-ai-config-debug-logger.js";import{isMessagePollingIdleCommand as $,isPollMessageToolDescriptor as pt}from"./acode-tool-names.js";import{IdlePollLoop as gt}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as ft}from"./prompts.js";import{resolveAcodeProviderConfig as ht}from"./instance-ai-config-resolver.js";import{getCanonicalMcpDetail as N,getToolActionInfo as Tt}from"./types.js";const At=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...u){At&&console.log(...u)}const _t=process.env.ACODE_TOKEN_DEBUG==="1";function C(...u){_t&&console.log("[TokenDebug][Adapter]",...u)}const H=["Continue the AgentsWork message loop now.","You MUST call the exact MCP tool named aws-mcp__poll_message as your next action and wait for the next assigned message or task.","Do not answer in plain text before calling aws-mcp__poll_message.","After handling any received work, reply through the appropriate aws-mcp messaging tool, then continue listening again."].join(" "),St=5e3;function M(u,t){const e=process.env[u];if(e===void 0||e.trim()==="")return t;const o=Number(e.trim());return Number.isFinite(o)&&o>=0?Math.floor(o):t}const K=M("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),yt=5*6e4,bt=M("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),kt=250,Ct=2e3,j=M("ACODE_SUBMIT_TIMEOUT_MS",12e4),Q=3e3,wt=ft;function Pt(){return U.resolve(it())}function Lt(u){return tt(U.resolve(u)).href}const G=128e3,w={"claude-4":{contextLimit:2e5,maxOutput:8192},"claude-sonnet-4":{contextLimit:2e5,maxOutput:8192},"claude-3-5-sonnet":{contextLimit:2e5,maxOutput:8192},"claude-3-opus":{contextLimit:2e5,maxOutput:8192},"claude-3-haiku":{contextLimit:2e5,maxOutput:8192},"claude-2":{contextLimit:1e5,maxOutput:4096},"gpt-4o":{contextLimit:128e3,maxOutput:16384},"gpt-4-turbo":{contextLimit:128e3,maxOutput:4096},"gpt-4":{contextLimit:8192,maxOutput:4096},"gpt-3.5-turbo":{contextLimit:16384,maxOutput:4096},o1:{contextLimit:2e5,maxOutput:1e5},"o3-mini":{contextLimit:2e5,maxOutput:1e5},"gemini-2.0-flash":{contextLimit:1048576,maxOutput:8192},"gemini-2.5-pro":{contextLimit:1048576,maxOutput:8192},"gemini-1.5-pro":{contextLimit:2097152,maxOutput:8192},"gemini-1.5-flash":{contextLimit:1048576,maxOutput:8192},deepseek:{contextLimit:64e3,maxOutput:8192},"deepseek-chat":{contextLimit:64e3,maxOutput:8192},"deepseek-reasoner":{contextLimit:64e3,maxOutput:8192},"qwen-max":{contextLimit:32e3,maxOutput:8192},"qwen-plus":{contextLimit:128e3,maxOutput:8192},"qwen-turbo":{contextLimit:1e6,maxOutput:8192},"glm-4":{contextLimit:128e3,maxOutput:4096},"yi-":{contextLimit:2e5,maxOutput:4096},"llama-3":{contextLimit:8192,maxOutput:4096},"llama-2":{contextLimit:4096,maxOutput:4096},mistral:{contextLimit:32e3,maxOutput:4096},mixtral:{contextLimit:32e3,maxOutput:4096},codestral:{contextLimit:256e3,maxOutput:8192},grok:{contextLimit:131072,maxOutput:4096},"nova-":{contextLimit:2e5,maxOutput:8192}};function $t(u){if(!u)return G;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.contextLimit;const o=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),s=o[0]!==void 0?w[o[0]]:void 0;return s?s.contextLimit:G}const J=4096;function xt(u){if(!u)return J;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.maxOutput;const o=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),s=o[0]!==void 0?w[o[0]]:void 0;return s?s.maxOutput:J}function Dt(u){if(!u||typeof u!="object")return;const t=u,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&o===0)return;let s=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),a=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(s===0&&a===0){const n=h(t.cache_read_input_tokens),r=h(t.cache_creation_input_tokens);n>0||r>0?(s=n,a=r+h(t.input_tokens),i=!0):(s=h(t.cache_hit_tokens),a=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(s===0&&a===0){const n=h(t.prompt_tokens_details?.cached_tokens);n>0&&(s=n,a=e>n?e-n:0,i=!0)}return{inputTokens:e,outputTokens:o,...s>0||a>0?{cacheHitTokens:s,cacheMissTokens:a}:{},...i?{hasCache:!0}:{}}}function h(...u){for(const t of u){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function z(u){return h(u.estimatedContextTokens,u.contextTokens,u.context_tokens,u.contextUsedTokens,u.context_used_tokens)}function Ot(u){return u==="stderr"||u==="mixed"?u:"stdout"}function Et(u){if(!u||typeof u!="object"||Array.isArray(u))return;const t={};for(const[e,o]of Object.entries(u))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Mt(u){return u.failed===!0}function Y(u,t,e){if(!u)return e?`${t}/${e}`:t;const o=`${t}__`;return u.startsWith(o)?N(`${t}__${u.slice(o.length)}`):N(u.replace("/","__"))}function It(u){return u==="read_file"||u==="edit_file"||u==="write_file"||u==="bash"}function Ut(u){const t=Rt(u);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof u=="string"&&u.trim().length>0}function Rt(u){if(u&&typeof u=="object"&&!Array.isArray(u))return u;if(!(typeof u!="string"||!u.trim()))try{const t=JSON.parse(u);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class ae extends X{constructor(){super(),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map,L.setOnPluginsChanged(t=>{this.syncPluginCommands(t)})}async syncPluginCommands(t){try{const e=await L.getPluginCommands(t);for(const o of this.sessions.values())o.config.agentId===t&&o.runtime.addPluginCommands?.(e)}catch(e){l(`[acode-adapter] syncPluginCommands failed for agent ${t}:`,e.message)}}async startSession(t,e){const o=e.mcpConfigPath||x(),{resolved:s,configContextLimit:a,supportsImage:i}=await this.resolveAcodeProvider(e,o),n=s.model,r=a??$t(n),d=xt(n),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:r,maxOutput:d,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,n,e,s,i),autoPollActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const c=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,c),rt(e.agentId,c);try{await m.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){p.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),q(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const o=Date.now();l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l("[ACode] \u25B6\uFE0F sendMessage STARTED"),l(`[ACode] Session: ${t}`),l(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");const s=this.requireSession(t),a=s.adapterSession.status;l(`[ACode] Previous status: ${a}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:R(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${a} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const n=Date.now();await s.runtime.submit(e);const r=Date.now()-n;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${r}ms`),l(`[ACode] Current status after submit: ${s.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${s.adapterSession.status}`);const d=Date.now()-o;l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l(`[ACode] \u2705 sendMessage COMPLETED in ${d}ms`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(n){const r=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${r}ms:`,n instanceof Error?n.message:String(n)),this.cancelSubmitTimeoutDetection(s),l("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,n,{recover:!0}),l(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}submitToolPermissionDecision(t,e,o){const s=this.sessions.get(t);if(!s)return!1;s.pendingToolAuthRequests?.delete(e);const a=s.runtime.submitToolPermissionDecision?.(e,o)??!1;return a&&this.startSubmitTimeoutDetection(t,s,"submitToolPermissionDecision"),a}getPendingToolAuthRequests(t){const e=this.sessions.get(t);return e?.pendingToolAuthRequests?Array.from(e.pendingToolAuthRequests.entries()).map(([o,s])=>({requestId:o,capability:s.capability,detail:s.detail,requestedAt:s.requestedAt})):[]}async sendQuestionAnswer(t,e){const o=this.sessions.get(t);if(!o)return;const s=o.pendingQuestionToolCallId;if(!s){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}o.pendingQuestionToolCallId=void 0,o.pendingQuestions=void 0,o.runtime.submitQuestionAnswer&&o.runtime.submitQuestionAnswer(s,e),this.startSubmitTimeoutDetection(t,o,"sendQuestionAnswer")}async abortCurrentTurn(t){await this.requireSession(t).runtime.abort()}async resetContext(t){const e=this.requireSession(t);if(this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.autoPollActive=!1,e.autoPollObservedPollingTool=!1,e.autoPollObservedAssistantText=!1,e.autoPollObservedAnyTool=!1,e.stopAutoPollAfterCurrentTurn=!1,e.idlePollLoop?.stop(),!e.runtime.resetContext)throw new Error("ACode runtime does not support context reset");await e.runtime.resetContext(),e.adapterSession.messages=[];const o=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:o.contextLimit,maxOutput:o.maxOutput,inputLimit:o.inputLimit,compactionThreshold:o.compactionThreshold,cacheHitTokens:o.cacheHitTokens,cacheMissTokens:o.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const o=e.config.agentId;o&&(q(o,this.listenerWakeHooks.get(t)),nt(o)),this.listenerWakeHooks.delete(t),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const o=e.config.mcpConfigPath||x(),{resolved:s,supportsImage:a}=await this.resolveAcodeProvider(e.config,o);return s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0}catch{return}}resolveAgentSkillsDir(t){if(t){try{const e=F(t);if(e)return e}catch(e){l(`[acode-adapter] skill farm sync failed for agent ${t}:`,e.message)}return ot(t)}return st()}async applyAgentFeatures(t){if(!t)return;const e=P(t,O),o=P(t,W);for(const[a,i]of this.sessions){if(i.config.agentId!==t)continue;const n=i.runtime;try{if(e){const r=await D(t,await this.resolveAgentAiInfo(t)),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} desktop tools hot-added for agent ${t}`)}else{const r=n.removeBuiltInToolsByPrefix?.("desktop_")??0;r>0&&l(`[acode-adapter] session ${a}: ${r} desktop tools hot-removed for agent ${t}`)}}catch(r){l(`[acode-adapter] session ${a}: desktop feature hot-sync failed for agent ${t}:`,r.message)}if(o)try{const r=await v(t,i.config.scopeKey,typeof i.config.browserAllowPrivate=="boolean"?{allowPrivate:i.config.browserAllowPrivate}:void 0),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} browser tools hot-added for agent ${t}`)}catch(r){l(`[acode-adapter] session ${a}: browser feature hot-sync failed for agent ${t}:`,r.message)}}this.syncMcpToolsForAgent(t);try{F(t)}catch(a){l(`[acode-adapter] skill farm hot-sync failed for agent ${t}:`,a.message)}try{await L.applyCapabilities(t)}catch(a){l(`[acode-adapter] plugin capability hot-sync failed for agent ${t}:`,a.message)}const s=dt(t);for(const[a,i]of this.sessions)if(i.config.agentId===t)try{i.runtime.setToolPermissionPolicy?.(s)}catch(n){l(`[acode-adapter] session ${a}: tool permission policy hot-sync failed for agent ${t}:`,n.message)}}syncMcpToolsForAgent(t){if(t){for(const[e,o]of this.sessions)if(o.config.agentId===t)try{o.runtime.requestMcpToolsRefresh?.()}catch(s){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,s.message)}}}getPendingQuestion(t){const e=this.sessions.get(t);if(e?.pendingQuestionToolCallId)return{toolCallId:e.pendingQuestionToolCallId,questions:e.pendingQuestions??[]}}cleanup(){for(const t of this.sessions.keys())this.terminateSession(t)}setIdleCommands(t,e){const o=this.sessions.get(t);if(o){if(o.idleCommands=e,this.cancelScheduledAutoPoll(o),e.idleInputCommand&&$(e.idleInputCommand)){this.getIdlePollLoop(o).start();return}o.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(o).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await V.readFile(t,"utf-8"),o=JSON.parse(e),a=o.provider?.default,i=a?.options,n=h(o.contextLimit),r={},d={},p=a?.models;if(p&&typeof p=="object"){for(const[m,c]of Object.entries(p))if(c&&typeof c=="object"){const g=h(c.contextLimit);g>0&&(r[m.trim()]=g);const f=c.modalities?.input,_=Array.isArray(f)&&f.includes("image")||c.supportsImageInput===!0;d[m.trim()]=_===!0}}return{...a?.model?{model:a.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...n>0?{contextLimit:n}:{},...Object.keys(r).length>0?{modelContextLimits:r}:{},...Object.keys(d).length>0?{modelImageSupport:d}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return E().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${o}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const o=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,s=E();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?B(t.instanceAiConfig):null,configPath:e}});const a={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...o?{model:o}:{}},i=await this.loadAcodeProviderSection(e);let n=i.contextLimit;if(!n&&i.modelContextLimits){const d=o||t.instanceAiConfig?.model||i.model;d&&i.modelContextLimits[d]&&(n=i.modelContextLimits[d])}const r=ht(a,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:B(a),globalConfigModel:i?.model??null,resolvedModel:r.model,resolvedBaseURL:r.baseURL??null,resolvedApiKey:r.apiKey?"[set]":null,configContextLimit:n,resolvedSource:r.source}}),{resolved:r,configPath:e,perSessionModel:o,configContextLimit:n,supportsImage:i.modelImageSupport?.[r.model]===!0}}async createRuntime(t,e,o,s,a){const i=await this.loadRuntimeConstructor(),n=o.mcpConfigPath||x();let r=[];try{r=await v(o.agentId,o.scopeKey,typeof o.browserAllowPrivate=="boolean"?{allowPrivate:o.browserAllowPrivate}:void 0)}catch(c){l(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,c.message)}let d=[];if(P(o.agentId??"",W)&&(d=r),o.agentId&&P(o.agentId,O))try{const c=s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0,g=await D(o.agentId,c);g.length>0&&(d=[...d,...g])}catch(c){l(`[acode-adapter] desktop tools injection skipped for agent ${o.agentId}:`,c.message)}const p=new i({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:n,skillsDir:this.resolveAgentSkillsDir(o.agentId),pluginsDir:o.agentId?et(o.agentId):void 0,model:e,systemPrompt:typeof o.systemPrompt=="string"?o.systemPrompt:void 0,globalPrompt:typeof o.globalPrompt=="string"?o.globalPrompt:void 0,rolePrompt:typeof o.rolePrompt=="string"?o.rolePrompt:void 0,memory:typeof o.memory=="string"?o.memory:void 0,env:o.envOverrides,subAgentManager:ct,terminalManager:at,pluginBridge:o.agentId?L.forAgent(o.agentId):void 0,commandDirs:[Z(new URL("../services/builtin-commands/",import.meta.url))],...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:c=>mt({...c,agentId:o.agentId,workspacePath:o.workingDirectory}),extraBuiltInTools:d,...o.agentId?{toolPermissionPolicy:lt(o.agentId)??void 0}:{},subAgentSuiteTools:r,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(o.agentId)});return E().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:o.instanceAiConfig?.model||null,perInstanceBaseURL:o.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:o.instanceAiConfig?.apiKey?"[set]":null,configPath:n}}),p.on("event",c=>this.forwardAcodeEvent(c)),p}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!P(t,O))return[];if(e.length===0)return ut();if(!e.some(a=>{const i=a.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const s=await this.resolveAgentAiInfo(t);return D(t,s)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=Pt(),e=await import(Lt(t));if(!e.ACodeRuntime)throw new Error(`ACode runtime export not found: ${t}`);return this.runtimeConstructor=e.ACodeRuntime,this.runtimeConstructor}requireSession(t){const e=this.sessions.get(t);if(!e)throw new Error("ACode session not found");return e}startInitialPromptTurn(t,e){const o=this.sessions.get(t);o&&(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,o,"startInitialPromptTurn"),o.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(o),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(s=>{const a=this.sessions.get(t);a&&(this.cancelSubmitTimeoutDetection(a),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:R(),sessionId:t.sessionId,role:"assistant",content:o,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:o});return}if(t.type==="thinking_delta"){const o=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:o});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:Ot(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const o=z(t.data),s=t.data.lastUsage,a=h(s?.inputTokens),i=h(s?.outputTokens),n=h(s?.cacheHitTokens),r=h(s?.cacheMissTokens),d=!!(s&&(a>0||i>0));let p;if(d&&(a>0&&(e.adapterSession.totalUsage.inputTokens=a),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(s?.cacheHitTokens!==void 0||s?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=n,e.adapterSession.totalUsage.cacheMissTokens=r),p={...e.adapterSession.totalUsage},C(`ai_request lastUsage applied: ${JSON.stringify(s)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!d&&o>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=o,p={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const c={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};p&&(c.usage=p),C(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(p??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,c),this.startDataFlowWatchdog(t.sessionId,e),e.adapterSession.status==="thinking"&&e.watchdogSubmitStartTime&&(e.watchdogSubmitStartTime=Date.now()),this.emitProviderEvent(t,"ai_request",{model:typeof t.data.model=="string"?t.data.model:void 0,endpoint:typeof t.data.endpoint=="string"?t.data.endpoint:void 0,requestMethod:typeof t.data.requestMethod=="string"?t.data.requestMethod:void 0,requestUrl:typeof t.data.requestUrl=="string"?t.data.requestUrl:void 0,requestHeaders:Et(t.data.requestHeaders),stream:typeof t.data.stream=="boolean"?t.data.stream:void 0,messageCount:typeof t.data.messageCount=="number"?t.data.messageCount:void 0,toolCount:typeof t.data.toolCount=="number"?t.data.toolCount:void 0,lastUserMessagePreview:typeof t.data.lastUserMessagePreview=="string"?t.data.lastUserMessagePreview:void 0,requestBody:typeof t.data.requestBody=="string"?t.data.requestBody:void 0});return}if(t.type==="turn_complete"){const o=Dt(t.data.usage);if(o){const a=e.adapterSession.totalUsage.inputTokens,i=a>0&&o.inputTokens<Math.floor(a*.2)&&!o.hasCache;C(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(o)} currentInput=${a} threshold20pct=${Math.floor(a*.2)} isFallbackUsage=${i}`),i?o.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=o.outputTokens):(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens),(o.cacheHitTokens||o.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=o.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=o.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${o.cacheHitTokens||0}, miss=${o.cacheMissTokens||0})`)),C(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else C(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const s=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Mt(t.data)){l(`[ACode] Recovering from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&e.autoPollActive){l(`[ACode] Recovering from aborted turn_complete (session: ${t.sessionId}), using R2 2s backoff instead of immediate rearm`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(this.cancelDataFlowWatchdog(e),this.emitProviderEvent(t,"turn_complete",{usage:e.adapterSession.totalUsage,responseBody:typeof t.data.responseBody=="string"?t.data.responseBody:void 0,finishReason:typeof t.data.finishReason=="string"?t.data.finishReason:void 0}),e.adapterSession.status="waiting_input",this.emit("status-change",t.sessionId,"waiting_input",{usage:e.adapterSession.totalUsage}),C(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",s=Array.isArray(t.data.questions)?t.data.questions:[];o&&(e.pendingQuestionToolCallId=o,e.pendingQuestions=s),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:o||void 0,questions:s});return}if(t.type==="tool_permission_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.requestId=="string"?t.data.requestId:"";o&&(e.pendingToolAuthRequests||(e.pendingToolAuthRequests=new Map),e.pendingToolAuthRequests.set(o,{capability:String(t.data.capability||""),detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation},requestedAt:Date.now()})),this.emit("tool-permission-request",{sessionId:t.sessionId,requestId:o,capability:String(t.data.capability||""),agentId:e.config.agentId,detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation}});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>pt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const A=Array.isArray(t.data.servers)?t.data.servers:[],y=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),b={kind:"mcp",mcpServers:A,mcpTools:y};e.cachedMcpCapabilities=b,e.lastMcpCapabilities=b,e.lastCombinedCapabilities={kind:"combined",mcpServers:A,mcpTools:y,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${A.length} servers, ${y.length} tools`,{sessionId:t.sessionId,servers:A,toolNames:y.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const k={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:k,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(k)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${Q}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},Q);return}const o=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${o}, server=${typeof t.data.server=="string"?t.data.server:"?"}, tool=${typeof t.data.tool=="string"?t.data.tool:"?"}, toolUseId=${typeof t.data.toolUseId=="string"?t.data.toolUseId.slice(0,16)+"\u2026":"none"}, failed=${t.data.failed===!0}, session=${t.sessionId}, status=${e.adapterSession.status}`);const s=typeof t.data.server=="string"?t.data.server:"mcp",a=typeof t.data.tool=="string"?t.data.tool:"",i=s&&a?`${s}__${a}`:a||s,n=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,r=Tt(i,n);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,r.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const d=It(r.actionType)?r.actionDetail||Y(void 0,s,a):Y(r.actionDetail,s,a),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=n?JSON.stringify(n,null,2):void 0,c={toolName:d,rawToolName:i,actionType:r.actionType,actionLabel:r.actionLabel,actionDetail:d,...m?{actionInput:m}:{},...n?{toolInput:n}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...c,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=r.actionType==="idle"&&!Ut(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,r.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const _=r.actionType==="idle";this.emit("status-change",t.sessionId,f,_||f==="thinking"?void 0:c);return}const g=r.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,r.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...c}),this.emitProviderEvent(t,"tool_use_start",c),this.emit("status-change",t.sessionId,g,c);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),a=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,n=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const c=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:c.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),r=e.cachedMcpCapabilities??e.lastMcpCapabilities,d=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:r?.mcpServers??[],mcpTools:r?.mcpTools??[],skills:s,skillsDir:a,skillGroups:n};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:p,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(p)}),e.lastCombinedCapabilities=p,l(`[cap-diag] Combined capabilities emitted ${d?"(startup merge)":"(runtime refresh)"}: ${(r?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:r?.mcpServers??[],skillsDir:a}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const o=z(t.data),s=h(t.data.contextLimit)||void 0,a=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,n=h(t.data.compactionThreshold)||void 0;let r=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,r=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,r=!0),a!==void 0&&(e.adapterSession.totalUsage.maxOutput=a,r=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,r=!0),n!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=n,r=!0),r&&this.emit("status-change",t.sessionId,e.adapterSession.status,{usage:e.adapterSession.totalUsage});return}if(t.type==="exit_plan_mode"){e.adapterSession.status="waiting_input";const o=typeof t.data.plan=="string"?t.data.plan:void 0;this.emitProviderEvent(t,"exit_plan_mode",{toolInput:t.data.toolInput&&typeof t.data.toolInput=="object"?t.data.toolInput:void 0,text:o||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:o||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const o=t.data,s=o.action,a=s==="start",i=s==="end",n=s==="phase",r=o.parentId,d=o.compactionId;let p,m;if(a){const g=String(o.sizeKB??o.sizeBeforeKB??"?"),f=String(o.messageCount??o.messageCountBefore??"?"),_=o.estimatedTokens,A=o.actualInputTokens?`input=${o.actualInputTokens}`:"",y=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",b=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",_!==void 0?m=`\u538B\u7F29\u524D: ~${_} tokens, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${y}`:"")+b:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${y}`:"")+b}else if(n)p=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(o.phaseDetail??"");else{const g=o.tokensBefore,f=o.tokensAfter,_=o.freedTokens,A=String(o.sizeBeforeKB??"?"),y=String(o.sizeAfterKB??"?"),b=String(o.freedKB??"?"),T=String(o.strategy??"?"),k=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${_??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):m=`\u91CA\u653E: ${b}KB, ${A}KB \u2192 ${y}KB, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}a&&(e.adapterSession.status="compacting");const c={actionType:"context_compaction",actionLabel:p,actionDetail:m};if(a&&d)c.actionId=d;else if((n||i)&&d)if(c.parentId=d,n){const g=String(o.phase??"unknown");c.actionId=`${d}-phase-${g}`}else c.actionId=`${d}-end`;n&&r&&!c.parentId&&(c.parentId=r),i&&(e.adapterSession.totalUsage.inputTokens=h(o.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,e.config.agentId&&L.markAgentCompacted(e.config.agentId),c.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",c),this.emit("status-change",t.sessionId,"compacting",c);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,o){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:o})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(e.idleCommands?.idleInputCommand){this.getIdlePollLoop(e).start();return}this.scheduleAutoPoll(t)}}getIdlePollLoop(t){if(t.idlePollLoop)return t.idlePollLoop;const e=t.adapterSession.sessionId;return t.idlePollLoop=new gt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>$(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,s)=>this.submitAutoPollPrompt(e,s?o:wt,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.submitAutoPollPrompt(e,o)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const a=(s.autoPollToken??0)+1;s.autoPollToken=a,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,s.autoPollQueuedAt=Date.now(),s.autoPollLastActivityAt=Date.now(),s.idleToolActiveAt=void 0,o?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,s,"submitAutoPollPrompt"),s.runtime.submit(e).catch(i=>{this.emitRuntimeError(t,i)}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==a){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${a}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=kt){const o=this.sessions.get(t);!o||o.autoPollActive||o.autoPollTimer||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=setTimeout(()=>{const s=this.sessions.get(t);!s||s.autoPollActive||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=void 0,this.submitAutoPollPrompt(t,H,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeError(t,e,o){const s=this.sessions.get(t);s&&(s.adapterSession.status="error",this.emitRuntimeErrorEvent(t,e),this.emit("status-change",t,"error"),o?.recover&&this.recoverTurnFailure(t,s))}emitRuntimeErrorEvent(t,e){const o=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:o,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(o=>o.role==="assistant").map(o=>o.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.pendingToolAuthRequests?.size&&e.pendingToolAuthRequests.clear(),e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const n=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${n.toolName??"unknown"}) \u5173\u95ED\u65F6\u95F4\u7EBF\u6761\u76EE\uFF0C\u907F\u514D\u6C38\u4E45\u5361\u5728\u5DE5\u5177\u6267\u884C\u72B6\u6001`),this.emit("event",{type:"tool_use_end",sessionId:t,timestamp:new Date().toISOString(),data:{...n,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const o=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(o>0){const n=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${n} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&$(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;if(e.autoPollTimer||e.failedTurnRecoveryScheduled){e.adapterSession.status!=="waiting_input"&&(e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}));return}this.cancelScheduledAutoPoll(e),e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}),e.failedTurnRecoveryScheduled=!0,e.autoPollTimer=setTimeout(()=>{const n=this.sessions.get(t);if(!n||n.autoPollActive||this.isTerminalStatus(n.adapterSession.status)){n&&(n.failedTurnRecoveryScheduled=!1);return}n.autoPollTimer=void 0,n.failedTurnRecoveryScheduled=!1,n.idleCommands?.idleInputCommand?this.getIdlePollLoop(n).start():this.submitAutoPollPrompt(t,H,{keepWaitingStatus:!0})},Ct)}recoverResolvedTurnWithoutTerminalEvent(t){l(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){l(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(l(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){l(`[ACode] Skipping recovery: status is ${e.adapterSession.status} (not thinking/tool_using)`);return}console.warn(`[ACode] \u26A0\uFE0F Detected stuck state: ${e.adapterSession.status} after submit resolved! Recovering to waiting_input. If runtime.submit() is still pending (e.g., built-in tool execution not interruptible by abort()), the submitQueue is deadlocked and subsequent auto-poll/user submits will never execute.`),l("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,a=!!(o&&$(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",a),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,o){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const s=this.sessions.get(t);if(!s){this.cancelSubmitTimeoutDetection(e);return}const a=s.adapterSession.status,i=Date.now();if(a==="waiting_input"){if(s.autoPollActive&&s.autoPollLastActivityAt&&s.idleToolActiveAt===void 0&&i-s.autoPollLastActivityAt>=bt){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-s.autoPollLastActivityAt)/1e3)}s (source: ${o}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,s,o,"stuck_autopoll",i-s.autoPollLastActivityAt);return}s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(a==="tool_using"){const d=i-(s.watchdogLastDataFlowTime||i);if(d>=yt){const p=String(s.pendingToolEventData?.rawToolName??"");if((s.pendingToolAuthRequests?.size??0)>0){const m=s.pendingToolAuthRequests?.size??0;console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but ${m} tool permission request(s) awaiting user decision (session: ${t}), skipping recovery`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(p.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but await_complete is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(d/1e3)}s (source: ${o}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),s.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(d/1e3)}s): detached tool ${p} to background (session: ${t}); waiting for the real tool_result to continue the turn`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,s,o,"tool_using_slow",d);return}s.watchdogSubmitStartTime=i;return}if(a!=="thinking")return;const n=i-(s.watchdogSubmitStartTime||i),r=i-(s.watchdogLastDataFlowTime||i);if(K>0&&r>=K){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(r/1e3)}s (source: ${o}, session: ${t}, status: ${a}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",r);return}if(j>0&&n>=j){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(n/1e3)}s (source: ${o}, session: ${t}, status: ${a}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",n);return}},St)}executeWatchdogRecovery(t,e,o,s,a){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(a/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${s}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
2
2
 
3
3
  \u8BF7\u6C42\u5934:
4
4
  `,o=`
@@ -7,5 +7,5 @@ import{EventEmitter as X}from"node:events";import V from"node:fs/promises";impor
7
7
  `,a=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",n=typeof t.requestMethod=="string"?t.requestMethod:"",r=typeof t.stream=="boolean"?t.stream:void 0,d=typeof t.messageCount=="number"?t.messageCount:void 0,p=typeof t.toolCount=="number"?t.toolCount:void 0,m=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",c=[a?`\u6A21\u578B: ${a}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,n?`\u65B9\u6CD5: ${n}`:void 0,r!==void 0?`\u6D41\u5F0F: ${r?"\u662F":"\u5426"}`:void 0,d!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${d}`:void 0,p!==void 0?`\u53EF\u7528\u5DE5\u5177: ${p}`:void 0,m?`\u6700\u540E\u8BF7\u6C42: ${m}`:void 0].filter(S=>!!S),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,f=t.requestHeaders,_=f?Object.entries(f).filter(([S])=>!g.test(S)).map(([S,I])=>`${S}: ${I}`).filter(S=>S.trim().length>0):[],A=c.join(`
8
8
  `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",y=_.length>0?`${e}${_.join(`
9
9
  `)}`:"",b=typeof t.requestBody=="string"?t.requestBody:"",T=b.length>6e4?`${b.slice(0,6e4)}
10
- ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:b,k=T?`${o}${T}`:"";return`${A}${y}${k}`}}export{se as AcodeSdkAdapter,Et as isFailedAcodeTurnComplete,Pt as toAcodeEsmImportSpecifier};
10
+ ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:b,k=T?`${o}${T}`:"";return`${A}${y}${k}`}}export{ae as AcodeSdkAdapter,Mt as isFailedAcodeTurnComplete,Lt as toAcodeEsmImportSpecifier};
11
11
 
@@ -1,4 +1,4 @@
1
- import{execSync as y}from"child_process";import{EventEmitter as k}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{registerListenerWakeHook as v,unregisterListenerWakeHook as g}from"../services/browser-session-manager.js";import{importBridgeSdkPackage as _}from"../utils/sdk-package-loader.js";import{IdlePollLoop as x}from"./idle-poll-loop.js";import{getToolActionInfo as f}from"./types.js";class w{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>{if(this.queue.length>0){const t=this.queue.shift();if(t!==void 0)return Promise.resolve({value:t,done:!1})}return this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}}class E extends k{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map,this.sessionAgentIds=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const i={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};if(this.sessions.set(t,i),e.agentId&&this.sessionAgentIds.set(t,e.agentId),e.agentId){const o=()=>{this.getIdlePollLoop(t).start()};this.listenerWakeHooks.set(t,o),v(e.agentId,o)}try{const o=await this.loadSdk(),n=new AbortController;this.abortControllers.set(t,n);const s=new w;this.inputStreams.set(t,s);const a=this.buildQueryOptions(t,e,n),r=o.query({prompt:s,options:a});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){i.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};i.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);s.enqueue({type:"user",message:{role:"user",content:d}})}else i.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:i.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(o){e.agentId&&g(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const n=o instanceof Error?o.message:String(o);throw i.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${n}`}}),o}}async sendMessage(t,e){const i=this.sessions.get(t),o=this.inputStreams.get(t);if(!i||!o)throw new Error(`Session ${t} not found`);if(i.status==="error")throw new Error(`Session ${t} is in error state`);const n={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};i.messages.push(n),this.emit("conversation-message",t,n),i.status="thinking",this.emit("status-change",t,"thinking");const s=this.parseMessageContent(e);o.enqueue({type:"user",message:{role:"user",content:s}})}parseMessageContent(t){const e=[],i=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let o=0,n=i.exec(t);for(;n!==null;){if(n.index>o){const a=t.slice(o,n.index).trim();a&&e.push({type:"text",text:a})}const s=n[1].trim();s&&e.push({type:"image",source:{type:"url",url:s}}),o=n.index+n[0].length,n=i.exec(t)}if(o<t.length){const s=t.slice(o).trim();s&&e.push({type:"text",text:s})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const i=this.pendingPermissions.get(t);i&&(e?i.resolve({behavior:"allow",updatedInput:i.toolInput}):i.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const o=i.toolInput.questions;let n=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
1
+ import{execSync as y}from"child_process";import{EventEmitter as k}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{registerListenerWakeHook as v,unregisterListenerWakeHook as g}from"../services/browser-session-manager.js";import{importBridgeSdkPackage as x}from"../utils/sdk-package-loader.js";import{IdlePollLoop as _}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as w}from"./prompts.js";import{getToolActionInfo as f}from"./types.js";class C{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>{if(this.queue.length>0){const t=this.queue.shift();if(t!==void 0)return Promise.resolve({value:t,done:!1})}return this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}}class L extends k{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map,this.sessionAgentIds=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const i={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};if(this.sessions.set(t,i),e.agentId&&this.sessionAgentIds.set(t,e.agentId),e.agentId){const o=()=>{this.getIdlePollLoop(t).start()};this.listenerWakeHooks.set(t,o),v(e.agentId,o)}try{const o=await this.loadSdk(),n=new AbortController;this.abortControllers.set(t,n);const s=new C;this.inputStreams.set(t,s);const a=this.buildQueryOptions(t,e,n),r=o.query({prompt:s,options:a});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){i.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};i.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);s.enqueue({type:"user",message:{role:"user",content:d}})}else i.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:i.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(o){e.agentId&&g(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const n=o instanceof Error?o.message:String(o);throw i.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${n}`}}),o}}async sendMessage(t,e){const i=this.sessions.get(t),o=this.inputStreams.get(t);if(!i||!o)throw new Error(`Session ${t} not found`);if(i.status==="error")throw new Error(`Session ${t} is in error state`);const n={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};i.messages.push(n),this.emit("conversation-message",t,n),i.status="thinking",this.emit("status-change",t,"thinking");const s=this.parseMessageContent(e);o.enqueue({type:"user",message:{role:"user",content:s}})}parseMessageContent(t){const e=[],i=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let o=0,n=i.exec(t);for(;n!==null;){if(n.index>o){const a=t.slice(o,n.index).trim();a&&e.push({type:"text",text:a})}const s=n[1].trim();s&&e.push({type:"image",source:{type:"url",url:s}}),o=n.index+n[0].length,n=i.exec(t)}if(o<t.length){const s=t.slice(o).trim();s&&e.push({type:"text",text:s})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const i=this.pendingPermissions.get(t);i&&(e?i.resolve({behavior:"allow",updatedInput:i.toolInput}):i.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const o=i.toolInput.questions;let n=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
2
2
  `;Array.isArray(o)?o.forEach((s,a)=>{const r=String(a),l=e[r]||e[s.header||""]||e[s.question]||"\uFF08\u672A\u586B\u5199\uFF09";n+=`\u2022 ${s.header||s.question}\uFF1A${l}
3
- `}):n+=JSON.stringify(e),i.resolve({behavior:"deny",message:n}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t){const e=this.sessions.get(t),i=this.sdkQueries.get(t),o=this.inputStreams.get(t);if(o&&o.close(),i)try{i.close()}catch{}e&&(e.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}));const n=this.sessionAgentIds.get(t);n&&g(n,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const i=this.sessions.get(t);i&&i.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(!e?.idleInputCommand)return;if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now());const i=setInterval(()=>{this.checkIdleState(t)},500);this.idleTimers.set(t,i)}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearInterval(e),this.idleTimers.delete(t))}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const i=this.idleCommands.get(t);if(!i||!i.idleInputCommand&&!i.nonInputCommand)return;const o=this.lastActivityAt.get(t)||0;if(!(Date.now()-o<1500)&&(this.lastActivityAt.set(t,Date.now()),i.idleInputCommand)){const a=i.idleInputCommand;this.isMessagePollingIdleCommand(a)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,a)}}sendIdlePrompt(t,e,i){const o=this.inputStreams.get(t);if(!o)return;const n=this.sessions.get(t);n&&!i?.keepWaitingStatus&&(n.status="thinking",this.emit("status-change",t,"thinking")),o.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const i=e.toLowerCase();return i.includes("poll_message")||i.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return"\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002"}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const i=new x({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendIdlePrompt(t,n?o:this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendIdlePrompt(t,o)});return this.idlePollLoops.set(t,i),i}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const i=this.inputStreams.get(t);if(!i)return;const o=/\[(.+?)\]/g;let n=0;const s=[];let a=o.exec(e);for(;a!==null;){a.index>n&&s.push({type:"text",value:e.slice(n,a.index)});const r=a[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||s.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};s.push({type:"key",value:l[r.toLowerCase()]||r})}n=a.index+a[0].length,a=o.exec(e)}n<e.length&&s.push({type:"text",value:e.slice(n)});for(const r of s)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);i.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now())}async resumeSession(t,e,i){const o={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,o);try{await this.startSession(t,i),o.providerSessionId=e}catch(n){throw o.status="error",this.emit("status-change",t,"error"),n}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await _("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const s=this.resolveWindowsWrapper(e);if(s)return s;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const i=this.resolveExecutableFromPath(e);if(i)return i;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const s=process.env.USERPROFILE||"",a=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(a,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(a,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(a,"Programs","claude-code","claude.exe"),c.join(s,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return u}const o=process.env.HOME||"",n=[c.join(o,".local","bin","claude"),c.join(o,".npm-global","bin","claude"),c.join(o,".local","share","mise","shims","claude"),c.join(o,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(o,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(o,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const s of n)if(s&&p.existsSync(s))return s}if(this.shouldUseDefaultClaudeFallbacks(e))try{const s=y("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),a=c.join(s,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(a))return a}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const i=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return i?.[1]||i?.[2]||i?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const i=c.extname(t).length>0,o=process.platform==="win32"?this.getWindowsPathExtensions(i):[""];for(const n of e.split(c.delimiter))if(n)for(const s of o){const a=c.join(n,`${t}${s}`);if(p.existsSync(a)){if(this.isWindowsWrapperPath(a)){const r=this.resolveWindowsWrapper(a);if(r)return r;continue}return a}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(i=>i.trim()).filter(i=>i.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const n=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}const i=c.dirname(t),o=c.join(i,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(o))return o}catch{}}buildQueryOptions(t,e,i){const o={cwd:e.workingDirectory,abortController:i,settingSources:["user","project","local"],includePartialMessages:!0},n=this.findClaudeExecutable(e.command);if(n?o.pathToClaudeCodeExecutable=n:console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(o.model=e.model),e.maxTurns&&e.maxTurns>0&&(o.maxTurns=e.maxTurns),e.mcpConfigPath)try{const s=p.readFileSync(e.mcpConfigPath,"utf-8"),a=JSON.parse(s);o.mcpServers={...e.extraMcpServers,...a.mcpServers}}catch{o.mcpServers=e.extraMcpServers||{}}else o.mcpServers=e.extraMcpServers||{};return e.allowedTools&&e.allowedTools.length>0?o.allowedTools=e.allowedTools:o.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],o.env={...process.env,...e.envOverrides},o.canUseTool=this.createPermissionHandler(t,e.autoAccept),o}createPermissionHandler(t,e){return async(i,o,n)=>i==="AskUserQuestion"||i==="ask_user_question"?new Promise(s=>{this.pendingQuestions.set(t,{resolve:s,toolInput:o}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:o.questions})}):e?{behavior:"allow",updatedInput:o}:new Promise(s=>{this.pendingPermissions.set(t,{resolve:s,toolInput:o}),this.emit("permission-request",{sessionId:t,toolName:i,toolInput:o,permissionPrompt:`Allow ${i}?`})})}async consumeStream(t,e){const i=this.sessions.get(t);if(i)try{for await(const o of e){const n=o;this.handleSdkMessage(t,i,n)}}catch(o){if(this.abortControllers.get(t)?.signal.aborted)return;const n=o instanceof Error?o.message:String(o);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${n}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,i){const o=new Date().toISOString();switch(i.type){case"text":i.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:o,data:{text:i.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(i.content||i.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:o,data:{text:i.delta||i.content}});break;case"tool_use":case"tool_use_start":{const n={...f(i.tool_name,i.tool_input),actionId:i.tool_use_id},s=n.actionType==="idle"?"waiting_input":"tool_using";e.status=s;const a=this.extractMcpServerName(i.tool_name||"");this.emit("status-change",t,s,{actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:n.actionDetail,actionId:n.actionId,usage:e.totalUsage,...a?{metadata:{mcpServer:a}}:{}}),n.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,i,o)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:o,data:{toolName:i.tool_name,toolResult:i.tool_result,isError:i.is_error,toolUseId:i.tool_use_id}});break;case"result":{const n=i.subtype==="success";this.applyUsage(e,i.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:o,data:{usage:e.totalUsage,text:n?i.result:void 0}}),e.status="waiting_input",(()=>{const a=this.idleCommands.get(t);return!!(a?.idleInputCommand&&this.isMessagePollingIdleCommand(a.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":break;case"assistant":if(this.applyUsage(e,i.message?.usage),i.message?.content){const n=i.message.content.filter(s=>s.type==="text"&&s.text).map(s=>s.text||"").join("");n&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:n,timestamp:o})}break;case"user":i.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:o,data:{text:i.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,i,o);break;default:break}}handleToolUse(t,e,i,o){const n=this.recentToolNames.get(t),s=this.extractToolNameSuffix(i.tool_name||"");if(n&&Date.now()-n.time<3e4&&n.name===s){this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:o,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const a=f(i.tool_name,i.tool_input),r=this.extractMcpServerName(i.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:o,data:{toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id,actionType:a.actionType,actionLabel:a.actionLabel,actionDetail:a.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:o,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id})}handleStreamEvent(t,e,i,o){const n=i.event;if(n){if(n.type==="content_block_start"){const s=n.content_block;if(s?.type==="tool_use"&&s.name){const a=s.name,r=s.id||`stream_${Date.now()}`;this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(a);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(n.type==="content_block_delta"&&n.delta?.type==="input_json_delta"&&n.delta.partial_json){const s=this.activeToolUseIds.get(t);if(s){const a=`${t}:${s}`,r=this.toolInputBuffers.get(a)||"";this.toolInputBuffers.set(a,r+n.delta.partial_json)}}if(n.type==="content_block_stop"){const s=this.activeToolUseIds.get(t),a=this.recentToolNames.get(t);if(s&&a){const r=`${t}:${s}`,l=this.toolInputBuffers.get(r)||"";let d;if(l)try{d=JSON.parse(l)}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...f(a.name,d),actionId:s},m=this.extractMcpServerName(a.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:o,data:{toolName:a.name,toolInput:d,toolUseId:s,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${a.name}: ${l.slice(0,100)}`,timestamp:o,toolName:a.name,toolInput:d,toolUseId:s}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.sessionAgentIds.delete(t),this.lastActivityAt.delete(t)}}export{E as ClaudeSdkAdapter};
3
+ `}):n+=JSON.stringify(e),i.resolve({behavior:"deny",message:n}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t){const e=this.sessions.get(t),i=this.sdkQueries.get(t),o=this.inputStreams.get(t);if(o&&o.close(),i)try{i.close()}catch{}e&&(e.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}));const n=this.sessionAgentIds.get(t);n&&g(n,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const i=this.sessions.get(t);i&&i.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(!e?.idleInputCommand)return;if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now());const i=setInterval(()=>{this.checkIdleState(t)},500);this.idleTimers.set(t,i)}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearInterval(e),this.idleTimers.delete(t))}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const i=this.idleCommands.get(t);if(!i||!i.idleInputCommand&&!i.nonInputCommand)return;const o=this.lastActivityAt.get(t)||0;if(!(Date.now()-o<1500)&&(this.lastActivityAt.set(t,Date.now()),i.idleInputCommand)){const a=i.idleInputCommand;this.isMessagePollingIdleCommand(a)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,a)}}sendIdlePrompt(t,e,i){const o=this.inputStreams.get(t);if(!o)return;const n=this.sessions.get(t);n&&!i?.keepWaitingStatus&&(n.status="thinking",this.emit("status-change",t,"thinking")),o.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const i=e.toLowerCase();return i.includes("poll_message")||i.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return w}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const i=new _({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendIdlePrompt(t,n?o:this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendIdlePrompt(t,o)});return this.idlePollLoops.set(t,i),i}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const i=this.inputStreams.get(t);if(!i)return;const o=/\[(.+?)\]/g;let n=0;const s=[];let a=o.exec(e);for(;a!==null;){a.index>n&&s.push({type:"text",value:e.slice(n,a.index)});const r=a[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||s.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};s.push({type:"key",value:l[r.toLowerCase()]||r})}n=a.index+a[0].length,a=o.exec(e)}n<e.length&&s.push({type:"text",value:e.slice(n)});for(const r of s)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);i.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now())}async resumeSession(t,e,i){const o={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,o);try{await this.startSession(t,i),o.providerSessionId=e}catch(n){throw o.status="error",this.emit("status-change",t,"error"),n}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await x("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const s=this.resolveWindowsWrapper(e);if(s)return s;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const i=this.resolveExecutableFromPath(e);if(i)return i;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const s=process.env.USERPROFILE||"",a=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(a,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(a,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(a,"Programs","claude-code","claude.exe"),c.join(s,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return u}const o=process.env.HOME||"",n=[c.join(o,".local","bin","claude"),c.join(o,".npm-global","bin","claude"),c.join(o,".local","share","mise","shims","claude"),c.join(o,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(o,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(o,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const s of n)if(s&&p.existsSync(s))return s}if(this.shouldUseDefaultClaudeFallbacks(e))try{const s=y("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),a=c.join(s,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(a))return a}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const i=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return i?.[1]||i?.[2]||i?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const i=c.extname(t).length>0,o=process.platform==="win32"?this.getWindowsPathExtensions(i):[""];for(const n of e.split(c.delimiter))if(n)for(const s of o){const a=c.join(n,`${t}${s}`);if(p.existsSync(a)){if(this.isWindowsWrapperPath(a)){const r=this.resolveWindowsWrapper(a);if(r)return r;continue}return a}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(i=>i.trim()).filter(i=>i.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const n=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}const i=c.dirname(t),o=c.join(i,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(o))return o}catch{}}buildQueryOptions(t,e,i){const o={cwd:e.workingDirectory,abortController:i,settingSources:["user","project","local"],includePartialMessages:!0},n=this.findClaudeExecutable(e.command);if(n?o.pathToClaudeCodeExecutable=n:console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(o.model=e.model),e.maxTurns&&e.maxTurns>0&&(o.maxTurns=e.maxTurns),e.mcpConfigPath)try{const s=p.readFileSync(e.mcpConfigPath,"utf-8"),a=JSON.parse(s);o.mcpServers={...e.extraMcpServers,...a.mcpServers}}catch{o.mcpServers=e.extraMcpServers||{}}else o.mcpServers=e.extraMcpServers||{};return e.allowedTools&&e.allowedTools.length>0?o.allowedTools=e.allowedTools:o.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],o.env={...process.env,...e.envOverrides},o.canUseTool=this.createPermissionHandler(t,e.autoAccept),o}createPermissionHandler(t,e){return async(i,o,n)=>i==="AskUserQuestion"||i==="ask_user_question"?new Promise(s=>{this.pendingQuestions.set(t,{resolve:s,toolInput:o}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:o.questions})}):e?{behavior:"allow",updatedInput:o}:new Promise(s=>{this.pendingPermissions.set(t,{resolve:s,toolInput:o}),this.emit("permission-request",{sessionId:t,toolName:i,toolInput:o,permissionPrompt:`Allow ${i}?`})})}async consumeStream(t,e){const i=this.sessions.get(t);if(i)try{for await(const o of e){const n=o;this.handleSdkMessage(t,i,n)}}catch(o){if(this.abortControllers.get(t)?.signal.aborted)return;const n=o instanceof Error?o.message:String(o);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${n}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,i){const o=new Date().toISOString();switch(i.type){case"text":i.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:o,data:{text:i.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(i.content||i.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:o,data:{text:i.delta||i.content}});break;case"tool_use":case"tool_use_start":{const n={...f(i.tool_name,i.tool_input),actionId:i.tool_use_id},s=n.actionType==="idle"?"waiting_input":"tool_using";e.status=s;const a=this.extractMcpServerName(i.tool_name||"");this.emit("status-change",t,s,{actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:n.actionDetail,actionId:n.actionId,usage:e.totalUsage,...a?{metadata:{mcpServer:a}}:{}}),n.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,i,o)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:o,data:{toolName:i.tool_name,toolResult:i.tool_result,isError:i.is_error,toolUseId:i.tool_use_id}});break;case"result":{const n=i.subtype==="success";this.applyUsage(e,i.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:o,data:{usage:e.totalUsage,text:n?i.result:void 0}}),e.status="waiting_input",(()=>{const a=this.idleCommands.get(t);return!!(a?.idleInputCommand&&this.isMessagePollingIdleCommand(a.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":break;case"assistant":if(this.applyUsage(e,i.message?.usage),i.message?.content){const n=i.message.content.filter(s=>s.type==="text"&&s.text).map(s=>s.text||"").join("");n&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:n,timestamp:o})}break;case"user":i.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:o,data:{text:i.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,i,o);break;default:break}}handleToolUse(t,e,i,o){const n=this.recentToolNames.get(t),s=this.extractToolNameSuffix(i.tool_name||"");if(n&&Date.now()-n.time<3e4&&n.name===s){this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:o,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const a=f(i.tool_name,i.tool_input),r=this.extractMcpServerName(i.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:o,data:{toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id,actionType:a.actionType,actionLabel:a.actionLabel,actionDetail:a.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:o,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id})}handleStreamEvent(t,e,i,o){const n=i.event;if(n){if(n.type==="content_block_start"){const s=n.content_block;if(s?.type==="tool_use"&&s.name){const a=s.name,r=s.id||`stream_${Date.now()}`;this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(a);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(n.type==="content_block_delta"&&n.delta?.type==="input_json_delta"&&n.delta.partial_json){const s=this.activeToolUseIds.get(t);if(s){const a=`${t}:${s}`,r=this.toolInputBuffers.get(a)||"";this.toolInputBuffers.set(a,r+n.delta.partial_json)}}if(n.type==="content_block_stop"){const s=this.activeToolUseIds.get(t),a=this.recentToolNames.get(t);if(s&&a){const r=`${t}:${s}`,l=this.toolInputBuffers.get(r)||"";let d;if(l)try{d=JSON.parse(l)}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...f(a.name,d),actionId:s},m=this.extractMcpServerName(a.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:o,data:{toolName:a.name,toolInput:d,toolUseId:s,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${a.name}: ${l.slice(0,100)}`,timestamp:o,toolName:a.name,toolInput:d,toolUseId:s}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.sessionAgentIds.delete(t),this.lastActivityAt.delete(t)}}export{L as ClaudeSdkAdapter};
4
4
 
@@ -1,4 +1,4 @@
1
- import{EventEmitter as y}from"node:events";import{v4 as p}from"uuid";import{registerListenerWakeHook as _,unregisterListenerWakeHook as m}from"../services/browser-session-manager.js";import{IdlePollLoop as g}from"./idle-poll-loop.js";import{getToolActionInfo as v}from"./types.js";function E(i){return i instanceof Error&&"code"in i&&typeof i.code=="string"}function T(i,t){return E(i)&&i.code==="ERR_MODULE_NOT_FOUND"&&i.message.includes(t)}const d=1500;function f(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function D(i){return f(i)?i:{value:i}}function k(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return String(i)}}function P(i,t){const n={};for(const[e,s]of Object.entries(i))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function A(i){const t=[];let n="",e=null,s=!1;for(const a of i.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function S(i){const t=(i||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function M(i){return i.includes("/")||i.includes("\\")||/^[a-zA-Z]:/.test(i)}function w(i){const t=A(i||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=S(n);return M(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&S(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function x(i){if(/^(true|1|yes)$/i.test(i))return!0;if(/^(false|0|no)$/i.test(i))return!1}function c(i){return i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'")?i.slice(1,-1):i}function O(i,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=i;for(const l of e.slice(0,-1)){const o=s[l];f(o)||(s[l]={}),s=s[l]}const a=c(n),r=x(a);s[e[e.length-1]]=r??a}function u(i,t,n){const e=i[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:i[t+1],nextIndex:t+1}}function b(i){const t={additionalDirectories:[],config:{}};for(let n=0;n<i.length;n++){const e=i[n];switch(e){case"--model":case"-m":{const s=u(i,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(i,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(i,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(i,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const r=s.value.slice(0,a),l=s.value.slice(a+1);if(r==="model_reasoning_effort"){const o=c(l);(o==="minimal"||o==="low"||o==="medium"||o==="high"||o==="xhigh")&&(t.modelReasoningEffort=o)}else if(r==="web_search"){const o=c(l);(o==="disabled"||o==="cached"||o==="live")&&(t.webSearchMode=o)}else if(r==="sandbox_workspace_write.network_access")t.networkAccessEnabled=x(c(l));else if(r==="approval_policy"){const o=c(l);(o==="never"||o==="on-request"||o==="on-failure"||o==="untrusted")&&(t.approvalPolicy=o)}else O(t.config,r,l)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function L(i){return{inputTokens:i?.input_tokens??0,outputTokens:i?.output_tokens??0}}class H extends y{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,n){const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const r=a.startThread(this.buildThreadOptions(n)),l={adapterSession:e,config:n,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};if(this.sessions.set(t,l),n.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),_(n.agentId,o)}n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(o=>{const C=o instanceof Error?o.message:String(o),h=this.sessions.get(t);h&&(h.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${C}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){n.agentId&&m(n.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:p(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t){const n=this.sessions.get(t);n&&(this.stopIdleDetection(t),n.terminating=!0,n.currentAbortController?.abort(),n.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),n.config.agentId&&m(n.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const r=a.resumeThread(n,this.buildThreadOptions(e)),l={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:l,config:e,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw T(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
- `)):t}return this.sdkModule}buildCodexOptions(t){const n=P(process.env,t.envOverrides),e={env:n},s=n.CODEX_API_KEY||n.OPENAI_API_KEY;s&&(e.apiKey=s);const a=n.CODEX_BASE_URL||n.OPENAI_BASE_URL;a&&(e.baseUrl=a);const r=w(t.command);t.executablePath?e.codexPathOverride=t.executablePath:r.executablePath&&(e.codexPathOverride=r.executablePath);const l=b(r.args);return Object.keys(l.config).length>0&&(e.config=l.config),e}warnUnsupportedMcpConfig(t){const n=!!(t.extraMcpServers&&Object.keys(t.extraMcpServers).length>0);(t.mcpConfigPath||n)&&console.warn("[CodexSdkAdapter] Codex SDK ThreadOptions do not expose dynamic MCP server injection; mcpConfigPath/extraMcpServers are ignored for Codex SDK sessions.")}buildThreadOptions(t){const n=w(t.command),e=b(n.args),s={workingDirectory:t.workingDirectory,skipGitRepoCheck:e.skipGitRepoCheck??!1,approvalPolicy:e.approvalPolicy??(t.autoAccept?"never":"on-request")};return(t.model||e.model)&&(s.model=t.model??e.model),(t.additionalDirectories||e.additionalDirectories.length>0)&&(s.additionalDirectories=[...t.additionalDirectories??[],...e.additionalDirectories]),e.sandboxMode&&(s.sandboxMode=e.sandboxMode),e.modelReasoningEffort&&(s.modelReasoningEffort=e.modelReasoningEffort),e.networkAccessEnabled!==void 0&&(s.networkAccessEnabled=e.networkAccessEnabled),e.webSearchMode&&(s.webSearchMode=e.webSearchMode),e.webSearchEnabled!==void 0&&(s.webSearchEnabled=e.webSearchEnabled),s}async runTurn(t,n,e,s){try{const a=await n.thread.runStreamed(e,{signal:s.signal});for await(const r of a.events)this.handleThreadEvent(t,n,r)}catch(a){if(s.signal.aborted){if(!this.sessions.has(t)||n.terminating||n.adapterSession.status==="terminated")return;n.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input");return}const r=a instanceof Error?a.message:String(a);n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:r}})}}handleThreadEvent(t,n,e){const s=new Date().toISOString();switch(e.type){case"thread.started":n.adapterSession.providerSessionId=e.thread_id;break;case"turn.started":n.adapterSession.status="thinking",this.emit("status-change",t,"thinking");break;case"item.started":case"item.updated":case"item.completed":this.handleThreadItem(t,n,e.item,e.type,s);break;case"turn.completed":this.completeTurn(t,n,e.usage,s);break;case"turn.failed":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.error.message}});break;case"error":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.message}});break}}handleThreadItem(t,n,e,s,a){switch(e.type){case"agent_message":this.emitTextDelta(t,n,e.id,e.text,a);break;case"reasoning":this.emitReasoningDelta(t,n,e.id,e.text,a);break;case"command_execution":this.handleToolLikeItem(t,n,{id:e.id,toolName:"bash",toolInput:{command:e.command},result:e.aggregated_output,isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a});break;case"mcp_tool_call":{const r={mcpServer:e.server};this.handleToolLikeItem(t,n,{id:e.id,toolName:e.tool,toolInput:D(e.arguments),result:e.error?.message??k(e.result),isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a,metadata:r});break}case"file_change":this.handleToolLikeItem(t,n,{id:e.id,toolName:"apply_patch",toolInput:{changes:e.changes},result:e.status,isError:e.status==="failed",isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"web_search":this.handleToolLikeItem(t,n,{id:e.id,toolName:"web_search",toolInput:{query:e.query},result:e.query,isError:!1,isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"todo_list":this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:e.items.map(r=>`${r.completed?"\u2713":"\u2022"} ${r.text}`).join(`
3
- `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const r=n.emittedTextLengths.get(e)??0,l=s.slice(r);n.emittedTextLengths.set(e,s.length),l&&(n.currentAssistantText+=l,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:l}}))}emitReasoningDelta(t,n,e,s,a){const r=n.emittedReasoningLengths.get(e)??0,l=s.slice(r);n.emittedReasoningLengths.set(e,s.length),l&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:l}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...v(e.toolName,e.toolInput,e.metadata),actionId:e.id,actionInput:k(e.toolInput)};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:p(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=L(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:p(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const r=n.idleCommands?.idleInputCommand;!!(r&&this.isMessagePollingIdleCommand(r))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!n||!e)return;if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,r)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:r}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,r)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:r}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now();const s=setInterval(()=>{this.checkIdleState(t)},500);n.idleTimer=s}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearInterval(n.idleTimer),n.idleTimer=void 0)}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=e?.injected?n.trim():this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const r=new AbortController;s.currentAbortController=r,s.runningTurn=this.runTurn(t,s,a,r);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?"\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002":n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{H as CodexSdkAdapter};
1
+ import{EventEmitter as y}from"node:events";import{v4 as p}from"uuid";import{registerListenerWakeHook as _,unregisterListenerWakeHook as m}from"../services/browser-session-manager.js";import{IdlePollLoop as g}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as E}from"./prompts.js";import{getToolActionInfo as v}from"./types.js";function T(r){return r instanceof Error&&"code"in r&&typeof r.code=="string"}function P(r,t){return T(r)&&r.code==="ERR_MODULE_NOT_FOUND"&&r.message.includes(t)}const d=1500;function f(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function D(r){return f(r)?r:{value:r}}function k(r){if(typeof r=="string")return r;try{return JSON.stringify(r)}catch{return String(r)}}function A(r,t){const n={};for(const[e,s]of Object.entries(r))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function M(r){const t=[];let n="",e=null,s=!1;for(const a of r.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function S(r){const t=(r||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function O(r){return r.includes("/")||r.includes("\\")||/^[a-zA-Z]:/.test(r)}function w(r){const t=M(r||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=S(n);return O(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&S(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function x(r){if(/^(true|1|yes)$/i.test(r))return!0;if(/^(false|0|no)$/i.test(r))return!1}function c(r){return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function L(r,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=r;for(const l of e.slice(0,-1)){const o=s[l];f(o)||(s[l]={}),s=s[l]}const a=c(n),i=x(a);s[e[e.length-1]]=i??a}function u(r,t,n){const e=r[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:r[t+1],nextIndex:t+1}}function b(r){const t={additionalDirectories:[],config:{}};for(let n=0;n<r.length;n++){const e=r[n];switch(e){case"--model":case"-m":{const s=u(r,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(r,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(r,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(r,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const i=s.value.slice(0,a),l=s.value.slice(a+1);if(i==="model_reasoning_effort"){const o=c(l);(o==="minimal"||o==="low"||o==="medium"||o==="high"||o==="xhigh")&&(t.modelReasoningEffort=o)}else if(i==="web_search"){const o=c(l);(o==="disabled"||o==="cached"||o==="live")&&(t.webSearchMode=o)}else if(i==="sandbox_workspace_write.network_access")t.networkAccessEnabled=x(c(l));else if(i==="approval_policy"){const o=c(l);(o==="never"||o==="on-request"||o==="on-failure"||o==="untrusted")&&(t.approvalPolicy=o)}else L(t.config,i,l)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function I(r){return{inputTokens:r?.input_tokens??0,outputTokens:r?.output_tokens??0}}class K extends y{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,n){const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const i=a.startThread(this.buildThreadOptions(n)),l={adapterSession:e,config:n,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};if(this.sessions.set(t,l),n.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),_(n.agentId,o)}n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(o=>{const C=o instanceof Error?o.message:String(o),h=this.sessions.get(t);h&&(h.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${C}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){n.agentId&&m(n.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:p(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t){const n=this.sessions.get(t);n&&(this.stopIdleDetection(t),n.terminating=!0,n.currentAbortController?.abort(),n.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),n.config.agentId&&m(n.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const i=a.resumeThread(n,this.buildThreadOptions(e)),l={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:l,config:e,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw P(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
+ `)):t}return this.sdkModule}buildCodexOptions(t){const n=A(process.env,t.envOverrides),e={env:n},s=n.CODEX_API_KEY||n.OPENAI_API_KEY;s&&(e.apiKey=s);const a=n.CODEX_BASE_URL||n.OPENAI_BASE_URL;a&&(e.baseUrl=a);const i=w(t.command);t.executablePath?e.codexPathOverride=t.executablePath:i.executablePath&&(e.codexPathOverride=i.executablePath);const l=b(i.args);return Object.keys(l.config).length>0&&(e.config=l.config),e}warnUnsupportedMcpConfig(t){const n=!!(t.extraMcpServers&&Object.keys(t.extraMcpServers).length>0);(t.mcpConfigPath||n)&&console.warn("[CodexSdkAdapter] Codex SDK ThreadOptions do not expose dynamic MCP server injection; mcpConfigPath/extraMcpServers are ignored for Codex SDK sessions.")}buildThreadOptions(t){const n=w(t.command),e=b(n.args),s={workingDirectory:t.workingDirectory,skipGitRepoCheck:e.skipGitRepoCheck??!1,approvalPolicy:e.approvalPolicy??(t.autoAccept?"never":"on-request")};return(t.model||e.model)&&(s.model=t.model??e.model),(t.additionalDirectories||e.additionalDirectories.length>0)&&(s.additionalDirectories=[...t.additionalDirectories??[],...e.additionalDirectories]),e.sandboxMode&&(s.sandboxMode=e.sandboxMode),e.modelReasoningEffort&&(s.modelReasoningEffort=e.modelReasoningEffort),e.networkAccessEnabled!==void 0&&(s.networkAccessEnabled=e.networkAccessEnabled),e.webSearchMode&&(s.webSearchMode=e.webSearchMode),e.webSearchEnabled!==void 0&&(s.webSearchEnabled=e.webSearchEnabled),s}async runTurn(t,n,e,s){try{const a=await n.thread.runStreamed(e,{signal:s.signal});for await(const i of a.events)this.handleThreadEvent(t,n,i)}catch(a){if(s.signal.aborted){if(!this.sessions.has(t)||n.terminating||n.adapterSession.status==="terminated")return;n.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input");return}const i=a instanceof Error?a.message:String(a);n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:i}})}}handleThreadEvent(t,n,e){const s=new Date().toISOString();switch(e.type){case"thread.started":n.adapterSession.providerSessionId=e.thread_id;break;case"turn.started":n.adapterSession.status="thinking",this.emit("status-change",t,"thinking");break;case"item.started":case"item.updated":case"item.completed":this.handleThreadItem(t,n,e.item,e.type,s);break;case"turn.completed":this.completeTurn(t,n,e.usage,s);break;case"turn.failed":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.error.message}});break;case"error":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.message}});break}}handleThreadItem(t,n,e,s,a){switch(e.type){case"agent_message":this.emitTextDelta(t,n,e.id,e.text,a);break;case"reasoning":this.emitReasoningDelta(t,n,e.id,e.text,a);break;case"command_execution":this.handleToolLikeItem(t,n,{id:e.id,toolName:"bash",toolInput:{command:e.command},result:e.aggregated_output,isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a});break;case"mcp_tool_call":{const i={mcpServer:e.server};this.handleToolLikeItem(t,n,{id:e.id,toolName:e.tool,toolInput:D(e.arguments),result:e.error?.message??k(e.result),isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a,metadata:i});break}case"file_change":this.handleToolLikeItem(t,n,{id:e.id,toolName:"apply_patch",toolInput:{changes:e.changes},result:e.status,isError:e.status==="failed",isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"web_search":this.handleToolLikeItem(t,n,{id:e.id,toolName:"web_search",toolInput:{query:e.query},result:e.query,isError:!1,isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"todo_list":this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:e.items.map(i=>`${i.completed?"\u2713":"\u2022"} ${i.text}`).join(`
3
+ `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const i=n.emittedTextLengths.get(e)??0,l=s.slice(i);n.emittedTextLengths.set(e,s.length),l&&(n.currentAssistantText+=l,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:l}}))}emitReasoningDelta(t,n,e,s,a){const i=n.emittedReasoningLengths.get(e)??0,l=s.slice(i);n.emittedReasoningLengths.set(e,s.length),l&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:l}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...v(e.toolName,e.toolInput,e.metadata),actionId:e.id,actionInput:k(e.toolInput)};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:p(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=I(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:p(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const i=n.idleCommands?.idleInputCommand;!!(i&&this.isMessagePollingIdleCommand(i))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!n||!e)return;if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,i)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:i}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,i)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:i}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now();const s=setInterval(()=>{this.checkIdleState(t)},500);n.idleTimer=s}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearInterval(n.idleTimer),n.idleTimer=void 0)}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=e?.injected?n.trim():this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const i=new AbortController;s.currentAbortController=i,s.runningTurn=this.runTurn(t,s,a,i);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?E:n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{K as CodexSdkAdapter};
4
4
 
@@ -1,4 +1,4 @@
1
- import{spawn as E}from"node:child_process";import{EventEmitter as x}from"node:events";import*as S from"node:fs";import*as T from"node:net";import*as A from"node:os";import*as g from"node:path";import{v4 as P}from"uuid";import{getAcodeDataHome as _}from"../config.js";import{registerListenerWakeHook as M,unregisterListenerWakeHook as D}from"../services/browser-session-manager.js";import{logger as $}from"../utils/logger.js";import{BRIDGE_PACKAGE_ROOT as L,importBridgeSdkPackage as U}from"../utils/sdk-package-loader.js";import{IdlePollLoop as C}from"./idle-poll-loop.js";import{getToolActionInfo as I,redactTransientClipboardPastePaths as O,redactTransientClipboardPastePathsInValue as j}from"./types.js";function N(d){if(d&&g.isAbsolute(d)&&S.existsSync(d))return d;const t=d?.trim()||"opencode";if(process.platform==="win32"){const e=process.env.USERPROFILE||process.env.HOME||A.homedir(),s=process.env.LOCALAPPDATA||"",r=[g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64","bin"),g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64-baseline","bin")];for(const o of r){const n=g.join(o,"opencode.exe");if(S.existsSync(n))return n}const i=[g.join(e,"AppData","Roaming","npm"),g.join(e,"AppData","Local","Volta","bin")];for(const o of i)for(const n of["opencode.cmd","opencode.exe","opencode"]){const a=g.join(o,n);if(S.existsSync(a))return a}}return t}async function R(d=14096){for(let t=d;t<d+100;t++)if(await new Promise(s=>{const r=T.createServer();r.once("error",()=>s(!1)),r.once("listening",()=>{r.close(()=>s(!0))}),r.listen(t,"127.0.0.1")}))return t;throw new Error(`No available port found in range ${d}\u2013${d+99}`)}function H(d){return d instanceof Error&&"code"in d&&typeof d.code=="string"}function W(d,t){return H(d)&&d.code==="ERR_MODULE_NOT_FOUND"&&d.message.includes(t)}function v(d){if(!d||!d.trim())return;const t=d.trim(),e=t.indexOf("/");return e>0?{providerID:t.slice(0,e),modelID:t.slice(e+1)}:{modelID:t}}class Z extends x{constructor(){super(...arguments),this.providerId="opencode",this.displayName="OpenCode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const s={adapterSession:{sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}},config:e,sseActive:!1,pendingPermissions:new Map,emittedToolStarts:new Set,workingDirectory:e.workingDirectory,userMessageIds:new Set,currentAssistantText:"",seenTextPartIds:new Set};if(this.sessions.set(t,s),e.agentId){const r=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,r),M(e.agentId,r)}this.emit("status-change",t,"starting");try{const r=await R();s.port=r;const i=N(e.command),o=i.endsWith(".cmd")||i.endsWith(".CMD")||process.platform==="win32"&&!g.isAbsolute(i),n={...process.env,...e.envOverrides},a={},m=v(e.model),h=e.model;m?.modelID&&h!==null&&h!==void 0&&(a.model=h.trim()),e.systemPrompt&&typeof e.systemPrompt=="string"&&(a.systemPrompt=e.systemPrompt),Object.keys(a).length>0&&(n.OPENCODE_CONFIG_CONTENT=JSON.stringify(a),$.info(`[OpencodeSdkAdapter] OPENCODE_CONFIG_CONTENT keys=${Object.keys(a).join(",")}`));const l=E(i,["serve","--port",String(r)],{cwd:e.workingDirectory,stdio:["ignore","pipe","pipe"],env:n,shell:o});s.serverProcess=l,s.startupOutput=[],l.stdout?.on("data",u=>{const y=u.toString();this.recordStartupOutput(s,y)}),l.stderr?.on("data",u=>{const y=u.toString();this.recordStartupOutput(s,y)}),l.on("error",u=>{console.error("[OpencodeSdkAdapter] Server process error:",u),s.adapterSession.status!=="terminated"&&(s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode server error: ${u.message}`}}))}),l.on("exit",u=>{s.sseActive=!1});const c=new Promise(u=>{l.once("exit",(y,b)=>u({code:y,signal:b}))}),p=(await this.loadSdk()).createOpencodeClient({baseUrl:`http://127.0.0.1:${r}`});s.client=p,await Promise.race([this.waitForServer(p,e.workingDirectory,1e4,r),c.then(u=>{throw new Error(this.formatStartupExitMessage(u,s.startupOutput))})]);const k=(await p.session.create({body:{title:`aws-bridge-${t.slice(0,8)}`},query:{directory:e.workingDirectory}})).data;if(!k?.id)throw new Error("OpenCode session.create() did not return an ID");s.opencodeSessionId=k.id,s.adapterSession.providerSessionId=k.id,this.startSseLoop(t,s),s.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:s.adapterSession.totalUsage}),e.initialPrompt&&this.dispatchInitialPrompt(t,e.initialPrompt)}catch(r){e.agentId&&D(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const i=r instanceof Error?r.message:String(r);throw console.error("[OpencodeSdkAdapter] startSession failed:",r),s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode start failed: ${i}`}}),r}}async sendMessage(t,e,s){const r=this.sessions.get(t);if(!r)throw new Error(`Session ${t} not found`);if(!r.client||!r.opencodeSessionId)throw new Error(`Session ${t} not ready`);const i={id:P(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};r.adapterSession.messages.push(i),this.emit("conversation-message",t,i),s?.keepWaitingStatus||(r.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t));try{const o=v(r.config.model),n={parts:[{type:"text",text:e}]};o?.providerID&&o?.modelID&&(n.model={providerID:o.providerID,modelID:o.modelID}),await r.client.session.prompt({path:{id:r.opencodeSessionId},body:n,query:{directory:r.workingDirectory}})}catch(o){const n=o instanceof Error?o.message:String(o);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:n}})}}async sendConfirmation(t,e){const s=this.sessions.get(t);if(!s?.client||!s.opencodeSessionId)return;const r=e?"once":"reject",i=s.opencodeSessionId;for(const[o]of s.pendingPermissions)try{await s.client.postSessionIdPermissionsPermissionId({path:{id:i,permissionID:o},body:{response:r},query:{directory:s.workingDirectory}})}catch(n){console.warn("[OpencodeSdkAdapter] Permission response failed:",n)}s.pendingPermissions.clear()}async sendQuestionAnswer(t,e){}setIdleCommands(t,e){const s=this.sessions.get(t);s&&(s.idleCommands=e,s.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){const e=this.sessions.get(t);if(!(!e?.client||!e.opencodeSessionId))try{await e.client.session.abort({path:{id:e.opencodeSessionId},query:{directory:e.workingDirectory}})}catch(s){console.warn("[OpencodeSdkAdapter] Abort failed:",s)}}async terminateSession(t){const e=this.sessions.get(t);if(e){if(this.stopIdleDetection(t),e.sseActive=!1,e.sseAbortController?.abort(),e.serverProcess)try{e.serverProcess.kill()}catch{}e.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),e.config.agentId&&D(e.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t)}}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.opencodeSessionId}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){const e=this.sessions.get(t);if(e)return e.serverProcess?.pid}cleanup(){for(const[t]of this.sessions)try{this.terminateSession(t)}catch{}this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await U("@opencode-ai/sdk")}catch(t){throw W(t,"@opencode-ai/sdk")?new Error(["OpenCode SDK provider is not installed.","","aws-runtime-bridge keeps Codex/OpenCode provider SDKs optional to reduce default install size.",'To use SDK mode with command "opencode", install the SDK into the aws-runtime-bridge package root:',"",` npm install --prefix "${L}" @opencode-ai/sdk@latest opencode-ai@latest`,"","If aws-runtime-bridge is installed locally, run the same command with that local package path.","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
1
+ import{spawn as E}from"node:child_process";import{EventEmitter as T}from"node:events";import*as S from"node:fs";import*as x from"node:net";import*as A from"node:os";import*as g from"node:path";import{v4 as P}from"uuid";import{getAcodeDataHome as _}from"../config.js";import{registerListenerWakeHook as M,unregisterListenerWakeHook as D}from"../services/browser-session-manager.js";import{logger as $}from"../utils/logger.js";import{BRIDGE_PACKAGE_ROOT as L,importBridgeSdkPackage as N}from"../utils/sdk-package-loader.js";import{IdlePollLoop as I}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as R}from"./prompts.js";import{getToolActionInfo as C,redactTransientClipboardPastePaths as O,redactTransientClipboardPastePathsInValue as U}from"./types.js";function j(d){if(d&&g.isAbsolute(d)&&S.existsSync(d))return d;const t=d?.trim()||"opencode";if(process.platform==="win32"){const e=process.env.USERPROFILE||process.env.HOME||A.homedir(),s=process.env.LOCALAPPDATA||"",r=[g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64","bin"),g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64-baseline","bin")];for(const o of r){const n=g.join(o,"opencode.exe");if(S.existsSync(n))return n}const i=[g.join(e,"AppData","Roaming","npm"),g.join(e,"AppData","Local","Volta","bin")];for(const o of i)for(const n of["opencode.cmd","opencode.exe","opencode"]){const a=g.join(o,n);if(S.existsSync(a))return a}}return t}async function H(d=14096){for(let t=d;t<d+100;t++)if(await new Promise(s=>{const r=x.createServer();r.once("error",()=>s(!1)),r.once("listening",()=>{r.close(()=>s(!0))}),r.listen(t,"127.0.0.1")}))return t;throw new Error(`No available port found in range ${d}\u2013${d+99}`)}function W(d){return d instanceof Error&&"code"in d&&typeof d.code=="string"}function F(d,t){return W(d)&&d.code==="ERR_MODULE_NOT_FOUND"&&d.message.includes(t)}function v(d){if(!d||!d.trim())return;const t=d.trim(),e=t.indexOf("/");return e>0?{providerID:t.slice(0,e),modelID:t.slice(e+1)}:{modelID:t}}class Y extends T{constructor(){super(...arguments),this.providerId="opencode",this.displayName="OpenCode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const s={adapterSession:{sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}},config:e,sseActive:!1,pendingPermissions:new Map,emittedToolStarts:new Set,workingDirectory:e.workingDirectory,userMessageIds:new Set,currentAssistantText:"",seenTextPartIds:new Set};if(this.sessions.set(t,s),e.agentId){const r=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,r),M(e.agentId,r)}this.emit("status-change",t,"starting");try{const r=await H();s.port=r;const i=j(e.command),o=i.endsWith(".cmd")||i.endsWith(".CMD")||process.platform==="win32"&&!g.isAbsolute(i),n={...process.env,...e.envOverrides},a={},m=v(e.model),h=e.model;m?.modelID&&h!==null&&h!==void 0&&(a.model=h.trim()),e.systemPrompt&&typeof e.systemPrompt=="string"&&(a.systemPrompt=e.systemPrompt),Object.keys(a).length>0&&(n.OPENCODE_CONFIG_CONTENT=JSON.stringify(a),$.info(`[OpencodeSdkAdapter] OPENCODE_CONFIG_CONTENT keys=${Object.keys(a).join(",")}`));const l=E(i,["serve","--port",String(r)],{cwd:e.workingDirectory,stdio:["ignore","pipe","pipe"],env:n,shell:o});s.serverProcess=l,s.startupOutput=[],l.stdout?.on("data",u=>{const y=u.toString();this.recordStartupOutput(s,y)}),l.stderr?.on("data",u=>{const y=u.toString();this.recordStartupOutput(s,y)}),l.on("error",u=>{console.error("[OpencodeSdkAdapter] Server process error:",u),s.adapterSession.status!=="terminated"&&(s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode server error: ${u.message}`}}))}),l.on("exit",u=>{s.sseActive=!1});const c=new Promise(u=>{l.once("exit",(y,b)=>u({code:y,signal:b}))}),p=(await this.loadSdk()).createOpencodeClient({baseUrl:`http://127.0.0.1:${r}`});s.client=p,await Promise.race([this.waitForServer(p,e.workingDirectory,1e4,r),c.then(u=>{throw new Error(this.formatStartupExitMessage(u,s.startupOutput))})]);const k=(await p.session.create({body:{title:`aws-bridge-${t.slice(0,8)}`},query:{directory:e.workingDirectory}})).data;if(!k?.id)throw new Error("OpenCode session.create() did not return an ID");s.opencodeSessionId=k.id,s.adapterSession.providerSessionId=k.id,this.startSseLoop(t,s),s.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:s.adapterSession.totalUsage}),e.initialPrompt&&this.dispatchInitialPrompt(t,e.initialPrompt)}catch(r){e.agentId&&D(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const i=r instanceof Error?r.message:String(r);throw console.error("[OpencodeSdkAdapter] startSession failed:",r),s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode start failed: ${i}`}}),r}}async sendMessage(t,e,s){const r=this.sessions.get(t);if(!r)throw new Error(`Session ${t} not found`);if(!r.client||!r.opencodeSessionId)throw new Error(`Session ${t} not ready`);const i={id:P(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};r.adapterSession.messages.push(i),this.emit("conversation-message",t,i),s?.keepWaitingStatus||(r.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t));try{const o=v(r.config.model),n={parts:[{type:"text",text:e}]};o?.providerID&&o?.modelID&&(n.model={providerID:o.providerID,modelID:o.modelID}),await r.client.session.prompt({path:{id:r.opencodeSessionId},body:n,query:{directory:r.workingDirectory}})}catch(o){const n=o instanceof Error?o.message:String(o);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:n}})}}async sendConfirmation(t,e){const s=this.sessions.get(t);if(!s?.client||!s.opencodeSessionId)return;const r=e?"once":"reject",i=s.opencodeSessionId;for(const[o]of s.pendingPermissions)try{await s.client.postSessionIdPermissionsPermissionId({path:{id:i,permissionID:o},body:{response:r},query:{directory:s.workingDirectory}})}catch(n){console.warn("[OpencodeSdkAdapter] Permission response failed:",n)}s.pendingPermissions.clear()}async sendQuestionAnswer(t,e){}setIdleCommands(t,e){const s=this.sessions.get(t);s&&(s.idleCommands=e,s.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){const e=this.sessions.get(t);if(!(!e?.client||!e.opencodeSessionId))try{await e.client.session.abort({path:{id:e.opencodeSessionId},query:{directory:e.workingDirectory}})}catch(s){console.warn("[OpencodeSdkAdapter] Abort failed:",s)}}async terminateSession(t){const e=this.sessions.get(t);if(e){if(this.stopIdleDetection(t),e.sseActive=!1,e.sseAbortController?.abort(),e.serverProcess)try{e.serverProcess.kill()}catch{}e.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),e.config.agentId&&D(e.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t)}}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.opencodeSessionId}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){const e=this.sessions.get(t);if(e)return e.serverProcess?.pid}cleanup(){for(const[t]of this.sessions)try{this.terminateSession(t)}catch{}this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await N("@opencode-ai/sdk")}catch(t){throw F(t,"@opencode-ai/sdk")?new Error(["OpenCode SDK provider is not installed.","","aws-runtime-bridge keeps Codex/OpenCode provider SDKs optional to reduce default install size.",'To use SDK mode with command "opencode", install the SDK into the aws-runtime-bridge package root:',"",` npm install --prefix "${L}" @opencode-ai/sdk@latest opencode-ai@latest`,"","If aws-runtime-bridge is installed locally, run the same command with that local package path.","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
2
  `)):t}return this.sdkModule}async waitForServer(t,e,s,r){const i=Date.now()+s;for(;Date.now()<i;){try{if((await t.session.list({query:{directory:e}})).data!==void 0)return}catch{}await new Promise(o=>setTimeout(o,300))}throw new Error(`OpenCode server (port ${r}) did not start within ${s}ms`)}recordStartupOutput(t,e){const s=e.trim();s&&(t.startupOutput=[...t.startupOutput??[],s].slice(-8))}formatStartupExitMessage(t,e){const s=t.signal?`signal ${t.signal}`:`code ${t.code??"unknown"}`,r=(e??[]).join(`
3
- `).trim();return r?`OpenCode server exited during startup (${s}): ${r}`:`OpenCode server exited during startup (${s}). Please check whether opencode serve can run in this workspace.`}dispatchInitialPrompt(t,e){this.sendMessage(t,e).catch(s=>{const r=s instanceof Error?s.message:String(s);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode initial prompt failed: ${r}`}})})}startSseLoop(t,e){e.sseActive=!0;const s=new AbortController;e.sseAbortController=s,this.runSseLoop(t,e,s).catch(r=>{s.signal.aborted||console.error("[OpencodeSdkAdapter] SSE loop error:",r)})}async runSseLoop(t,e,s){if(e.client)try{const r=await e.client.event.subscribe({query:{directory:e.workingDirectory},signal:s.signal});for await(const i of r.stream){if(!e.sseActive||s.signal.aborted)break;this.handleOpenCodeEvent(t,e,i)}}catch(r){if(s.signal.aborted)return;console.error("[OpencodeSdkAdapter] SSE stream ended:",r)}}handleOpenCodeEvent(t,e,s){const r=new Date().toISOString(),i=e.opencodeSessionId;switch(s.type){case"message.updated":{const o=s.properties.info;if(o.sessionID!==i)break;if(o.role==="user")e.userMessageIds.add(o.id);else if(o.role==="assistant"){const n=o.tokens;n&&(e.adapterSession.totalUsage.inputTokens=Math.max(e.adapterSession.totalUsage.inputTokens,n.input),e.adapterSession.totalUsage.outputTokens=Math.max(e.adapterSession.totalUsage.outputTokens,n.output))}break}case"message.part.updated":{const{part:o,delta:n}=s.properties;if(o.sessionID!==i||e.userMessageIds.has(o.messageID))break;this.handlePartUpdate(t,e,o,n,r);break}case"session.idle":{if(s.properties.sessionID!==i)break;if(e.currentAssistantText){const a={id:P(),sessionId:t,role:"assistant",content:e.currentAssistantText,timestamp:r};e.adapterSession.messages.push(a),e.currentAssistantText=""}e.seenTextPartIds.clear(),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:r,data:{usage:e.adapterSession.totalUsage}}),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand;!!(o&&this.isMessagePollingIdleCommand(o))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.adapterSession.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),this.startIdleDetection(t);break}case"permission.updated":{const o=s.properties;if(o.sessionID!==i)break;const n=o.id;e.pendingPermissions.set(n,o),e.config.autoAccept&&e.client&&i?e.client.postSessionIdPermissionsPermissionId({path:{id:i,permissionID:n},body:{response:"once"},query:{directory:e.workingDirectory}}).then(()=>{e.pendingPermissions.delete(n)}).catch(a=>{console.warn("[OpencodeSdkAdapter] Auto-accept permission failed:",a)}):this.emitEvent({type:"permission_request",sessionId:t,timestamp:r,data:{permissionPrompt:o.title,toolName:o.type}});break}case"session.error":{const{sessionID:o,error:n}=s.properties;if(o&&o!==i)break;let a="OpenCode session error";if(n){const m=n.data;typeof m?.message=="string"?a=`${n.name}: ${m.message}`:a=n.name}this.emitEvent({type:"error",sessionId:t,timestamp:r,data:{text:a}});break}}}handlePartUpdate(t,e,s,r,i){switch(s.type){case"text":{let o;if(r!==void 0)o=r,e.seenTextPartIds.add(s.id);else if(!e.seenTextPartIds.has(s.id))o=s.text,o&&e.seenTextPartIds.add(s.id);else break;if(!o)break;e.currentAssistantText+=o,this.emitEvent({type:"text_delta",sessionId:t,timestamp:i,data:{text:o}});break}case"reasoning":{const o=r??s.text;if(!o)break;this.emitEvent({type:"thinking",sessionId:t,timestamp:i,data:{text:o}});break}case"tool":{const o=s.callID,n=s.tool,a=s.state,m=a.input,h=s.metadata,l=j(m),c=l&&typeof l=="object"&&!Array.isArray(l)?l:{},f=()=>{if(e.emittedToolStarts.has(o))return;e.emittedToolStarts.add(o);const p={...I(n,m,h),actionId:o};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:i,data:{toolName:n,toolInput:c,toolUseId:o,...p}}),e.adapterSession.messages.push({id:P(),sessionId:t,role:"tool_use",content:`${n}: ${JSON.stringify(c).slice(0,100)}`,timestamp:i,toolName:n,toolInput:c,toolUseId:o})};if(a.status==="running"){f();const p={...I(n,m,h),actionId:o};this.emit("status-change",t,"tool_using",{...p,usage:e.adapterSession.totalUsage})}else if(a.status==="completed"){(n==="todowrite"||n==="todo_write")&&this.syncTodosFromToolCall(e,m).catch(w=>{console.warn("[OpencodeSdkAdapter] \u540C\u6B65 todo \u5230\u6587\u4EF6\u5931\u8D25:",w)}),f();const p=O(a.output);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:i,data:{toolName:n,toolResult:p,isError:!1,toolUseId:o}}),e.emittedToolStarts.delete(o)}else if(a.status==="error"){f();const p=O(a.error);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:i,data:{toolName:n,toolResult:p,isError:!0,toolUseId:o}}),e.emittedToolStarts.delete(o)}break}}}getTodoStoreDir(){return g.join(_(),"todos")}async syncTodosFromToolCall(t,e){const s=t.config.agentId;if(!s)return;const r=e.todos;if(!Array.isArray(r)||r.length===0)return;const i=[];for(const l of r)if(l&&typeof l=="object"){const c=l,f=typeof c.content=="string"?c.content.trim():"",p=typeof c.status=="string"?c.status:"",w=typeof c.priority=="string"?c.priority:"";f&&p&&w&&i.push({content:f,status:p,priority:w})}if(i.length===0)return;const o=String(s).replace(/[^a-zA-Z0-9_-]/g,"_"),n=this.getTodoStoreDir(),a=g.join(n,`${o}.json`),m={agentId:s,updatedAt:new Date().toISOString(),background:"OpenCode runtime todos",todos:i};await S.promises.mkdir(n,{recursive:!0});const h=`${a}.tmp`;await S.promises.writeFile(h,JSON.stringify(m,null,2),"utf-8"),await S.promises.rename(h,a)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.sessions.get(t),s=e?.idleCommands?.idleInputCommand;if(!e||!s)return;if(this.isMessagePollingIdleCommand(s)){e.idlePollLoop||(e.idlePollLoop=new C({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:i=>this.isMessagePollingIdleCommand(i),preDispatchHook:()=>null,dispatchPollingPrompt:(i,o)=>this.sendMessage(t,o?i.trim():this.toIdlePrompt(i),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:i=>this.sendMessage(t,this.toIdlePrompt(i)),pollDelayMs:1500})),e.idlePollLoop.start();return}e.idlePollLoop||(e.idlePollLoop=new C({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:i=>this.isMessagePollingIdleCommand(i),preDispatchHook:()=>null,dispatchPollingPrompt:(i,o)=>this.sendMessage(t,o?i.trim():this.toIdlePrompt(i),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:i=>this.sendMessage(t,this.toIdlePrompt(i)),pollDelayMs:1500}));const r=setInterval(()=>{this.checkIdleState(t)},500);e.idleTimer=r}stopIdleDetection(t){const e=this.sessions.get(t);e?.idlePollLoop?.stop(),e?.idleTimer&&(clearInterval(e.idleTimer),e.idleTimer=void 0)}checkIdleState(t){const e=this.sessions.get(t);!e||e.adapterSession.status!=="waiting_input"||e.idleCommands?.idleInputCommand&&(this.sendMessage(t,this.toIdlePrompt(e.idleCommands.idleInputCommand)),this.stopIdleDetection(t))}toIdlePrompt(t){const e=t.trim();return this.isMessagePollingIdleCommand(e)?"\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002":e}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const s=e.toLowerCase();return s.includes("poll_message")||s.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}}export{Z as OpencodeSdkAdapter};
3
+ `).trim();return r?`OpenCode server exited during startup (${s}): ${r}`:`OpenCode server exited during startup (${s}). Please check whether opencode serve can run in this workspace.`}dispatchInitialPrompt(t,e){this.sendMessage(t,e).catch(s=>{const r=s instanceof Error?s.message:String(s);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode initial prompt failed: ${r}`}})})}startSseLoop(t,e){e.sseActive=!0;const s=new AbortController;e.sseAbortController=s,this.runSseLoop(t,e,s).catch(r=>{s.signal.aborted||console.error("[OpencodeSdkAdapter] SSE loop error:",r)})}async runSseLoop(t,e,s){if(e.client)try{const r=await e.client.event.subscribe({query:{directory:e.workingDirectory},signal:s.signal});for await(const i of r.stream){if(!e.sseActive||s.signal.aborted)break;this.handleOpenCodeEvent(t,e,i)}}catch(r){if(s.signal.aborted)return;console.error("[OpencodeSdkAdapter] SSE stream ended:",r)}}handleOpenCodeEvent(t,e,s){const r=new Date().toISOString(),i=e.opencodeSessionId;switch(s.type){case"message.updated":{const o=s.properties.info;if(o.sessionID!==i)break;if(o.role==="user")e.userMessageIds.add(o.id);else if(o.role==="assistant"){const n=o.tokens;n&&(e.adapterSession.totalUsage.inputTokens=Math.max(e.adapterSession.totalUsage.inputTokens,n.input),e.adapterSession.totalUsage.outputTokens=Math.max(e.adapterSession.totalUsage.outputTokens,n.output))}break}case"message.part.updated":{const{part:o,delta:n}=s.properties;if(o.sessionID!==i||e.userMessageIds.has(o.messageID))break;this.handlePartUpdate(t,e,o,n,r);break}case"session.idle":{if(s.properties.sessionID!==i)break;if(e.currentAssistantText){const a={id:P(),sessionId:t,role:"assistant",content:e.currentAssistantText,timestamp:r};e.adapterSession.messages.push(a),e.currentAssistantText=""}e.seenTextPartIds.clear(),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:r,data:{usage:e.adapterSession.totalUsage}}),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand;!!(o&&this.isMessagePollingIdleCommand(o))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.adapterSession.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),this.startIdleDetection(t);break}case"permission.updated":{const o=s.properties;if(o.sessionID!==i)break;const n=o.id;e.pendingPermissions.set(n,o),e.config.autoAccept&&e.client&&i?e.client.postSessionIdPermissionsPermissionId({path:{id:i,permissionID:n},body:{response:"once"},query:{directory:e.workingDirectory}}).then(()=>{e.pendingPermissions.delete(n)}).catch(a=>{console.warn("[OpencodeSdkAdapter] Auto-accept permission failed:",a)}):this.emitEvent({type:"permission_request",sessionId:t,timestamp:r,data:{permissionPrompt:o.title,toolName:o.type}});break}case"session.error":{const{sessionID:o,error:n}=s.properties;if(o&&o!==i)break;let a="OpenCode session error";if(n){const m=n.data;typeof m?.message=="string"?a=`${n.name}: ${m.message}`:a=n.name}this.emitEvent({type:"error",sessionId:t,timestamp:r,data:{text:a}});break}}}handlePartUpdate(t,e,s,r,i){switch(s.type){case"text":{let o;if(r!==void 0)o=r,e.seenTextPartIds.add(s.id);else if(!e.seenTextPartIds.has(s.id))o=s.text,o&&e.seenTextPartIds.add(s.id);else break;if(!o)break;e.currentAssistantText+=o,this.emitEvent({type:"text_delta",sessionId:t,timestamp:i,data:{text:o}});break}case"reasoning":{const o=r??s.text;if(!o)break;this.emitEvent({type:"thinking",sessionId:t,timestamp:i,data:{text:o}});break}case"tool":{const o=s.callID,n=s.tool,a=s.state,m=a.input,h=s.metadata,l=U(m),c=l&&typeof l=="object"&&!Array.isArray(l)?l:{},f=()=>{if(e.emittedToolStarts.has(o))return;e.emittedToolStarts.add(o);const p={...C(n,m,h),actionId:o};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:i,data:{toolName:n,toolInput:c,toolUseId:o,...p}}),e.adapterSession.messages.push({id:P(),sessionId:t,role:"tool_use",content:`${n}: ${JSON.stringify(c).slice(0,100)}`,timestamp:i,toolName:n,toolInput:c,toolUseId:o})};if(a.status==="running"){f();const p={...C(n,m,h),actionId:o};this.emit("status-change",t,"tool_using",{...p,usage:e.adapterSession.totalUsage})}else if(a.status==="completed"){(n==="todowrite"||n==="todo_write")&&this.syncTodosFromToolCall(e,m).catch(w=>{console.warn("[OpencodeSdkAdapter] \u540C\u6B65 todo \u5230\u6587\u4EF6\u5931\u8D25:",w)}),f();const p=O(a.output);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:i,data:{toolName:n,toolResult:p,isError:!1,toolUseId:o}}),e.emittedToolStarts.delete(o)}else if(a.status==="error"){f();const p=O(a.error);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:i,data:{toolName:n,toolResult:p,isError:!0,toolUseId:o}}),e.emittedToolStarts.delete(o)}break}}}getTodoStoreDir(){return g.join(_(),"todos")}async syncTodosFromToolCall(t,e){const s=t.config.agentId;if(!s)return;const r=e.todos;if(!Array.isArray(r)||r.length===0)return;const i=[];for(const l of r)if(l&&typeof l=="object"){const c=l,f=typeof c.content=="string"?c.content.trim():"",p=typeof c.status=="string"?c.status:"",w=typeof c.priority=="string"?c.priority:"";f&&p&&w&&i.push({content:f,status:p,priority:w})}if(i.length===0)return;const o=String(s).replace(/[^a-zA-Z0-9_-]/g,"_"),n=this.getTodoStoreDir(),a=g.join(n,`${o}.json`),m={agentId:s,updatedAt:new Date().toISOString(),background:"OpenCode runtime todos",todos:i};await S.promises.mkdir(n,{recursive:!0});const h=`${a}.tmp`;await S.promises.writeFile(h,JSON.stringify(m,null,2),"utf-8"),await S.promises.rename(h,a)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.sessions.get(t),s=e?.idleCommands?.idleInputCommand;if(!e||!s)return;if(this.isMessagePollingIdleCommand(s)){e.idlePollLoop||(e.idlePollLoop=new I({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:i=>this.isMessagePollingIdleCommand(i),preDispatchHook:()=>null,dispatchPollingPrompt:(i,o)=>this.sendMessage(t,o?i.trim():this.toIdlePrompt(i),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:i=>this.sendMessage(t,this.toIdlePrompt(i)),pollDelayMs:1500})),e.idlePollLoop.start();return}e.idlePollLoop||(e.idlePollLoop=new I({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:i=>this.isMessagePollingIdleCommand(i),preDispatchHook:()=>null,dispatchPollingPrompt:(i,o)=>this.sendMessage(t,o?i.trim():this.toIdlePrompt(i),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:i=>this.sendMessage(t,this.toIdlePrompt(i)),pollDelayMs:1500}));const r=setInterval(()=>{this.checkIdleState(t)},500);e.idleTimer=r}stopIdleDetection(t){const e=this.sessions.get(t);e?.idlePollLoop?.stop(),e?.idleTimer&&(clearInterval(e.idleTimer),e.idleTimer=void 0)}checkIdleState(t){const e=this.sessions.get(t);!e||e.adapterSession.status!=="waiting_input"||e.idleCommands?.idleInputCommand&&(this.sendMessage(t,this.toIdlePrompt(e.idleCommands.idleInputCommand)),this.stopIdleDetection(t))}toIdlePrompt(t){const e=t.trim();return this.isMessagePollingIdleCommand(e)?R:e}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const s=e.toLowerCase();return s.includes("poll_message")||s.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}}export{Y as OpencodeSdkAdapter};
4
4
 
@@ -0,0 +1,2 @@
1
+
2
+ export declare const MESSAGE_POLLING_IDLE_PROMPT = "\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002";
@@ -0,0 +1,2 @@
1
+ const s="\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002";export{s as MESSAGE_POLLING_IDLE_PROMPT};
2
+