aws-runtime-bridge 1.9.102 → 1.9.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/AcodeSdkAdapter.js +3 -3
- package/dist/index.js +1 -1
- package/dist/remote-desktop/computer-use-backend.d.ts +111 -0
- package/dist/remote-desktop/computer-use-backend.js +1 -0
- package/dist/remote-desktop/types.d.ts +79 -0
- package/dist/routes/computer.d.ts +1 -0
- package/dist/routes/computer.js +2 -0
- package/dist/routes/file-change-diff.d.ts +27 -0
- package/dist/routes/file-change-diff.js +5 -0
- package/dist/routes/instance.js +2 -2
- package/dist/routes/pty.d.ts +2 -2
- package/dist/routes/pty.js +3 -3
- package/dist/routes/task-context.js +1 -1
- package/dist/routes/terminal.js +28 -28
- package/dist/services/auto-register.d.ts +1 -1
- package/dist/services/auto-register.js +1 -1
- package/dist/services/instance-features.d.ts +10 -0
- package/dist/services/instance-features.js +2 -0
- package/dist/services/sdk-tool-file-change-recorder.d.ts +12 -0
- package/dist/services/sdk-tool-file-change-recorder.js +2 -0
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspaceTaskChangeWatcher.d.ts +9 -1
- package/dist/services/workspaceTaskChangeWatcher.js +3 -1
- package/package/acode/dist/built-in-file-tools.d.ts +4 -0
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/runtime.d.ts +13 -0
- package/package/acode/dist/runtime.js +18 -18
- package/package/aws-client-agent-mcp/README.md +2 -2
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +14 -4
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +36 -36
- package/package/aws-client-agent-mcp/dist/config.js +1 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +21 -21
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +35 -36
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +6 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -5
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +17 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +14 -12
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package.json +3 -2
- package/scripts/ensure-playwright-browser.mjs +118 -0
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ npm install -g aws-runtime-bridge
|
|
|
14
14
|
|
|
15
15
|
安装脚本会在 macOS、Linux 与常见 Unix 平台自动为 CLI 入口补齐可执行权限;Windows 平台无需 chmod,会自动跳过该步骤。
|
|
16
16
|
|
|
17
|
+
> **浏览器内核自动安装**:安装完成后会自动下载 Playwright Chromium(约 150MB,存于 `~/.cache/ms-playwright`),Linux 上以 root 安装(如 `sudo npm install -g`)时还会自动补齐系统依赖,装完即可使用浏览器功能。可用 `AWS_BRIDGE_SKIP_PLAYWRIGHT_INSTALL=1 npm install -g aws-runtime-bridge` 跳过;跳过或安装失败后,可随时手动执行:`npx playwright install chromium`(Linux 缺系统库时:`sudo npx playwright install --with-deps chromium`)。
|
|
18
|
+
|
|
17
19
|
从当前仓库安装时:
|
|
18
20
|
|
|
19
21
|
```bash
|
|
@@ -17,6 +17,8 @@ type ACodeRuntimeInstance = {
|
|
|
17
17
|
stop(): Promise<void>;
|
|
18
18
|
|
|
19
19
|
submitQuestionAnswer?(toolCallId: string, answers: Record<string, string>): boolean;
|
|
20
|
+
|
|
21
|
+
detachCurrentToolExecution?(): boolean;
|
|
20
22
|
};
|
|
21
23
|
type ACodeRuntimeConstructor = new (config: {
|
|
22
24
|
sessionId: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{EventEmitter as B}from"node:events";import L from"node:path";import q from"node:fs/promises";import{pathToFileURL as N}from"node:url";import{v4 as D}from"uuid";import{getAcodeConfigFile as O,getAcodeSkillsDir as K,getRuntimeHomeDir as H}from"../config.js";import{getReleasedAcodeEntryPath as j}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as P}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as $}from"../services/instance-ai-config-service.js";import{subAgentManager as Q}from"../services/sub-agent-manager-instance.js";import{agentPtyManager as G}from"../services/agent-pty-manager.js";import{resolveAcodeProviderConfig as z}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as J}from"../services/workspaceTaskChangeWatcher.js";import{getBrowserTools as Y,closeBrowserSession as X,registerListenerWakeHook as V,unregisterListenerWakeHook as E}from"../services/browser-session-manager.js";import{isMessagePollingIdleCommand as w,isPollMessageToolDescriptor as Z}from"./acode-tool-names.js";import{IdlePollLoop as tt}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as I,getToolActionInfo as et}from"./types.js";const ot=process.env.ACODE_COMPACTION_DEBUG==="1";function u(...r){ot&&console.log(...r)}const M=["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,it=4e4,at=5*6e4,nt=250,rt=2e3,lt=12e4,R=3e3,ut="\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 dt(){return L.resolve(j())}function ct(r){return N(L.resolve(r)).href}const U=128e3,k={"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 mt(r){if(!r)return U;const t=r.toLowerCase().trim();if(k[t])return k[t].contextLimit;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].contextLimit:U}const v=4096;function pt(r){if(!r)return v;const t=r.toLowerCase().trim();if(k[t])return k[t].maxOutput;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].maxOutput:v}function gt(r){if(!r||typeof r!="object")return;const t=r,e=y(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=y(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(!(e===0&&o===0))return{inputTokens:e,outputTokens:o}}function y(...r){for(const t of r){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function F(r){return y(r.estimatedContextTokens,r.contextTokens,r.context_tokens,r.contextUsedTokens,r.context_used_tokens)}function ft(r){return r==="stderr"||r==="mixed"?r:"stdout"}function ht(r){if(!r||typeof r!="object"||Array.isArray(r))return;const t={};for(const[e,o]of Object.entries(r))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Tt(r){return r.failed===!0}function W(r,t,e){if(!r)return e?`${t}/${e}`:t;const o=`${t}__`;return r.startsWith(o)?I(`${t}__${r.slice(o.length)}`):I(r.replace("/","__"))}function St(r){return r==="read_file"||r==="edit_file"||r==="write_file"||r==="bash"}function At(r){const t=_t(r);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof r=="string"&&r.trim().length>0}function _t(r){if(r&&typeof r=="object"&&!Array.isArray(r))return r;if(!(typeof r!="string"||!r.trim()))try{const t=JSON.parse(r);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class Ft extends B{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const o=H(),s=e.mcpConfigPath||O(o),{resolved:n,configContextLimit:i}=await this.resolveAcodeProvider(e,s),a=n.model,l=i??mt(a),c=pt(a),m={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:l,maxOutput:c}};this.sessions.set(t,{adapterSession:m,config:e,runtime:await this.createRuntime(t,a,e,o),autoPollActive:!1}),this.emit("status-change",t,"starting");const d=this.sessions.get(t);if(!d)throw new Error("ACode session was not initialized");const g=()=>{const p=this.sessions.get(t);p&&this.getIdlePollLoop(p).start()};this.listenerWakeHooks.set(t,g),V(e.agentId,g);try{await d.runtime.start(),m.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:d.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(p){m.status="error",this.emitRuntimeErrorEvent(t,p),this.emit("status-change",t,"error");const h=this.sessions.get(t);throw h?.capabilitiesFallbackTimer&&clearTimeout(h.capabilitiesFallbackTimer),this.sessions.delete(t),E(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),p}}async sendMessage(t,e){const o=Date.now();u("[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"),u("[ACode] \u25B6\uFE0F sendMessage STARTED"),u(`[ACode] Session: ${t}`),u(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),u("[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),n=s.adapterSession.status;u(`[ACode] Previous status: ${n}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:D(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),u(`[ACode] Changing status: ${n} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{u("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const a=Date.now();await s.runtime.submit(e);const l=Date.now()-a;this.cancelSubmitTimeoutDetection(s),u(`[ACode] \u2705 runtime.submit() completed in ${l}ms`),u(`[ACode] Current status after submit: ${s.adapterSession.status}`),u("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),u(`[ACode] Status after recovery: ${s.adapterSession.status}`);const c=Date.now()-o;u("[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"),u(`[ACode] \u2705 sendMessage COMPLETED in ${c}ms`),u("[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(a){const l=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${l}ms:`,a instanceof Error?a.message:String(a)),this.cancelSubmitTimeoutDetection(s),u("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,a,{recover:!0}),u(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}async sendQuestionAnswer(t,e){const o=this.sessions.get(t);if(!o)return;const s=o.pendingQuestionToolCallId;if(!s){u(`[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},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&&(E(o,this.listenerWakeHooks.get(t)),X(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}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}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&&w(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 q.readFile(t,"utf-8"),o=JSON.parse(e),n=o.provider?.default,i=n?.options,a=y(o.contextLimit),l={},c=n?.models;if(c&&typeof c=="object"){for(const[m,d]of Object.entries(c))if(d&&typeof d=="object"){const g=y(d.contextLimit);g>0&&(l[m.trim()]=g)}}return{...n?.model?{model:n.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...a>0?{contextLimit:a}:{},...Object.keys(l).length>0?{modelContextLimits:l}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return P().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=P();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?$(t.instanceAiConfig):null,configPath:e}});const n={...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 a=i.contextLimit;if(!a&&i.modelContextLimits){const c=o||t.instanceAiConfig?.model||i.model;c&&i.modelContextLimits[c]&&(a=i.modelContextLimits[c])}const l=z(n,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:$(n),globalConfigModel:i?.model??null,resolvedModel:l.model,resolvedBaseURL:l.baseURL??null,resolvedApiKey:l.apiKey?"[set]":null,configContextLimit:a,resolvedSource:l.source}}),{resolved:l,configPath:e,perSessionModel:o,configContextLimit:a}}async createRuntime(t,e,o,s){const n=await this.loadRuntimeConstructor(),i=o.mcpConfigPath||O(s);let a=[];try{a=await Y(o.agentId,o.scopeKey)}catch(m){u(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,m.message)}const l=new n({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:i,skillsDir:K(s),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:Q,terminalManager:G,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:m=>J(m),extraBuiltInTools:a});return P().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:i}}),l.on("event",m=>this.forwardAcodeEvent(m)),l}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=dt(),e=await import(ct(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 n=this.sessions.get(t);n&&(this.cancelSubmitTimeoutDetection(n),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:D(),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:ft(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==="ai_request"){const o=F(t.data);let s;if(o>0){const a=e.adapterSession.totalUsage.inputTokens;a>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(a*1.5)):e.adapterSession.totalUsage.inputTokens=o,s={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const i={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};s&&(i.usage=s),this.emit("status-change",t.sessionId,e.adapterSession.status,i),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:ht(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=gt(t.data.usage);if(o){const n=e.adapterSession.totalUsage.inputTokens;n>0&&o.inputTokens<Math.floor(n*.2)||(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens)}const s=e.adapterSession.status;if(u(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Tt(t.data)){u(`[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){u(`[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}),u(`[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==="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 h=t.data.tools;h.some(f=>Z(f))||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 T=Array.isArray(t.data.servers)?t.data.servers:[],A=h.map(f=>({name:String(f.name??""),source:String(f.source??""),description:String(f.description??"")})).filter(f=>f.name),_={kind:"mcp",mcpServers:T,mcpTools:A};e.cachedMcpCapabilities=_,e.lastMcpCapabilities=_,e.lastCombinedCapabilities={kind:"combined",mcpServers:T,mcpTools:A,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},u(`[cap-diag] MCP capabilities cached: ${T.length} servers, ${A.length} tools`,{sessionId:t.sessionId,servers:T,toolNames:A.map(f=>f.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const f=e.cachedMcpCapabilities;if(!f)return;const b={...f,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:b,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(b)}),u(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${R}ms)`,{sessionId:t.sessionId,mcpServers:f.mcpServers,mcpToolsCount:f.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},R);return}const o=String(t.data.action??"");u(`[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",n=typeof t.data.tool=="string"?t.data.tool:"",i=s&&n?`${s}__${n}`:n||s,a=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,l=et(i,a);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,l.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=St(l.actionType)?l.actionDetail||W(void 0,s,n):W(l.actionDetail,s,n),m=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,d=a?JSON.stringify(a,null,2):void 0,g={toolName:c,rawToolName:i,actionType:l.actionType,actionLabel:l.actionLabel,actionDetail:c,...d?{actionInput:d}:{},...a?{toolInput:a}:{},...m?{toolUseId:m,actionId:m}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...g,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const h=l.actionType==="idle"&&!At(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=h,this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const C=l.actionType==="idle";this.emit("status-change",t.sessionId,h,C||h==="thinking"?void 0:g);return}const p=l.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=p,p==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...g}),this.emitProviderEvent(t,"tool_use_start",g),this.emit("status-change",t.sessionId,p,g);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(d=>({name:String(d.name??""),description:typeof d.description=="string"?d.description:void 0,directory:typeof d.directory=="string"?d.directory:void 0})).filter(d=>d.name),n=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,a=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(d=>{const g=Array.isArray(d.skills)?d.skills:[];return{dir:typeof d.dir=="string"?d.dir:"",exists:d.exists===!0,skills:g.map(p=>({name:String(p.name??""),description:typeof p.description=="string"?p.description:void 0,directory:typeof p.directory=="string"?p.directory:void 0})).filter(p=>p.name)}}).filter(d=>d.dir),l=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,m={kind:"combined",mcpServers:l?.mcpServers??[],mcpTools:l?.mcpTools??[],skills:s,skillsDir:n,skillGroups:a};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:m,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(m)}),e.lastCombinedCapabilities=m,u(`[cap-diag] Combined capabilities emitted ${c?"(startup merge)":"(runtime refresh)"}: ${(l?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:l?.mcpServers??[],skillsDir:n}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="session_started"){const o=F(t.data),s=y(t.data.contextLimit)||void 0,n=y(t.data.maxOutput)||void 0,i=y(t.data.inputLimit)||void 0,a=y(t.data.compactionThreshold)||void 0;let l=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,l=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,l=!0),n!==void 0&&(e.adapterSession.totalUsage.maxOutput=n,l=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,l=!0),a!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=a,l=!0),l&&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,n=s==="start",i=s==="end",a=s==="phase",l=o.parentId,c=o.compactionId;let m,d;if(n){const p=String(o.sizeKB??o.sizeBeforeKB??"?"),h=String(o.messageCount??o.messageCountBefore??"?"),C=o.estimatedTokens,T=o.actualInputTokens?`input=${o.actualInputTokens}`:"",A=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",_=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";m="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",C!==void 0?d=`\u538B\u7F29\u524D: ~${C} tokens, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_:d=`\u538B\u7F29\u524D: ${p}KB, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_}else if(a)m=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),d=String(o.phaseDetail??"");else{const p=o.tokensBefore,h=o.tokensAfter,C=o.freedTokens,T=String(o.sizeBeforeKB??"?"),A=String(o.sizeAfterKB??"?"),_=String(o.freedKB??"?"),f=String(o.strategy??"?"),b=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);m="\u538B\u7F29\u5B8C\u6210",p!==void 0&&h!==void 0?d=`\u91CA\u653E: ${C??p-h} tokens, ${p} tokens \u2192 ${h} tokens, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):d=`\u91CA\u653E: ${_}KB, ${T}KB \u2192 ${A}KB, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}n&&(e.adapterSession.status="compacting");const g={actionType:"context_compaction",actionLabel:m,actionDetail:d};if(n&&c)g.actionId=c;else if((a||i)&&c)if(g.parentId=c,a){const p=String(o.phase??"unknown");g.actionId=`${c}-phase-${p}`}else g.actionId=`${c}-end`;a&&l&&!g.parentId&&(g.parentId=l),i&&(e.adapterSession.totalUsage.inputTokens=0,e.adapterSession.totalUsage.outputTokens=0,g.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",g),this.emit("status-change",t.sessionId,"compacting",g);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,o=t.config.agentId;return t.idlePollLoop=new tt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:s=>w(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,n)=>this.submitAutoPollPrompt(e,n?s:ut,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:s=>this.submitAutoPollPrompt(e,s)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const n=(s.autoPollToken??0)+1;s.autoPollToken=n,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,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!==n){u(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${n}, 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=nt){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,M,{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.adapterSession.status==="tool_using"&&e.pendingToolEventData){const a=e.pendingToolEventData;u(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${a.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:{...a,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 a=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,u(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${a} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&w(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 a=this.sessions.get(t);if(!a||a.autoPollActive||this.isTerminalStatus(a.adapterSession.status)){a&&(a.failedTurnRecoveryScheduled=!1);return}a.autoPollTimer=void 0,a.failedTurnRecoveryScheduled=!1,a.idleCommands?.idleInputCommand?this.getIdlePollLoop(a).start():this.submitAutoPollPrompt(t,M,{keepWaitingStatus:!0})},rt)}recoverResolvedTurnWithoutTerminalEvent(t){u(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){u(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(u(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){u(`[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.`),u("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,n=!!(o&&w(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",n),u(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),u("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),u("[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 n=s.adapterSession.status,i=Date.now();if(n==="waiting_input"){s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(n==="tool_using"){const c=i-(s.watchdogLastDataFlowTime||i);if(c>=at){const m=String(s.pendingToolEventData?.rawToolName??"");if(m.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_complete is running (session: ${t}, tool: ${m}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(c/1e3)}s (source: ${o}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"tool_using_slow",c);return}s.watchdogSubmitStartTime=i;return}if(n!=="thinking")return;const a=i-(s.watchdogSubmitStartTime||i),l=i-(s.watchdogLastDataFlowTime||i);if(l>=it){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(l/1e3)}s (source: ${o}, session: ${t}, status: ${n}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",l);return}if(a>=lt){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(a/1e3)}s (source: ${o}, session: ${t}, status: ${n}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",a);return}},st)}executeWatchdogRecovery(t,e,o,s,n){u(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(n/1e3)}s...`);try{e.runtime.abort(),u(`[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()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
|
|
1
|
+
import{EventEmitter as B}from"node:events";import L from"node:path";import q from"node:fs/promises";import{pathToFileURL as N}from"node:url";import{v4 as D}from"uuid";import{getAcodeConfigFile as $,getAcodeSkillsDir as K,getRuntimeHomeDir as H}from"../config.js";import{getReleasedAcodeEntryPath as j}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as P}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as O}from"../services/instance-ai-config-service.js";import{subAgentManager as Q}from"../services/sub-agent-manager-instance.js";import{agentPtyManager as G}from"../services/agent-pty-manager.js";import{resolveAcodeProviderConfig as z}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as J}from"../services/workspaceTaskChangeWatcher.js";import{getBrowserTools as Y,closeBrowserSession as X,registerListenerWakeHook as V,unregisterListenerWakeHook as E}from"../services/browser-session-manager.js";import{isMessagePollingIdleCommand as w,isPollMessageToolDescriptor as Z}from"./acode-tool-names.js";import{IdlePollLoop as tt}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as I,getToolActionInfo as et}from"./types.js";const ot=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...r){ot&&console.log(...r)}const M=["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,it=4e4,at=5*6e4,nt=250,rt=2e3,ut=12e4,R=3e3,lt="\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 dt(){return L.resolve(j())}function ct(r){return N(L.resolve(r)).href}const U=128e3,k={"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 mt(r){if(!r)return U;const t=r.toLowerCase().trim();if(k[t])return k[t].contextLimit;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].contextLimit:U}const v=4096;function pt(r){if(!r)return v;const t=r.toLowerCase().trim();if(k[t])return k[t].maxOutput;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].maxOutput:v}function gt(r){if(!r||typeof r!="object")return;const t=r,e=b(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=b(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(!(e===0&&o===0))return{inputTokens:e,outputTokens:o}}function b(...r){for(const t of r){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function F(r){return b(r.estimatedContextTokens,r.contextTokens,r.context_tokens,r.contextUsedTokens,r.context_used_tokens)}function ft(r){return r==="stderr"||r==="mixed"?r:"stdout"}function ht(r){if(!r||typeof r!="object"||Array.isArray(r))return;const t={};for(const[e,o]of Object.entries(r))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Tt(r){return r.failed===!0}function W(r,t,e){if(!r)return e?`${t}/${e}`:t;const o=`${t}__`;return r.startsWith(o)?I(`${t}__${r.slice(o.length)}`):I(r.replace("/","__"))}function St(r){return r==="read_file"||r==="edit_file"||r==="write_file"||r==="bash"}function At(r){const t=_t(r);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof r=="string"&&r.trim().length>0}function _t(r){if(r&&typeof r=="object"&&!Array.isArray(r))return r;if(!(typeof r!="string"||!r.trim()))try{const t=JSON.parse(r);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class Ft extends B{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const o=H(),s=e.mcpConfigPath||$(o),{resolved:n,configContextLimit:i}=await this.resolveAcodeProvider(e,s),a=n.model,u=i??mt(a),c=pt(a),m={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:u,maxOutput:c}};this.sessions.set(t,{adapterSession:m,config:e,runtime:await this.createRuntime(t,a,e,o),autoPollActive:!1}),this.emit("status-change",t,"starting");const d=this.sessions.get(t);if(!d)throw new Error("ACode session was not initialized");const g=()=>{const p=this.sessions.get(t);p&&this.getIdlePollLoop(p).start()};this.listenerWakeHooks.set(t,g),V(e.agentId,g);try{await d.runtime.start(),m.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:d.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(p){m.status="error",this.emitRuntimeErrorEvent(t,p),this.emit("status-change",t,"error");const h=this.sessions.get(t);throw h?.capabilitiesFallbackTimer&&clearTimeout(h.capabilitiesFallbackTimer),this.sessions.delete(t),E(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),p}}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),n=s.adapterSession.status;l(`[ACode] Previous status: ${n}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:D(),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: ${n} \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 a=Date.now();await s.runtime.submit(e);const u=Date.now()-a;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${u}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 c=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 ${c}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(a){const u=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${u}ms:`,a instanceof Error?a.message:String(a)),this.cancelSubmitTimeoutDetection(s),l("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,a,{recover:!0}),l(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}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},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&&(E(o,this.listenerWakeHooks.get(t)),X(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}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}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&&w(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 q.readFile(t,"utf-8"),o=JSON.parse(e),n=o.provider?.default,i=n?.options,a=b(o.contextLimit),u={},c=n?.models;if(c&&typeof c=="object"){for(const[m,d]of Object.entries(c))if(d&&typeof d=="object"){const g=b(d.contextLimit);g>0&&(u[m.trim()]=g)}}return{...n?.model?{model:n.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...a>0?{contextLimit:a}:{},...Object.keys(u).length>0?{modelContextLimits:u}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return P().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=P();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?O(t.instanceAiConfig):null,configPath:e}});const n={...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 a=i.contextLimit;if(!a&&i.modelContextLimits){const c=o||t.instanceAiConfig?.model||i.model;c&&i.modelContextLimits[c]&&(a=i.modelContextLimits[c])}const u=z(n,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:O(n),globalConfigModel:i?.model??null,resolvedModel:u.model,resolvedBaseURL:u.baseURL??null,resolvedApiKey:u.apiKey?"[set]":null,configContextLimit:a,resolvedSource:u.source}}),{resolved:u,configPath:e,perSessionModel:o,configContextLimit:a}}async createRuntime(t,e,o,s){const n=await this.loadRuntimeConstructor(),i=o.mcpConfigPath||$(s);let a=[];try{a=await Y(o.agentId,o.scopeKey)}catch(m){l(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,m.message)}const u=new n({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:i,skillsDir:K(s),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:Q,terminalManager:G,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:m=>J({...m,agentId:o.agentId,workspacePath:o.workingDirectory}),extraBuiltInTools:a});return P().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:i}}),u.on("event",m=>this.forwardAcodeEvent(m)),u}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=dt(),e=await import(ct(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 n=this.sessions.get(t);n&&(this.cancelSubmitTimeoutDetection(n),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:D(),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:ft(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==="ai_request"){const o=F(t.data);let s;if(o>0){const a=e.adapterSession.totalUsage.inputTokens;a>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(a*1.5)):e.adapterSession.totalUsage.inputTokens=o,s={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const i={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};s&&(i.usage=s),this.emit("status-change",t.sessionId,e.adapterSession.status,i),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:ht(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=gt(t.data.usage);if(o){const n=e.adapterSession.totalUsage.inputTokens;n>0&&o.inputTokens<Math.floor(n*.2)||(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens)}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}`),Tt(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}),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==="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 h=t.data.tools;h.some(f=>Z(f))||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 T=Array.isArray(t.data.servers)?t.data.servers:[],A=h.map(f=>({name:String(f.name??""),source:String(f.source??""),description:String(f.description??"")})).filter(f=>f.name),_={kind:"mcp",mcpServers:T,mcpTools:A};e.cachedMcpCapabilities=_,e.lastMcpCapabilities=_,e.lastCombinedCapabilities={kind:"combined",mcpServers:T,mcpTools:A,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${T.length} servers, ${A.length} tools`,{sessionId:t.sessionId,servers:T,toolNames:A.map(f=>f.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const f=e.cachedMcpCapabilities;if(!f)return;const y={...f,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:y,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(y)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${R}ms)`,{sessionId:t.sessionId,mcpServers:f.mcpServers,mcpToolsCount:f.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},R);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",n=typeof t.data.tool=="string"?t.data.tool:"",i=s&&n?`${s}__${n}`:n||s,a=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,u=et(i,a);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,u.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=St(u.actionType)?u.actionDetail||W(void 0,s,n):W(u.actionDetail,s,n),m=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,d=a?JSON.stringify(a,null,2):void 0,g={toolName:c,rawToolName:i,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:c,...d?{actionInput:d}:{},...a?{toolInput:a}:{},...m?{toolUseId:m,actionId:m}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...g,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const h=u.actionType==="idle"&&!At(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=h,this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const C=u.actionType==="idle";this.emit("status-change",t.sessionId,h,C||h==="thinking"?void 0:g);return}const p=u.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=p,p==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...g}),this.emitProviderEvent(t,"tool_use_start",g),this.emit("status-change",t.sessionId,p,g);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(d=>({name:String(d.name??""),description:typeof d.description=="string"?d.description:void 0,directory:typeof d.directory=="string"?d.directory:void 0})).filter(d=>d.name),n=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,a=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(d=>{const g=Array.isArray(d.skills)?d.skills:[];return{dir:typeof d.dir=="string"?d.dir:"",exists:d.exists===!0,skills:g.map(p=>({name:String(p.name??""),description:typeof p.description=="string"?p.description:void 0,directory:typeof p.directory=="string"?p.directory:void 0})).filter(p=>p.name)}}).filter(d=>d.dir),u=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,m={kind:"combined",mcpServers:u?.mcpServers??[],mcpTools:u?.mcpTools??[],skills:s,skillsDir:n,skillGroups:a};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:m,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(m)}),e.lastCombinedCapabilities=m,l(`[cap-diag] Combined capabilities emitted ${c?"(startup merge)":"(runtime refresh)"}: ${(u?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:u?.mcpServers??[],skillsDir:n}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="session_started"){const o=F(t.data),s=b(t.data.contextLimit)||void 0,n=b(t.data.maxOutput)||void 0,i=b(t.data.inputLimit)||void 0,a=b(t.data.compactionThreshold)||void 0;let u=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,u=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,u=!0),n!==void 0&&(e.adapterSession.totalUsage.maxOutput=n,u=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,u=!0),a!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=a,u=!0),u&&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,n=s==="start",i=s==="end",a=s==="phase",u=o.parentId,c=o.compactionId;let m,d;if(n){const p=String(o.sizeKB??o.sizeBeforeKB??"?"),h=String(o.messageCount??o.messageCountBefore??"?"),C=o.estimatedTokens,T=o.actualInputTokens?`input=${o.actualInputTokens}`:"",A=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",_=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";m="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",C!==void 0?d=`\u538B\u7F29\u524D: ~${C} tokens, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_:d=`\u538B\u7F29\u524D: ${p}KB, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_}else if(a)m=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),d=String(o.phaseDetail??"");else{const p=o.tokensBefore,h=o.tokensAfter,C=o.freedTokens,T=String(o.sizeBeforeKB??"?"),A=String(o.sizeAfterKB??"?"),_=String(o.freedKB??"?"),f=String(o.strategy??"?"),y=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);m="\u538B\u7F29\u5B8C\u6210",p!==void 0&&h!==void 0?d=`\u91CA\u653E: ${C??p-h} tokens, ${p} tokens \u2192 ${h} tokens, \u7B56\u7565: ${f}`+(y?`, \u88C1\u526A\u5DE5\u5177: ${y}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):d=`\u91CA\u653E: ${_}KB, ${T}KB \u2192 ${A}KB, \u7B56\u7565: ${f}`+(y?`, \u88C1\u526A\u5DE5\u5177: ${y}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}n&&(e.adapterSession.status="compacting");const g={actionType:"context_compaction",actionLabel:m,actionDetail:d};if(n&&c)g.actionId=c;else if((a||i)&&c)if(g.parentId=c,a){const p=String(o.phase??"unknown");g.actionId=`${c}-phase-${p}`}else g.actionId=`${c}-end`;a&&u&&!g.parentId&&(g.parentId=u),i&&(e.adapterSession.totalUsage.inputTokens=b(o.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,g.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",g),this.emit("status-change",t.sessionId,"compacting",g);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,o=t.config.agentId;return t.idlePollLoop=new tt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:s=>w(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,n)=>this.submitAutoPollPrompt(e,n?s:lt,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:s=>this.submitAutoPollPrompt(e,s)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const n=(s.autoPollToken??0)+1;s.autoPollToken=n,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,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!==n){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${n}, 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=nt){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,M,{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.adapterSession.status==="tool_using"&&e.pendingToolEventData){const a=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${a.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:{...a,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 a=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${a} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&w(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 a=this.sessions.get(t);if(!a||a.autoPollActive||this.isTerminalStatus(a.adapterSession.status)){a&&(a.failedTurnRecoveryScheduled=!1);return}a.autoPollTimer=void 0,a.failedTurnRecoveryScheduled=!1,a.idleCommands?.idleInputCommand?this.getIdlePollLoop(a).start():this.submitAutoPollPrompt(t,M,{keepWaitingStatus:!0})},rt)}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,n=!!(o&&w(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",n),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 n=s.adapterSession.status,i=Date.now();if(n==="waiting_input"){s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(n==="tool_using"){const c=i-(s.watchdogLastDataFlowTime||i);if(c>=at){const m=String(s.pendingToolEventData?.rawToolName??"");if(m.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_complete is running (session: ${t}, tool: ${m}), 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(c/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(c/1e3)}s): detached tool ${m} 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",c);return}s.watchdogSubmitStartTime=i;return}if(n!=="thinking")return;const a=i-(s.watchdogSubmitStartTime||i),u=i-(s.watchdogLastDataFlowTime||i);if(u>=it){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(u/1e3)}s (source: ${o}, session: ${t}, status: ${n}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",u);return}if(a>=ut){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(a/1e3)}s (source: ${o}, session: ${t}, status: ${n}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",a);return}},st)}executeWatchdogRecovery(t,e,o,s,n){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(n/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()}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=`
|
|
5
5
|
|
|
6
6
|
\u8BF7\u6C42\u4F53:
|
|
7
|
-
`,n=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",a=typeof t.requestMethod=="string"?t.requestMethod:"",
|
|
7
|
+
`,n=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",a=typeof t.requestMethod=="string"?t.requestMethod:"",u=typeof t.stream=="boolean"?t.stream:void 0,c=typeof t.messageCount=="number"?t.messageCount:void 0,m=typeof t.toolCount=="number"?t.toolCount:void 0,d=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",g=[n?`\u6A21\u578B: ${n}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,a?`\u65B9\u6CD5: ${a}`:void 0,u!==void 0?`\u6D41\u5F0F: ${u?"\u662F":"\u5426"}`:void 0,c!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${c}`:void 0,m!==void 0?`\u53EF\u7528\u5DE5\u5177: ${m}`:void 0,d?`\u6700\u540E\u8BF7\u6C42: ${d}`:void 0].filter(S=>!!S),p=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,h=t.requestHeaders,C=h?Object.entries(h).filter(([S])=>!p.test(S)).map(([S,x])=>`${S}: ${x}`).filter(S=>S.trim().length>0):[],T=g.join(`
|
|
8
8
|
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",A=C.length>0?`${e}${C.join(`
|
|
9
9
|
`)}`:"",_=typeof t.requestBody=="string"?t.requestBody:"",f=_.length>6e4?`${_.slice(0,6e4)}
|
|
10
|
-
...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:_,
|
|
10
|
+
...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:_,y=f?`${o}${f}`:"";return`${T}${A}${y}`}}export{Ft as AcodeSdkAdapter,Tt as isFailedAcodeTurnComplete,ct as toAcodeEsmImportSpecifier};
|
|
11
11
|
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import I from"express";import B from"cors";import{existsSync as D,readFileSync as E}from"node:fs";import x from"node:path";import M from"node:os";import{allowedCorsOrigins as y,port as h,validateProductionToken as O}from"./config.js";import{propertiesRouter as G}from"./routes/properties.js";import{ymlRouter as _}from"./routes/yml.js";import{instanceRouter as F,setGracefulShutdownFn as K}from"./routes/instance.js";import{skillsRouter as L}from"./routes/skills.js";import{mcpRouter as N}from"./routes/mcp.js";import{terminalRouter as j,sdkSessions as S}from"./routes/terminal.js";import{sessionsRouter as W}from"./routes/sessions.js";import{gitRouter as U}from"./routes/git.js";import{fileSnapshotRouter as z}from"./routes/file-snapshot.js";import{acodeTodosRouter as J}from"./routes/acode-todos.js";import{backgroundTasksRouter as Y}from"./routes/background-tasks.js";import{subAgentsRouter as q}from"./routes/sub-agents.js";import{browserSessionsRouter as H}from"./routes/browser-sessions.js";import{browserListenersRouter as Z}from"./routes/browser-listeners.js";import{fileBrowserRouter as Q}from"./routes/file-browser.js";import{aiSourcesRouter as V}from"./routes/ai-sources.js";import{processesRouter as X}from"./routes/processes.js";import{systemMetricsRouter as ee}from"./routes/system-metrics.js";import{taskContextRouter as re}from"./routes/task-context.js";import{fileDiffRollbackRouter as te}from"./routes/file-diff-rollback.js";import{attachPtyWebSocketServer as ie,closeAllPtySessions as ne,ptyRouter as oe,ptySessions as se}from"./routes/pty.js";import{runtimeBindingRouter as ae,logRuntimeBindingStartupState as me}from"./routes/runtime-binding.js";import{dashboardRouter as ue}from"./routes/dashboard.js";import{eventsRouter as ce}from"./routes/events.js";import{attachRemoteDesktopWebSocketServer as de}from"./remote-desktop/index.js";import{attachBrowserWebSocketServer as ge}from"./browser/browser-ws-bridge.js";import{loadPersistedSessions as P,savePersistedSessions as $}from"./services/terminal-persistence.js";import{detectOrphanProcesses as pe}from"./services/process-detector.js";import{startOrphanMonitor as fe,stopOrphanMonitor as le}from"./services/orphan-monitor.js";import{getAgentProcessManager as k}from"./services/agent-process-manager.js";import{adapterRegistry as be}from"./adapter/index.js";import{logger as e}from"./utils/logger.js";import{autoRegister as we,unregister as he,bridgeRestartCleanup as Se,cancelBackgroundRegisterRetries as Re}from"./services/auto-register.js";import{stopTunnelClient as Ie}from"./services/tunnel-client.js";import{ensureAwsClientAgentMcpReleased as ye}from"./services/aws-client-agent-mcp.js";import{ensureAcodePackageReleased as Pe}from"./services/acode-package.js";import{ensureStartupConfig as $e}from"./services/startup-config-wizard.js";import{handleCliCommand as ke}from"./services/cli-commands.js";import{migrateOldPathsOnStartup as Ce}from"./services/legacy-path-migration.js";import{subAgentStore as Te}from"./services/sub-agent-manager-instance.js";import{disposeBrowserSessionManager as ve}from"./services/browser-session-manager.js";import{buildGracefulShutdownPlan as Ae,shouldCleanupPersistedSessionsOnStartup as Be}from"./services/runtime-lifecycle-policy.js";import{deliverPendingBridgeLifecycleNotifications as De}from"./services/lifecycle-state.js";const C=await ke();C.handled&&process.exit(C.exitCode),await $e(),O(),ye(),Pe(),Ce(),me();async function Ee(){try{if(await we())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:i}=await import("./services/auto-register.js"),s=i();!!s.userKey&&s.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info("[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json"))}}catch(r){const i=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",i.message)}}Ee().then(()=>xe()).then(()=>De()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)});async function xe(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),i=r();if(!i.registered||!i.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const s=await Se();s.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${s.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${s.error}`)}catch(r){const i=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",i.message)}}async function Me(){try{const r=await P();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await k().rebuildRegistry(r.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const i=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",i.message)}}Me().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u51FA\u9519:",r)});async function Oe(){try{const r=await import("node:fs/promises"),i=await import("node:path"),s=await import("node:os"),f=i.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(f,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(f),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await P();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!Be(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await k().rebuildRegistry(a.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const d=await pe(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(d.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of d)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of d)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:o}=await import("node:child_process");o(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(o){const c=o;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await $([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const i=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",i.message)}}Oe().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),fe().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const n=I();n.use(B({origin(r,i){if(!r){i(null,!0);return}if(y.includes("*")){i(null,!0);return}if(y.includes(r)){i(null,!0);return}try{if(new URL(r).port===String(h)){i(null,!0);return}}catch{}i(new Error(`[runtime-bridge] CORS origin is not allowed: ${r}`))}})),n.use(I.json({limit:"1mb"})),n.use("/runtime",ae),n.use("/runtime",G),n.use("/runtime",_),n.use("/runtime",F),n.use("/runtime",L),n.use("/runtime",N),n.use("/runtime",j),n.use("/runtime",W),n.use("/runtime",X),n.use("/runtime",ee),n.use("/runtime",ce),n.use("/runtime",U),n.use("/runtime",z),n.use("/runtime",J),n.use("/runtime",Y),n.use("/runtime",q),n.use("/runtime",H),n.use("/runtime",Z),n.use("/runtime",V),n.use("/runtime",re),n.use("/runtime",te),n.use("/pty",oe),n.use("/",ue),n.use("/api/file-browser",Q);function Ge(){const r=n.listen(h,()=>{e.info(`[runtime-bridge] listening on ${h}`)});return ie(r),de(r),ge(r),r.on("error",i=>{if(i.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${h} is already in use. Stop the existing runtime-bridge process or set AWS_RUNTIME_BRIDGE_PORT to another port before starting.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",i),process.exitCode=1}),r}let T=!1;async function b(r,i,s=!1){if(T){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}T=!0,s||R()&&(s=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${s})`);const f=Date.now(),u=Ae(s);try{const a=S.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,o]of S.entries())try{const c=o.providerId||"claude-code",g=be.get(c);let p="";try{const m=g.getSessionPid?.(t);m&&(p=` (PID: ${m})`)}catch{}await g.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${p}`),S.delete(t)}catch(c){const g=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,g.message),S.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const l=se.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),ne("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${l} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`),e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+require("path").join(__dirname,"..","package","acode","dist","background-command-manager.js")).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(le(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:o}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),g=await c();if(g.length>0){const p=await t(g.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(p.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${p.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of p)if(m.process.pid){const A=await o(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${A.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const o=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",o.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await he()}catch(t){const o=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Re(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),Ie()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await $([])}catch(t){const o=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await ve(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}const d=Date.now()-f;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${d}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),i.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const l=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",l),process.exit(1)}}Te.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const w=Ge(),v=x.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(D(v)){const r=E(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}K(async(r,i)=>{await b(r,w,i)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",w,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",w,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",w,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",w)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
|
|
2
|
+
import{existsSync as D,readFileSync as B}from"node:fs";import E from"node:os";import x from"node:path";import M from"cors";import I from"express";import{adapterRegistry as O}from"./adapter/index.js";import{attachBrowserWebSocketServer as G}from"./browser/browser-ws-bridge.js";import{allowedCorsOrigins as y,port as h,validateProductionToken as _}from"./config.js";import{attachRemoteDesktopWebSocketServer as F}from"./remote-desktop/index.js";import{acodeTodosRouter as K}from"./routes/acode-todos.js";import{aiSourcesRouter as L}from"./routes/ai-sources.js";import{backgroundTasksRouter as N}from"./routes/background-tasks.js";import{browserListenersRouter as j}from"./routes/browser-listeners.js";import{browserSessionsRouter as W}from"./routes/browser-sessions.js";import{computerRouter as U}from"./routes/computer.js";import{dashboardRouter as z}from"./routes/dashboard.js";import{eventsRouter as J}from"./routes/events.js";import{fileBrowserRouter as Y}from"./routes/file-browser.js";import{fileChangeDiffRouter as q}from"./routes/file-change-diff.js";import{fileDiffRollbackRouter as H}from"./routes/file-diff-rollback.js";import{fileSnapshotRouter as Z}from"./routes/file-snapshot.js";import{gitRouter as Q}from"./routes/git.js";import{instanceRouter as V,setGracefulShutdownFn as X}from"./routes/instance.js";import{mcpRouter as ee}from"./routes/mcp.js";import{processesRouter as re}from"./routes/processes.js";import{propertiesRouter as te}from"./routes/properties.js";import{attachPtyWebSocketServer as ie,closeAllPtySessions as oe,ptyRouter as ne,ptySessions as se}from"./routes/pty.js";import{runtimeBindingRouter as ae,logRuntimeBindingStartupState as me}from"./routes/runtime-binding.js";import{sessionsRouter as ue}from"./routes/sessions.js";import{skillsRouter as ce}from"./routes/skills.js";import{subAgentsRouter as de}from"./routes/sub-agents.js";import{systemMetricsRouter as ge}from"./routes/system-metrics.js";import{taskContextRouter as pe}from"./routes/task-context.js";import{terminalRouter as fe,sdkSessions as S}from"./routes/terminal.js";import{ymlRouter as le}from"./routes/yml.js";import{ensureAcodePackageReleased as be}from"./services/acode-package.js";import{getAgentProcessManager as P}from"./services/agent-process-manager.js";import{autoRegister as we,unregister as he,bridgeRestartCleanup as Se,cancelBackgroundRegisterRetries as Re}from"./services/auto-register.js";import{ensureAwsClientAgentMcpReleased as Ie}from"./services/aws-client-agent-mcp.js";import{disposeBrowserSessionManager as ye}from"./services/browser-session-manager.js";import{handleCliCommand as Pe}from"./services/cli-commands.js";import{migrateOldPathsOnStartup as $e}from"./services/legacy-path-migration.js";import{deliverPendingBridgeLifecycleNotifications as ke}from"./services/lifecycle-state.js";import{startOrphanMonitor as Ce,stopOrphanMonitor as Te}from"./services/orphan-monitor.js";import{detectOrphanProcesses as ve}from"./services/process-detector.js";import{buildGracefulShutdownPlan as Ae,shouldCleanupPersistedSessionsOnStartup as De}from"./services/runtime-lifecycle-policy.js";import{ensureStartupConfig as Be}from"./services/startup-config-wizard.js";import{subAgentStore as Ee}from"./services/sub-agent-manager-instance.js";import{loadPersistedSessions as $,savePersistedSessions as k}from"./services/terminal-persistence.js";import{stopTunnelClient as xe}from"./services/tunnel-client.js";import{logger as e}from"./utils/logger.js";const C=await Pe();C.handled&&process.exit(C.exitCode),await Be(),_(),Ie(),be(),$e(),me();async function Me(){try{if(await we())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:i}=await import("./services/auto-register.js"),s=i();!!s.userKey&&s.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info("[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json"))}}catch(r){const i=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",i.message)}}Me().then(()=>Oe()).then(()=>ke()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)});async function Oe(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),i=r();if(!i.registered||!i.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const s=await Se();s.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${s.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${s.error}`)}catch(r){const i=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",i.message)}}async function Ge(){try{const r=await $();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await P().rebuildRegistry(r.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const i=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",i.message)}}Ge().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u51FA\u9519:",r)});async function _e(){try{const r=await import("node:fs/promises"),i=await import("node:path"),s=await import("node:os"),f=i.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(f,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(f),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await $();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!De(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await P().rebuildRegistry(a.map(n=>({agentId:n.agentId,sessionId:n.sessionId,pid:n.pid,workspacePath:n.workspacePath,command:n.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const d=await ve(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(d.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of d)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of d)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:n}=await import("node:child_process");n(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(n){const c=n;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await k([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const i=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",i.message)}}_e().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),Ce().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const o=I();o.use(M({origin(r,i){if(!r){i(null,!0);return}if(y.includes("*")){i(null,!0);return}if(y.includes(r)){i(null,!0);return}try{if(new URL(r).port===String(h)){i(null,!0);return}}catch{}i(new Error(`[runtime-bridge] CORS origin is not allowed: ${r}`))}})),o.use(I.json({limit:"1mb"})),o.use("/runtime",ae),o.use("/runtime",te),o.use("/runtime",le),o.use("/runtime",V),o.use("/runtime",ce),o.use("/runtime",ee),o.use("/runtime",fe),o.use("/runtime",ue),o.use("/runtime",re),o.use("/runtime",ge),o.use("/runtime",J),o.use("/runtime",Q),o.use("/runtime",Z),o.use("/runtime",K),o.use("/runtime",N),o.use("/runtime",de),o.use("/runtime",W),o.use("/runtime",j),o.use("/runtime",L),o.use("/runtime",pe),o.use("/runtime",H),o.use("/runtime",q),o.use("/runtime/computer",U),o.use("/pty",ne),o.use("/",z),o.use("/api/file-browser",Y);function Fe(){const r=o.listen(h,()=>{e.info(`[runtime-bridge] listening on ${h}`)});return ie(r),F(r),G(r),r.on("error",i=>{if(i.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${h} is already in use. Stop the existing runtime-bridge process or set AWS_RUNTIME_BRIDGE_PORT to another port before starting.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",i),process.exitCode=1}),r}let T=!1;async function b(r,i,s=!1){if(T){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}T=!0,s||R()&&(s=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${s})`);const f=Date.now(),u=Ae(s);try{const a=S.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,n]of S.entries())try{const c=n.providerId||"claude-code",g=O.get(c);let p="";try{const m=g.getSessionPid?.(t);m&&(p=` (PID: ${m})`)}catch{}await g.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${p}`),S.delete(t)}catch(c){const g=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,g.message),S.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const l=se.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),oe("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${l} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`),e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+require("path").join(__dirname,"..","package","acode","dist","background-command-manager.js")).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(Te(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:n}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),g=await c();if(g.length>0){const p=await t(g.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(p.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${p.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of p)if(m.process.pid){const A=await n(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${A.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const n=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",n.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await he()}catch(t){const n=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",n.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Re(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),xe()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await k([])}catch(t){const n=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",n.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await ye(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}const d=Date.now()-f;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${d}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),i.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const l=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",l),process.exit(1)}}Ee.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const w=Fe(),v=x.join(E.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(D(v)){const r=B(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}X(async(r,i)=>{await b(r,w,i)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",w,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",w,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",w,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",w)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
|
|
3
3
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ScreenInfo, DesktopWindowInfo, OpenWithApp, DesktopFileEntry, UIElement, FlatNode } from "./types.js";
|
|
2
|
+
export interface WindowTarget {
|
|
3
|
+
hwnd?: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
pid?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface WindowRectPatch {
|
|
8
|
+
x?: number;
|
|
9
|
+
y?: number;
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface FullResScreenshot {
|
|
15
|
+
jpeg: Buffer;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
screen: ScreenInfo;
|
|
19
|
+
}
|
|
20
|
+
export interface UIElementTreeResult {
|
|
21
|
+
|
|
22
|
+
elements: UIElement[];
|
|
23
|
+
|
|
24
|
+
flatNodes: FlatNode[];
|
|
25
|
+
}
|
|
26
|
+
export interface ComputerUseBackend {
|
|
27
|
+
|
|
28
|
+
readonly platform: "windows" | "macos" | "linux";
|
|
29
|
+
|
|
30
|
+
readonly viaSidecar: boolean;
|
|
31
|
+
|
|
32
|
+
startPersistentProcess(): void;
|
|
33
|
+
listScreens(): Promise<ScreenInfo[]>;
|
|
34
|
+
|
|
35
|
+
captureFullResJpeg(screenId?: string): Promise<FullResScreenshot>;
|
|
36
|
+
|
|
37
|
+
setActiveScreen(screen: ScreenInfo): void;
|
|
38
|
+
getScreenSize(): {
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
};
|
|
42
|
+
moveMouse(x: number, y: number): Promise<void>;
|
|
43
|
+
click(x: number, y: number, button?: "left" | "right"): Promise<void>;
|
|
44
|
+
|
|
45
|
+
clickOs(x: number, y: number, button?: "left" | "right"): Promise<void>;
|
|
46
|
+
doubleClick(x: number, y: number): Promise<void>;
|
|
47
|
+
mouseDown(button?: "left" | "right"): Promise<void>;
|
|
48
|
+
mouseUp(button?: "left" | "right"): Promise<void>;
|
|
49
|
+
scroll(direction: "up" | "down" | "left" | "right", amount: number): Promise<void>;
|
|
50
|
+
type(text: string): Promise<void>;
|
|
51
|
+
keyPress(keys: string[]): Promise<void>;
|
|
52
|
+
keyDown(key: string): Promise<void>;
|
|
53
|
+
keyUp(key: string): Promise<void>;
|
|
54
|
+
drag(fromX: number, fromY: number, toX: number, toY: number, button?: "left" | "right"): Promise<void>;
|
|
55
|
+
getClipboard(): Promise<string>;
|
|
56
|
+
setClipboard(text: string): Promise<void>;
|
|
57
|
+
listWindows(): Promise<DesktopWindowInfo[]>;
|
|
58
|
+
activateWindow(target: WindowTarget): Promise<{
|
|
59
|
+
ok: boolean;
|
|
60
|
+
hwnd: string;
|
|
61
|
+
title?: string;
|
|
62
|
+
}>;
|
|
63
|
+
setWindowRect(target: WindowTarget, rect: WindowRectPatch): Promise<{
|
|
64
|
+
ok: boolean;
|
|
65
|
+
hwnd: string;
|
|
66
|
+
}>;
|
|
67
|
+
minimizeWindow(target: WindowTarget): Promise<{
|
|
68
|
+
ok: boolean;
|
|
69
|
+
}>;
|
|
70
|
+
maximizeWindow(target: WindowTarget): Promise<{
|
|
71
|
+
ok: boolean;
|
|
72
|
+
}>;
|
|
73
|
+
restoreWindow(target: WindowTarget): Promise<{
|
|
74
|
+
ok: boolean;
|
|
75
|
+
}>;
|
|
76
|
+
getZOrder(): Promise<DesktopWindowInfo[]>;
|
|
77
|
+
getForeground(): Promise<DesktopWindowInfo | null>;
|
|
78
|
+
launchApp(command: string): Promise<{
|
|
79
|
+
ok: boolean;
|
|
80
|
+
pid?: number;
|
|
81
|
+
}>;
|
|
82
|
+
openFile(filePath: string, app?: string): Promise<{
|
|
83
|
+
ok: boolean;
|
|
84
|
+
app?: string;
|
|
85
|
+
}>;
|
|
86
|
+
listOpenWith(filePath: string): Promise<OpenWithApp[]>;
|
|
87
|
+
listDir(path: string, opts?: {
|
|
88
|
+
includeHidden?: boolean;
|
|
89
|
+
}): Promise<{
|
|
90
|
+
path: string;
|
|
91
|
+
entries: DesktopFileEntry[];
|
|
92
|
+
}>;
|
|
93
|
+
listProcesses(): Promise<Array<{
|
|
94
|
+
pid: number;
|
|
95
|
+
name: string;
|
|
96
|
+
}>>;
|
|
97
|
+
|
|
98
|
+
getUIElementsTree(pid: number): Promise<UIElement[]>;
|
|
99
|
+
|
|
100
|
+
traverseNodes(pid: number): Promise<FlatNode[]>;
|
|
101
|
+
findElementsByName(pid: number, text: string, role?: string): Promise<FlatNode[]>;
|
|
102
|
+
findEditableByName(pid: number, text: string): Promise<FlatNode | null>;
|
|
103
|
+
findElementBounds(pid: number, path: string): Promise<{
|
|
104
|
+
x: number;
|
|
105
|
+
y: number;
|
|
106
|
+
width: number;
|
|
107
|
+
height: number;
|
|
108
|
+
} | null>;
|
|
109
|
+
findElementByFingerprint(pid: number, fingerprint: string): Promise<FlatNode | null>;
|
|
110
|
+
invalidateCache(pid?: number): void;
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -63,6 +63,37 @@ export interface StartResult {
|
|
|
63
63
|
permissions: RemoteDesktopCapability[];
|
|
64
64
|
}
|
|
65
65
|
export type ConnectionState = 'idle' | 'connecting' | 'authenticating' | 'connected' | 'disconnected' | 'error';
|
|
66
|
+
|
|
67
|
+
export interface DesktopWindowInfo {
|
|
68
|
+
hwnd: string;
|
|
69
|
+
title: string;
|
|
70
|
+
pid?: number;
|
|
71
|
+
processName?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface OpenWithApp {
|
|
75
|
+
|
|
76
|
+
name: string;
|
|
77
|
+
|
|
78
|
+
command: string;
|
|
79
|
+
|
|
80
|
+
isDefault?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface DesktopFileEntry {
|
|
84
|
+
|
|
85
|
+
name: string;
|
|
86
|
+
|
|
87
|
+
path: string;
|
|
88
|
+
|
|
89
|
+
type: "file" | "directory" | "symlink" | "other";
|
|
90
|
+
|
|
91
|
+
size?: number;
|
|
92
|
+
|
|
93
|
+
mtime?: number;
|
|
94
|
+
|
|
95
|
+
isHidden?: boolean;
|
|
96
|
+
}
|
|
66
97
|
export interface AppInfo {
|
|
67
98
|
pid: number;
|
|
68
99
|
name: string;
|
|
@@ -80,6 +111,10 @@ export interface UIElement {
|
|
|
80
111
|
role: string;
|
|
81
112
|
name?: string;
|
|
82
113
|
value?: string;
|
|
114
|
+
|
|
115
|
+
automationId?: string;
|
|
116
|
+
|
|
117
|
+
fingerprint?: string;
|
|
83
118
|
bounds?: {
|
|
84
119
|
x: number;
|
|
85
120
|
y: number;
|
|
@@ -91,3 +126,47 @@ export interface UIElement {
|
|
|
91
126
|
isFocused?: boolean;
|
|
92
127
|
isEditable?: boolean;
|
|
93
128
|
}
|
|
129
|
+
|
|
130
|
+
export interface FlatNode {
|
|
131
|
+
path: string;
|
|
132
|
+
role: string;
|
|
133
|
+
name?: string;
|
|
134
|
+
value?: string;
|
|
135
|
+
aid?: string;
|
|
136
|
+
x: number;
|
|
137
|
+
y: number;
|
|
138
|
+
w: number;
|
|
139
|
+
h: number;
|
|
140
|
+
actions?: string[];
|
|
141
|
+
|
|
142
|
+
fingerprint?: string;
|
|
143
|
+
}
|
|
144
|
+
export interface StateDiff {
|
|
145
|
+
added: UIElement[];
|
|
146
|
+
removed: UIElement[];
|
|
147
|
+
changed: Array<{
|
|
148
|
+
before: UIElement;
|
|
149
|
+
after: UIElement;
|
|
150
|
+
}>;
|
|
151
|
+
|
|
152
|
+
changedSummary: string;
|
|
153
|
+
}
|
|
154
|
+
export interface ActionVerification {
|
|
155
|
+
stateBefore: string;
|
|
156
|
+
stateAfter: string;
|
|
157
|
+
changed: boolean;
|
|
158
|
+
diff?: StateDiff;
|
|
159
|
+
|
|
160
|
+
toastDetected?: boolean;
|
|
161
|
+
|
|
162
|
+
windowChanged?: boolean;
|
|
163
|
+
|
|
164
|
+
summary: string;
|
|
165
|
+
}
|
|
166
|
+
export interface ActionResult {
|
|
167
|
+
ok: boolean;
|
|
168
|
+
elementId?: string;
|
|
169
|
+
x?: number;
|
|
170
|
+
y?: number;
|
|
171
|
+
verification?: ActionVerification;
|
|
172
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const computerRouter: import("express-serve-static-core").Router;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Router as s}from"express";const e=s();function t(i,o){o.status(503).json({error:"desktop capability is not implemented\uFF08\u684C\u9762\u64CD\u4F5C\u529F\u80FD\u5DF2\u4E0B\u7EBF\uFF0C\u5F85\u540E\u7EED\u7248\u672C\u91CD\u65B0\u5B9E\u73B0\uFF09"})}e.get("/screens",t),e.get("/windows",t),e.get("/window/z-order",t),e.get("/window/foreground",t),e.get("/processes",t),e.get("/file/open-with",t),e.get("/ui-tree",t),e.get("/describe-state",t),e.get("/clipboard",t),e.get("/list-dir",t),e.post("/screenshot",t),e.post("/vision-query",t),e.post("/mouse",t),e.post("/scroll",t),e.post("/keyboard",t),e.post("/drag",t),e.post("/window/activate",t),e.post("/window/move",t),e.post("/window/resize",t),e.post("/window/minimize",t),e.post("/window/maximize",t),e.post("/window/restore",t),e.post("/launch",t),e.post("/open-file",t),e.post("/ui-element/click",t),e.post("/ui-element/set-value",t),e.post("/ui-element/click-by-text",t),e.post("/ui-element/select-menu",t),e.post("/ui-element/fill-form",t),e.post("/clipboard",t);export{e as computerRouter};
|
|
2
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export declare const fileChangeDiffRouter: import("express-serve-static-core").Router;
|
|
3
|
+
|
|
4
|
+
export type ChangeDiffLineType = 'hunk' | 'context' | 'add' | 'remove';
|
|
5
|
+
|
|
6
|
+
export interface ChangeDiffLine {
|
|
7
|
+
type: ChangeDiffLineType;
|
|
8
|
+
|
|
9
|
+
text: string;
|
|
10
|
+
|
|
11
|
+
oldLine: number | null;
|
|
12
|
+
|
|
13
|
+
newLine: number | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ChangeDiffResponse {
|
|
17
|
+
available: boolean;
|
|
18
|
+
operation: string;
|
|
19
|
+
filePath: string;
|
|
20
|
+
lines: ChangeDiffLine[];
|
|
21
|
+
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export declare function parseDiffPatchLines(patch: string): ChangeDiffLine[];
|
|
26
|
+
|
|
27
|
+
export declare function buildChangeDiffResponse(workspacePath: string, cacheKey: string | null | undefined, operation: string, filePath: string): Promise<ChangeDiffResponse>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{promises as m}from"node:fs";import p from"node:path";import{Router as d}from"express";import{createLogger as h}from"../utils/logger.js";import{validateToken as g}from"../middleware/auth.js";import{readBeforeContentFromCache as v,readDiffFromCache as b}from"../services/workspaceTaskChangeWatcher.js";const x=h("file-change-diff"),y=d();function L(s){const n=[];let o=0,e=0;for(const r of s.split(`
|
|
2
|
+
`)){const t=r;if(t.startsWith("@@")){const i=t.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);i&&(o=Number(i[1]),e=Number(i[2])),n.push({type:"hunk",text:t,oldLine:o,newLine:e});continue}if(!(t.startsWith("--- ")||t.startsWith("+++ ")||t.startsWith("Index:")||t.startsWith("===")||t.startsWith("\\ No newline"))){if(t.startsWith("+")){n.push({type:"add",text:t,oldLine:null,newLine:e}),e++;continue}if(t.startsWith("-")){n.push({type:"remove",text:t,oldLine:o,newLine:null}),o++;continue}if(t.startsWith(" ")){n.push({type:"context",text:t,oldLine:o,newLine:e}),o++,e++;continue}}}return n}async function W(s,n,o,e){const r=String(o||"").toUpperCase();if(r==="UPDATE"){if(!n)return{available:!1,operation:r,filePath:e,lines:[],error:"\u7F3A\u5C11 cacheKey\uFF0C\u65E0\u6CD5\u8BFB\u53D6 diff \u7F13\u5B58"};const t=await b(s,n);return t===null?{available:!1,operation:r,filePath:e,lines:[],error:`\u672C\u5730\u7F13\u5B58\u4E2D\u627E\u4E0D\u5230 diff \u8865\u4E01\uFF08cacheKey=${n}\uFF09\uFF0C\u7F13\u5B58\u53EF\u80FD\u5DF2\u88AB\u6E05\u7406`}:{available:!0,operation:r,filePath:e,lines:L(t)}}if(r==="DELETE"){if(!n)return{available:!1,operation:r,filePath:e,lines:[],error:"\u7F3A\u5C11 cacheKey\uFF0C\u65E0\u6CD5\u8BFB\u53D6\u53D8\u66F4\u524D\u5185\u5BB9"};const t=await v(s,n);if(t===null)return{available:!1,operation:r,filePath:e,lines:[],error:`\u672C\u5730\u7F13\u5B58\u4E2D\u627E\u4E0D\u5230\u53D8\u66F4\u524D\u5185\u5BB9\uFF08cacheKey=${n}\uFF09\uFF0C\u7F13\u5B58\u53EF\u80FD\u5DF2\u88AB\u6E05\u7406`};const i=t.split(`
|
|
3
|
+
`);i.length>0&&i[i.length-1]===""&&i.pop();const l=i.map((a,f)=>({type:"remove",text:`-${a}`,oldLine:f+1,newLine:null}));return{available:!0,operation:r,filePath:e,lines:l}}if(r==="CREATE")try{const t=p.resolve(s),i=p.resolve(s,e);if(!i.startsWith(t))return{available:!1,operation:r,filePath:e,lines:[],error:"\u8DEF\u5F84\u8D8A\u754C\uFF0C\u62D2\u7EDD\u8BFB\u53D6\u5DE5\u4F5C\u533A\u5916\u6587\u4EF6"};const a=(await m.readFile(i,"utf-8")).split(`
|
|
4
|
+
`);a.length>0&&a[a.length-1]===""&&a.pop();const f=a.map((u,c)=>({type:"add",text:`+${u}`,oldLine:null,newLine:c+1}));return{available:!0,operation:r,filePath:e,lines:f}}catch{return{available:!1,operation:r,filePath:e,lines:[],error:"\u65B0\u589E\u6587\u4EF6\u5F53\u524D\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BFB\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF09\uFF0C\u65E0\u6CD5\u5C55\u793A\u5185\u5BB9"}}return{available:!1,operation:r,filePath:e,lines:[],error:`\u4E0D\u652F\u6301\u7684\u64CD\u4F5C\u7C7B\u578B: ${r}`}}y.post("/file-change-diff/read",g,async(s,n)=>{const{workspacePath:o,cacheKey:e,operation:r,filePath:t}=s.body||{};if(!o||!String(o).trim()){n.status(400).json({error:"workspacePath is required"});return}if(!r||!String(r).trim()){n.status(400).json({error:"operation is required"});return}if(!t||!String(t).trim()){n.status(400).json({error:"filePath is required"});return}try{const i=await W(String(o).trim(),e?String(e).trim():null,String(r).trim(),String(t).trim());n.json(i)}catch(i){const l=i instanceof Error?i.message:String(i);x.warn(`[file-change-diff] \u8BFB\u53D6 diff \u5931\u8D25: ${l}`),n.status(500).json({ok:!1,error:l})}});export{W as buildChangeDiffResponse,y as fileChangeDiffRouter,L as parseDiffPatchLines};
|
|
5
|
+
|