aws-runtime-bridge 1.9.183 → 1.9.184

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +30 -1
  3. package/dist/adapter/AcodeSdkAdapter.js +3 -3
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts +3 -1
  5. package/dist/adapter/ClaudeSdkAdapter.js +3 -3
  6. package/dist/adapter/CodexSdkAdapter.d.ts +3 -1
  7. package/dist/adapter/CodexSdkAdapter.js +2 -2
  8. package/dist/adapter/OpencodeSdkAdapter.d.ts +3 -1
  9. package/dist/adapter/OpencodeSdkAdapter.js +3 -3
  10. package/dist/adapter/types.d.ts +7 -1
  11. package/dist/index.js +1 -1
  12. package/dist/routes/terminal.d.ts +13 -0
  13. package/dist/routes/terminal.js +28 -28
  14. package/dist/services/agent-ownership.d.ts +16 -0
  15. package/dist/services/agent-ownership.js +2 -2
  16. package/dist/services/plugin-deployment.d.ts +14 -0
  17. package/dist/services/plugin-deployment.js +2 -2
  18. package/dist/services/plugin-manager.d.ts +3 -0
  19. package/dist/services/plugin-manager.js +4 -4
  20. package/dist/services/plugin-runtime.d.ts +10 -2
  21. package/dist/services/user-scope.d.ts +1 -0
  22. package/dist/services/user-scope.js +1 -1
  23. package/package/acode/dist/background-command-manager.d.ts +22 -0
  24. package/package/acode/dist/background-command-manager.js +5 -5
  25. package/package/acode/dist/built-in-file-tools.js +2 -2
  26. package/package/acode/dist/hibernation-journal.d.ts +67 -0
  27. package/package/acode/dist/hibernation-journal.js +2 -0
  28. package/package/acode/dist/index.d.ts +1 -0
  29. package/package/acode/dist/index.js +1 -1
  30. package/package/acode/dist/runtime-environment.d.ts +4 -1
  31. package/package/acode/dist/runtime-environment.js +3 -3
  32. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +7 -0
  33. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  34. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +2 -0
  35. package/package/aws-client-agent-mcp/dist/mcp-server.js +4 -4
  36. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +8 -0
  37. package/package/aws-client-agent-mcp/dist/mcp-tools.js +20 -20
  38. package/package/aws-client-agent-mcp/dist/types.d.ts +5 -0
  39. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import{execSync as y}from"child_process";import{EventEmitter as k}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{registerListenerWakeHook as v,unregisterListenerWakeHook as g}from"../services/browser-session-manager.js";import{injectEffectiveEnvIntoMcpServers as x}from"../services/mcp-env-injector.js";import{getPanelEnvVars as _,getAgentMeta as w}from"../services/panel-env.js";import{importBridgeSdkPackage as C}from"../utils/sdk-package-loader.js";import{IdlePollLoop as b}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as P}from"./prompts.js";import{getToolActionInfo as f}from"./types.js";class T{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>{if(this.queue.length>0){const t=this.queue.shift();if(t!==void 0)return Promise.resolve({value:t,done:!1})}return this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}}class N extends k{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map,this.sessionAgentIds=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const i={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};if(this.sessions.set(t,i),e.agentId&&this.sessionAgentIds.set(t,e.agentId),e.agentId){const n=()=>{this.getIdlePollLoop(t).start()};this.listenerWakeHooks.set(t,n),v(e.agentId,n)}try{const n=await this.loadSdk(),o=new AbortController;this.abortControllers.set(t,o);const a=new T;this.inputStreams.set(t,a);const s=this.buildQueryOptions(t,e,o),r=n.query({prompt:a,options:s});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){i.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};i.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);a.enqueue({type:"user",message:{role:"user",content:d}})}else i.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:i.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(n){e.agentId&&g(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const o=n instanceof Error?n.message:String(n);throw i.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${o}`}}),n}}async sendMessage(t,e){const i=this.sessions.get(t),n=this.inputStreams.get(t);if(!i||!n)throw new Error(`Session ${t} not found`);if(i.status==="error")throw new Error(`Session ${t} is in error state`);const o={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};i.messages.push(o),this.emit("conversation-message",t,o),i.status="thinking",this.emit("status-change",t,"thinking");const a=this.parseMessageContent(e);n.enqueue({type:"user",message:{role:"user",content:a}})}parseMessageContent(t){const e=[],i=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let n=0,o=i.exec(t);for(;o!==null;){if(o.index>n){const s=t.slice(n,o.index).trim();s&&e.push({type:"text",text:s})}const a=o[1].trim();a&&e.push({type:"image",source:{type:"url",url:a}}),n=o.index+o[0].length,o=i.exec(t)}if(n<t.length){const a=t.slice(n).trim();a&&e.push({type:"text",text:a})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const i=this.pendingPermissions.get(t);i&&(e?i.resolve({behavior:"allow",updatedInput:i.toolInput}):i.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const n=i.toolInput.questions;let o=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
2
- `;Array.isArray(n)?n.forEach((a,s)=>{const r=String(s),l=e[r]||e[a.header||""]||e[a.question]||"\uFF08\u672A\u586B\u5199\uFF09";o+=`\u2022 ${a.header||a.question}\uFF1A${l}
3
- `}):o+=JSON.stringify(e),i.resolve({behavior:"deny",message:o}),this.pendingQuestions.delete(t)}async cancelQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const n=String(e||"").trim(),o=n?`\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\u3002\u539F\u56E0\uFF1A${n}`:"\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\uFF0C\u672A\u63D0\u4F9B\u539F\u56E0\u3002";i.resolve({behavior:"deny",message:o}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t){const e=this.sessions.get(t),i=this.sdkQueries.get(t),n=this.inputStreams.get(t);if(n&&n.close(),i)try{i.close()}catch{}e&&(e.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}));const o=this.sessionAgentIds.get(t);o&&g(o,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const i=this.sessions.get(t);i&&i.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(e?.idleInputCommand){if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now()),this.armIdleCheck(t)}}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearTimeout(e),this.idleTimers.delete(t))}armIdleCheck(t){const e=this.idleTimers.get(t);e&&clearTimeout(e);const i=setTimeout(()=>{this.idleTimers.get(t)===i&&(this.idleTimers.delete(t),this.armIdleCheck(t),this.checkIdleState(t))},500);this.idleTimers.set(t,i)}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const i=this.idleCommands.get(t);if(!i||!i.idleInputCommand&&!i.nonInputCommand)return;const n=this.lastActivityAt.get(t)||0;if(!(Date.now()-n<1500)&&(this.lastActivityAt.set(t,Date.now()),i.idleInputCommand)){const s=i.idleInputCommand;this.isMessagePollingIdleCommand(s)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,s)}}sendIdlePrompt(t,e,i){const n=this.inputStreams.get(t);if(!n)return;const o=this.sessions.get(t);o&&!i?.keepWaitingStatus&&(o.status="thinking",this.emit("status-change",t,"thinking")),n.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const i=e.toLowerCase();return i.includes("poll_message")||i.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return P}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const i=new b({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:n=>this.isMessagePollingIdleCommand(n),preDispatchHook:()=>null,dispatchPollingPrompt:(n,o)=>this.sendIdlePrompt(t,o?n:this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:n=>this.sendIdlePrompt(t,n)});return this.idlePollLoops.set(t,i),i}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const i=this.inputStreams.get(t);if(!i)return;const n=/\[(.+?)\]/g;let o=0;const a=[];let s=n.exec(e);for(;s!==null;){s.index>o&&a.push({type:"text",value:e.slice(o,s.index)});const r=s[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||a.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};a.push({type:"key",value:l[r.toLowerCase()]||r})}o=s.index+s[0].length,s=n.exec(e)}o<e.length&&a.push({type:"text",value:e.slice(o)});for(const r of a)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);i.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now()),this.idleTimers.has(t)&&this.armIdleCheck(t)}async resumeSession(t,e,i){const n={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,n);try{await this.startSession(t,i),n.providerSessionId=e}catch(o){throw n.status="error",this.emit("status-change",t,"error"),o}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await C("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const a=this.resolveWindowsWrapper(e);if(a)return a;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const i=this.resolveExecutableFromPath(e);if(i)return i;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const a=process.env.USERPROFILE||"",s=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(s,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(s,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(s,"Programs","claude-code","claude.exe"),c.join(a,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return u}const n=process.env.HOME||"",o=[c.join(n,".local","bin","claude"),c.join(n,".npm-global","bin","claude"),c.join(n,".local","share","mise","shims","claude"),c.join(n,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(n,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(n,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const a of o)if(a&&p.existsSync(a))return a}if(this.shouldUseDefaultClaudeFallbacks(e))try{const a=y("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),s=c.join(a,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(s))return s}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const i=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return i?.[1]||i?.[2]||i?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const i=c.extname(t).length>0,n=process.platform==="win32"?this.getWindowsPathExtensions(i):[""];for(const o of e.split(c.delimiter))if(o)for(const a of n){const s=c.join(o,`${t}${a}`);if(p.existsSync(s)){if(this.isWindowsWrapperPath(s)){const r=this.resolveWindowsWrapper(s);if(r)return r;continue}return s}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(i=>i.trim()).filter(i=>i.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const o=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(o))return o}const i=c.dirname(t),n=c.join(i,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}catch{}}buildQueryOptions(t,e,i){const n={cwd:e.workingDirectory,abortController:i,settingSources:["user","project","local"],includePartialMessages:!0},o=this.findClaudeExecutable(e.command);if(o?n.pathToClaudeCodeExecutable=o:console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(n.model=e.model),e.maxTurns&&e.maxTurns>0&&(n.maxTurns=e.maxTurns),e.mcpConfigPath)try{const a=p.readFileSync(e.mcpConfigPath,"utf-8"),s=JSON.parse(a);n.mcpServers={...e.extraMcpServers,...s.mcpServers}}catch{n.mcpServers=e.extraMcpServers||{}}else n.mcpServers=e.extraMcpServers||{};return n.mcpServers&&typeof n.mcpServers=="object"&&x(n.mcpServers,_(e.agentId),{agentMeta:w(e.agentId)}),e.allowedTools&&e.allowedTools.length>0?n.allowedTools=e.allowedTools:n.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],n.env={...process.env,...e.envOverrides},n.canUseTool=this.createPermissionHandler(t,e.autoAccept),n}createPermissionHandler(t,e){return async(i,n,o)=>i==="AskUserQuestion"||i==="ask_user_question"?new Promise(a=>{this.pendingQuestions.set(t,{resolve:a,toolInput:n}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:n.questions})}):e?{behavior:"allow",updatedInput:n}:new Promise(a=>{this.pendingPermissions.set(t,{resolve:a,toolInput:n}),this.emit("permission-request",{sessionId:t,toolName:i,toolInput:n,permissionPrompt:`Allow ${i}?`})})}async consumeStream(t,e){const i=this.sessions.get(t);if(i)try{for await(const n of e){const o=n;this.handleSdkMessage(t,i,o)}}catch(n){if(this.abortControllers.get(t)?.signal.aborted)return;const o=n instanceof Error?n.message:String(n);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${o}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,i){const n=new Date().toISOString();switch(i.type){case"text":i.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:n,data:{text:i.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(i.content||i.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:n,data:{text:i.delta||i.content}});break;case"tool_use":case"tool_use_start":{const o={...f(i.tool_name,i.tool_input),actionId:i.tool_use_id},a=o.actionType==="idle"?"waiting_input":"tool_using";e.status=a;const s=this.extractMcpServerName(i.tool_name||"");this.emit("status-change",t,a,{actionType:o.actionType,actionLabel:o.actionLabel,actionDetail:o.actionDetail,actionId:o.actionId,usage:e.totalUsage,...s?{metadata:{mcpServer:s}}:{}}),o.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,i,n)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:n,data:{toolName:i.tool_name,toolResult:i.tool_result,isError:i.is_error,toolUseId:i.tool_use_id}});break;case"result":{const o=i.subtype==="success";this.applyUsage(e,i.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:n,data:{usage:e.totalUsage,text:o?i.result:void 0}}),e.status="waiting_input",(()=>{const s=this.idleCommands.get(t);return!!(s?.idleInputCommand&&this.isMessagePollingIdleCommand(s.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":break;case"assistant":if(this.applyUsage(e,i.message?.usage),i.message?.content){const o=i.message.content.filter(a=>a.type==="text"&&a.text).map(a=>a.text||"").join("");o&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:o,timestamp:n})}break;case"user":i.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:n,data:{text:i.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,i,n);break;default:break}}handleToolUse(t,e,i,n){const o=this.recentToolNames.get(t),a=this.extractToolNameSuffix(i.tool_name||"");if(o&&Date.now()-o.time<3e4&&o.name===a){this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:n,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const s=f(i.tool_name,i.tool_input),r=this.extractMcpServerName(i.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:n,data:{toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id,actionType:s.actionType,actionLabel:s.actionLabel,actionDetail:s.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:n,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id})}handleStreamEvent(t,e,i,n){const o=i.event;if(o){if(o.type==="content_block_start"){const a=o.content_block;if(a?.type==="tool_use"&&a.name){const s=a.name,r=a.id||`stream_${Date.now()}`;this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(s);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(o.type==="content_block_delta"&&o.delta?.type==="input_json_delta"&&o.delta.partial_json){const a=this.activeToolUseIds.get(t);if(a){const s=`${t}:${a}`,r=this.toolInputBuffers.get(s)||"";this.toolInputBuffers.set(s,r+o.delta.partial_json)}}if(o.type==="content_block_stop"){const a=this.activeToolUseIds.get(t),s=this.recentToolNames.get(t);if(a&&s){const r=`${t}:${a}`,l=this.toolInputBuffers.get(r)||"";let d;if(l)try{d=JSON.parse(l)}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...f(s.name,d),actionId:a},m=this.extractMcpServerName(s.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:n,data:{toolName:s.name,toolInput:d,toolUseId:a,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${s.name}: ${l.slice(0,100)}`,timestamp:n,toolName:s.name,toolInput:d,toolUseId:a}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.sessionAgentIds.delete(t),this.lastActivityAt.delete(t)}}export{N as ClaudeSdkAdapter};
1
+ import{execSync as y}from"child_process";import{EventEmitter as k}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{registerListenerWakeHook as v,unregisterListenerWakeHook as g}from"../services/browser-session-manager.js";import{injectEffectiveEnvIntoMcpServers as x}from"../services/mcp-env-injector.js";import{getPanelEnvVars as _,getAgentMeta as w}from"../services/panel-env.js";import{importBridgeSdkPackage as C}from"../utils/sdk-package-loader.js";import{IdlePollLoop as b}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as P}from"./prompts.js";import{getToolActionInfo as f}from"./types.js";class T{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>{if(this.queue.length>0){const t=this.queue.shift();if(t!==void 0)return Promise.resolve({value:t,done:!1})}return this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}}class N extends k{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map,this.sessionAgentIds=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const i={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};if(this.sessions.set(t,i),e.agentId&&this.sessionAgentIds.set(t,e.agentId),e.agentId){const n=()=>{this.getIdlePollLoop(t).start()};this.listenerWakeHooks.set(t,n),v(e.agentId,n)}try{const n=await this.loadSdk(),o=new AbortController;this.abortControllers.set(t,o);const s=new T;this.inputStreams.set(t,s);const a=this.buildQueryOptions(t,e,o),r=n.query({prompt:s,options:a});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){i.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};i.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);s.enqueue({type:"user",message:{role:"user",content:d}})}else i.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:i.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(n){e.agentId&&g(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const o=n instanceof Error?n.message:String(n);throw i.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${o}`}}),n}}async sendMessage(t,e){const i=this.sessions.get(t),n=this.inputStreams.get(t);if(!i||!n)throw new Error(`Session ${t} not found`);if(i.status==="error")throw new Error(`Session ${t} is in error state`);const o={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};i.messages.push(o),this.emit("conversation-message",t,o),i.status="thinking",this.emit("status-change",t,"thinking");const s=this.parseMessageContent(e);n.enqueue({type:"user",message:{role:"user",content:s}})}parseMessageContent(t){const e=[],i=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let n=0,o=i.exec(t);for(;o!==null;){if(o.index>n){const a=t.slice(n,o.index).trim();a&&e.push({type:"text",text:a})}const s=o[1].trim();s&&e.push({type:"image",source:{type:"url",url:s}}),n=o.index+o[0].length,o=i.exec(t)}if(n<t.length){const s=t.slice(n).trim();s&&e.push({type:"text",text:s})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const i=this.pendingPermissions.get(t);i&&(e?i.resolve({behavior:"allow",updatedInput:i.toolInput}):i.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const n=i.toolInput.questions;let o=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
2
+ `;Array.isArray(n)?n.forEach((s,a)=>{const r=String(a),l=e[r]||e[s.header||""]||e[s.question]||"\uFF08\u672A\u586B\u5199\uFF09";o+=`\u2022 ${s.header||s.question}\uFF1A${l}
3
+ `}):o+=JSON.stringify(e),i.resolve({behavior:"deny",message:o}),this.pendingQuestions.delete(t)}async cancelQuestionAnswer(t,e){const i=this.pendingQuestions.get(t);if(!i)return;const n=String(e||"").trim(),o=n?`\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\u3002\u539F\u56E0\uFF1A${n}`:"\u7528\u6237\u53D6\u6D88\u4E86\u672C\u6B21\u4F5C\u7B54\uFF0C\u672A\u63D0\u4F9B\u539F\u56E0\u3002";i.resolve({behavior:"deny",message:o}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t,e){const i=this.sessions.get(t),n=this.sdkQueries.get(t),o=this.inputStreams.get(t);if(o&&o.close(),n)try{n.close()}catch{}i&&(i.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}));const s=this.sessionAgentIds.get(t);s&&g(s,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const i=this.sessions.get(t);i&&i.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(e?.idleInputCommand){if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now()),this.armIdleCheck(t)}}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearTimeout(e),this.idleTimers.delete(t))}armIdleCheck(t){const e=this.idleTimers.get(t);e&&clearTimeout(e);const i=setTimeout(()=>{this.idleTimers.get(t)===i&&(this.idleTimers.delete(t),this.armIdleCheck(t),this.checkIdleState(t))},500);this.idleTimers.set(t,i)}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const i=this.idleCommands.get(t);if(!i||!i.idleInputCommand&&!i.nonInputCommand)return;const n=this.lastActivityAt.get(t)||0;if(!(Date.now()-n<1500)&&(this.lastActivityAt.set(t,Date.now()),i.idleInputCommand)){const a=i.idleInputCommand;this.isMessagePollingIdleCommand(a)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,a)}}sendIdlePrompt(t,e,i){const n=this.inputStreams.get(t);if(!n)return;const o=this.sessions.get(t);o&&!i?.keepWaitingStatus&&(o.status="thinking",this.emit("status-change",t,"thinking")),n.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const i=e.toLowerCase();return i.includes("poll_message")||i.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return P}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const i=new b({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:n=>this.isMessagePollingIdleCommand(n),preDispatchHook:()=>null,dispatchPollingPrompt:(n,o)=>this.sendIdlePrompt(t,o?n:this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:n=>this.sendIdlePrompt(t,n)});return this.idlePollLoops.set(t,i),i}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const i=this.inputStreams.get(t);if(!i)return;const n=/\[(.+?)\]/g;let o=0;const s=[];let a=n.exec(e);for(;a!==null;){a.index>o&&s.push({type:"text",value:e.slice(o,a.index)});const r=a[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||s.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};s.push({type:"key",value:l[r.toLowerCase()]||r})}o=a.index+a[0].length,a=n.exec(e)}o<e.length&&s.push({type:"text",value:e.slice(o)});for(const r of s)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);i.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now()),this.idleTimers.has(t)&&this.armIdleCheck(t)}async resumeSession(t,e,i){const n={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,n);try{await this.startSession(t,i),n.providerSessionId=e}catch(o){throw n.status="error",this.emit("status-change",t,"error"),o}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await C("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const s=this.resolveWindowsWrapper(e);if(s)return s;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const i=this.resolveExecutableFromPath(e);if(i)return i;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const s=process.env.USERPROFILE||"",a=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(a,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(a,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(a,"Programs","claude-code","claude.exe"),c.join(s,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return u}const n=process.env.HOME||"",o=[c.join(n,".local","bin","claude"),c.join(n,".npm-global","bin","claude"),c.join(n,".local","share","mise","shims","claude"),c.join(n,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(n,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(n,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const s of o)if(s&&p.existsSync(s))return s}if(this.shouldUseDefaultClaudeFallbacks(e))try{const s=y("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),a=c.join(s,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(a))return a}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const i=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return i?.[1]||i?.[2]||i?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const i=c.extname(t).length>0,n=process.platform==="win32"?this.getWindowsPathExtensions(i):[""];for(const o of e.split(c.delimiter))if(o)for(const s of n){const a=c.join(o,`${t}${s}`);if(p.existsSync(a)){if(this.isWindowsWrapperPath(a)){const r=this.resolveWindowsWrapper(a);if(r)return r;continue}return a}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(i=>i.trim()).filter(i=>i.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const o=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(o))return o}const i=c.dirname(t),n=c.join(i,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}catch{}}buildQueryOptions(t,e,i){const n={cwd:e.workingDirectory,abortController:i,settingSources:["user","project","local"],includePartialMessages:!0},o=this.findClaudeExecutable(e.command);if(o?n.pathToClaudeCodeExecutable=o:console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(n.model=e.model),e.maxTurns&&e.maxTurns>0&&(n.maxTurns=e.maxTurns),e.mcpConfigPath)try{const s=p.readFileSync(e.mcpConfigPath,"utf-8"),a=JSON.parse(s);n.mcpServers={...e.extraMcpServers,...a.mcpServers}}catch{n.mcpServers=e.extraMcpServers||{}}else n.mcpServers=e.extraMcpServers||{};return n.mcpServers&&typeof n.mcpServers=="object"&&x(n.mcpServers,_(e.agentId),{agentMeta:w(e.agentId)}),e.allowedTools&&e.allowedTools.length>0?n.allowedTools=e.allowedTools:n.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],n.env={...process.env,...e.envOverrides},n.canUseTool=this.createPermissionHandler(t,e.autoAccept),n}createPermissionHandler(t,e){return async(i,n,o)=>i==="AskUserQuestion"||i==="ask_user_question"?new Promise(s=>{this.pendingQuestions.set(t,{resolve:s,toolInput:n}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:n.questions})}):e?{behavior:"allow",updatedInput:n}:new Promise(s=>{this.pendingPermissions.set(t,{resolve:s,toolInput:n}),this.emit("permission-request",{sessionId:t,toolName:i,toolInput:n,permissionPrompt:`Allow ${i}?`})})}async consumeStream(t,e){const i=this.sessions.get(t);if(i)try{for await(const n of e){const o=n;this.handleSdkMessage(t,i,o)}}catch(n){if(this.abortControllers.get(t)?.signal.aborted)return;const o=n instanceof Error?n.message:String(n);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${o}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,i){const n=new Date().toISOString();switch(i.type){case"text":i.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:n,data:{text:i.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(i.content||i.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:n,data:{text:i.delta||i.content}});break;case"tool_use":case"tool_use_start":{const o={...f(i.tool_name,i.tool_input),actionId:i.tool_use_id},s=o.actionType==="idle"?"waiting_input":"tool_using";e.status=s;const a=this.extractMcpServerName(i.tool_name||"");this.emit("status-change",t,s,{actionType:o.actionType,actionLabel:o.actionLabel,actionDetail:o.actionDetail,actionId:o.actionId,usage:e.totalUsage,...a?{metadata:{mcpServer:a}}:{}}),o.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,i,n)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:n,data:{toolName:i.tool_name,toolResult:i.tool_result,isError:i.is_error,toolUseId:i.tool_use_id}});break;case"result":{const o=i.subtype==="success";this.applyUsage(e,i.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:n,data:{usage:e.totalUsage,text:o?i.result:void 0}}),e.status="waiting_input",(()=>{const a=this.idleCommands.get(t);return!!(a?.idleInputCommand&&this.isMessagePollingIdleCommand(a.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":break;case"assistant":if(this.applyUsage(e,i.message?.usage),i.message?.content){const o=i.message.content.filter(s=>s.type==="text"&&s.text).map(s=>s.text||"").join("");o&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:o,timestamp:n})}break;case"user":i.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:n,data:{text:i.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,i,n);break;default:break}}handleToolUse(t,e,i,n){const o=this.recentToolNames.get(t),s=this.extractToolNameSuffix(i.tool_name||"");if(o&&Date.now()-o.time<3e4&&o.name===s){this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:n,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const a=f(i.tool_name,i.tool_input),r=this.extractMcpServerName(i.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:n,data:{toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id,actionType:a.actionType,actionLabel:a.actionLabel,actionDetail:a.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${i.tool_name}: ${JSON.stringify(i.tool_input).slice(0,100)}`,timestamp:n,toolName:i.tool_name,toolInput:i.tool_input,toolUseId:i.tool_use_id})}handleStreamEvent(t,e,i,n){const o=i.event;if(o){if(o.type==="content_block_start"){const s=o.content_block;if(s?.type==="tool_use"&&s.name){const a=s.name,r=s.id||`stream_${Date.now()}`;this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(a);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(o.type==="content_block_delta"&&o.delta?.type==="input_json_delta"&&o.delta.partial_json){const s=this.activeToolUseIds.get(t);if(s){const a=`${t}:${s}`,r=this.toolInputBuffers.get(a)||"";this.toolInputBuffers.set(a,r+o.delta.partial_json)}}if(o.type==="content_block_stop"){const s=this.activeToolUseIds.get(t),a=this.recentToolNames.get(t);if(s&&a){const r=`${t}:${s}`,l=this.toolInputBuffers.get(r)||"";let d;if(l)try{d=JSON.parse(l)}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...f(a.name,d),actionId:s},m=this.extractMcpServerName(a.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:n,data:{toolName:a.name,toolInput:d,toolUseId:s,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${a.name}: ${l.slice(0,100)}`,timestamp:n,toolName:a.name,toolInput:d,toolUseId:s}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.sessionAgentIds.delete(t),this.lastActivityAt.delete(t)}}export{N as ClaudeSdkAdapter};
4
4
 
@@ -22,7 +22,9 @@ export declare class CodexSdkAdapter extends EventEmitter implements BaseProvide
22
22
  nonInputCommand: string;
23
23
  }): void;
24
24
  abortCurrentTurn(sessionId: string): Promise<void>;
25
- terminateSession(sessionId: string): Promise<void>;
25
+ terminateSession(sessionId: string, _options?: {
26
+ discardContext?: boolean;
27
+ }): Promise<void>;
26
28
  resumeSession(sessionId: string, providerSessionId: string, config: AdapterSessionConfig): Promise<void>;
27
29
  getConversation(sessionId: string): ConversationMessage[];
28
30
  hasSession(sessionId: string): boolean;
@@ -1,4 +1,4 @@
1
- import{EventEmitter as y}from"node:events";import{v4 as h}from"uuid";import{registerListenerWakeHook as T,unregisterListenerWakeHook as m}from"../services/browser-session-manager.js";import{IdlePollLoop as g}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as _}from"./prompts.js";import{getToolActionInfo as E}from"./types.js";function v(i){return i instanceof Error&&"code"in i&&typeof i.code=="string"}function P(i,t){return v(i)&&i.code==="ERR_MODULE_NOT_FOUND"&&i.message.includes(t)}const d=1500;function f(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function D(i){return f(i)?i:{value:i}}function k(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return String(i)}}function A(i,t){const n={};for(const[e,s]of Object.entries(i))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function M(i){const t=[];let n="",e=null,s=!1;for(const a of i.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function S(i){const t=(i||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function O(i){return i.includes("/")||i.includes("\\")||/^[a-zA-Z]:/.test(i)}function w(i){const t=M(i||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=S(n);return O(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&S(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function x(i){if(/^(true|1|yes)$/i.test(i))return!0;if(/^(false|0|no)$/i.test(i))return!1}function c(i){return i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'")?i.slice(1,-1):i}function L(i,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=i;for(const l of e.slice(0,-1)){const o=s[l];f(o)||(s[l]={}),s=s[l]}const a=c(n),r=x(a);s[e[e.length-1]]=r??a}function u(i,t,n){const e=i[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:i[t+1],nextIndex:t+1}}function b(i){const t={additionalDirectories:[],config:{}};for(let n=0;n<i.length;n++){const e=i[n];switch(e){case"--model":case"-m":{const s=u(i,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(i,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(i,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(i,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const r=s.value.slice(0,a),l=s.value.slice(a+1);if(r==="model_reasoning_effort"){const o=c(l);(o==="minimal"||o==="low"||o==="medium"||o==="high"||o==="xhigh")&&(t.modelReasoningEffort=o)}else if(r==="web_search"){const o=c(l);(o==="disabled"||o==="cached"||o==="live")&&(t.webSearchMode=o)}else if(r==="sandbox_workspace_write.network_access")t.networkAccessEnabled=x(c(l));else if(r==="approval_policy"){const o=c(l);(o==="never"||o==="on-request"||o==="on-failure"||o==="untrusted")&&(t.approvalPolicy=o)}else L(t.config,r,l)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function I(i){return{inputTokens:i?.input_tokens??0,outputTokens:i?.output_tokens??0}}class K extends y{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,n){const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const r=a.startThread(this.buildThreadOptions(n)),l={adapterSession:e,config:n,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};if(this.sessions.set(t,l),n.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),T(n.agentId,o)}n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(o=>{const C=o instanceof Error?o.message:String(o),p=this.sessions.get(t);p&&(p.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${C}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){n.agentId&&m(n.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:h(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t){const n=this.sessions.get(t);n&&(this.stopIdleDetection(t),n.terminating=!0,n.currentAbortController?.abort(),n.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),n.config.agentId&&m(n.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const r=a.resumeThread(n,this.buildThreadOptions(e)),l={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:l,config:e,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw P(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
1
+ import{EventEmitter as y}from"node:events";import{v4 as h}from"uuid";import{registerListenerWakeHook as _,unregisterListenerWakeHook as m}from"../services/browser-session-manager.js";import{IdlePollLoop as g}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as T}from"./prompts.js";import{getToolActionInfo as E}from"./types.js";function v(i){return i instanceof Error&&"code"in i&&typeof i.code=="string"}function P(i,t){return v(i)&&i.code==="ERR_MODULE_NOT_FOUND"&&i.message.includes(t)}const d=1500;function f(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function D(i){return f(i)?i:{value:i}}function k(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return String(i)}}function A(i,t){const n={};for(const[e,s]of Object.entries(i))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function M(i){const t=[];let n="",e=null,s=!1;for(const a of i.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function S(i){const t=(i||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function O(i){return i.includes("/")||i.includes("\\")||/^[a-zA-Z]:/.test(i)}function w(i){const t=M(i||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=S(n);return O(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&S(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function x(i){if(/^(true|1|yes)$/i.test(i))return!0;if(/^(false|0|no)$/i.test(i))return!1}function c(i){return i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'")?i.slice(1,-1):i}function L(i,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=i;for(const l of e.slice(0,-1)){const o=s[l];f(o)||(s[l]={}),s=s[l]}const a=c(n),r=x(a);s[e[e.length-1]]=r??a}function u(i,t,n){const e=i[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:i[t+1],nextIndex:t+1}}function b(i){const t={additionalDirectories:[],config:{}};for(let n=0;n<i.length;n++){const e=i[n];switch(e){case"--model":case"-m":{const s=u(i,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(i,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(i,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(i,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const r=s.value.slice(0,a),l=s.value.slice(a+1);if(r==="model_reasoning_effort"){const o=c(l);(o==="minimal"||o==="low"||o==="medium"||o==="high"||o==="xhigh")&&(t.modelReasoningEffort=o)}else if(r==="web_search"){const o=c(l);(o==="disabled"||o==="cached"||o==="live")&&(t.webSearchMode=o)}else if(r==="sandbox_workspace_write.network_access")t.networkAccessEnabled=x(c(l));else if(r==="approval_policy"){const o=c(l);(o==="never"||o==="on-request"||o==="on-failure"||o==="untrusted")&&(t.approvalPolicy=o)}else L(t.config,r,l)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function I(i){return{inputTokens:i?.input_tokens??0,outputTokens:i?.output_tokens??0}}class K extends y{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,n){const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const r=a.startThread(this.buildThreadOptions(n)),l={adapterSession:e,config:n,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};if(this.sessions.set(t,l),n.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),_(n.agentId,o)}n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(o=>{const C=o instanceof Error?o.message:String(o),p=this.sessions.get(t);p&&(p.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${C}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){n.agentId&&m(n.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:h(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t,n){const e=this.sessions.get(t);e&&(this.stopIdleDetection(t),e.terminating=!0,e.currentAbortController?.abort(),e.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),e.config.agentId&&m(e.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const r=a.resumeThread(n,this.buildThreadOptions(e)),l={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:l,config:e,thread:r,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw P(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
2
  `)):t}return this.sdkModule}buildCodexOptions(t){const n=A(process.env,t.envOverrides),e={env:n},s=n.CODEX_API_KEY||n.OPENAI_API_KEY;s&&(e.apiKey=s);const a=n.CODEX_BASE_URL||n.OPENAI_BASE_URL;a&&(e.baseUrl=a);const r=w(t.command);t.executablePath?e.codexPathOverride=t.executablePath:r.executablePath&&(e.codexPathOverride=r.executablePath);const l=b(r.args);return Object.keys(l.config).length>0&&(e.config=l.config),e}warnUnsupportedMcpConfig(t){const n=!!(t.extraMcpServers&&Object.keys(t.extraMcpServers).length>0);(t.mcpConfigPath||n)&&console.warn("[CodexSdkAdapter] Codex SDK ThreadOptions do not expose dynamic MCP server injection; mcpConfigPath/extraMcpServers are ignored for Codex SDK sessions.")}buildThreadOptions(t){const n=w(t.command),e=b(n.args),s={workingDirectory:t.workingDirectory,skipGitRepoCheck:e.skipGitRepoCheck??!1,approvalPolicy:e.approvalPolicy??(t.autoAccept?"never":"on-request")};return(t.model||e.model)&&(s.model=t.model??e.model),(t.additionalDirectories||e.additionalDirectories.length>0)&&(s.additionalDirectories=[...t.additionalDirectories??[],...e.additionalDirectories]),e.sandboxMode&&(s.sandboxMode=e.sandboxMode),e.modelReasoningEffort&&(s.modelReasoningEffort=e.modelReasoningEffort),e.networkAccessEnabled!==void 0&&(s.networkAccessEnabled=e.networkAccessEnabled),e.webSearchMode&&(s.webSearchMode=e.webSearchMode),e.webSearchEnabled!==void 0&&(s.webSearchEnabled=e.webSearchEnabled),s}async runTurn(t,n,e,s){try{const a=await n.thread.runStreamed(e,{signal:s.signal});for await(const r of a.events)this.handleThreadEvent(t,n,r)}catch(a){if(s.signal.aborted){if(!this.sessions.has(t)||n.terminating||n.adapterSession.status==="terminated")return;n.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input");return}const r=a instanceof Error?a.message:String(a);n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:r}})}}handleThreadEvent(t,n,e){const s=new Date().toISOString();switch(e.type){case"thread.started":n.adapterSession.providerSessionId=e.thread_id;break;case"turn.started":n.adapterSession.status="thinking",this.emit("status-change",t,"thinking");break;case"item.started":case"item.updated":case"item.completed":this.handleThreadItem(t,n,e.item,e.type,s);break;case"turn.completed":this.completeTurn(t,n,e.usage,s);break;case"turn.failed":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.error.message}});break;case"error":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.message}});break}}handleThreadItem(t,n,e,s,a){switch(e.type){case"agent_message":this.emitTextDelta(t,n,e.id,e.text,a);break;case"reasoning":this.emitReasoningDelta(t,n,e.id,e.text,a);break;case"command_execution":this.handleToolLikeItem(t,n,{id:e.id,toolName:"bash",toolInput:{command:e.command},result:e.aggregated_output,isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a});break;case"mcp_tool_call":{const r={mcpServer:e.server};this.handleToolLikeItem(t,n,{id:e.id,toolName:e.tool,toolInput:D(e.arguments),result:e.error?.message??k(e.result),isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a,metadata:r});break}case"file_change":this.handleToolLikeItem(t,n,{id:e.id,toolName:"apply_patch",toolInput:{changes:e.changes},result:e.status,isError:e.status==="failed",isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"web_search":this.handleToolLikeItem(t,n,{id:e.id,toolName:"web_search",toolInput:{query:e.query},result:e.query,isError:!1,isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"todo_list":this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:e.items.map(r=>`${r.completed?"\u2713":"\u2022"} ${r.text}`).join(`
3
- `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const r=n.emittedTextLengths.get(e)??0,l=s.slice(r);n.emittedTextLengths.set(e,s.length),l&&(n.currentAssistantText+=l,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:l}}))}emitReasoningDelta(t,n,e,s,a){const r=n.emittedReasoningLengths.get(e)??0,l=s.slice(r);n.emittedReasoningLengths.set(e,s.length),l&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:l}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...E(e.toolName,e.toolInput,e.metadata),actionId:e.id,actionInput:k(e.toolInput)};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=I(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:h(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const r=n.idleCommands?.idleInputCommand;!!(r&&this.isMessagePollingIdleCommand(r))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!(!n||!e)){if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:s=>this.isMessagePollingIdleCommand(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,a)=>this.sendIdlePrompt(t,s,{keepWaitingStatus:!0,injected:a}),dispatchRegularIdleCommand:s=>this.sendIdlePrompt(t,s),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:s=>this.isMessagePollingIdleCommand(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,a)=>this.sendIdlePrompt(t,s,{keepWaitingStatus:!0,injected:a}),dispatchRegularIdleCommand:s=>this.sendIdlePrompt(t,s),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now(),this.armIdleCheck(t)}}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearTimeout(n.idleTimer),n.idleTimer=void 0)}armIdleCheck(t){const n=this.sessions.get(t);if(!n)return;n.idleTimer&&clearTimeout(n.idleTimer);const e=setTimeout(()=>{n.idleTimer===e&&(n.idleTimer=void 0,this.armIdleCheck(t),this.checkIdleState(t))},500);n.idleTimer=e}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=e?.injected?n.trim():this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const r=new AbortController;s.currentAbortController=r,s.runningTurn=this.runTurn(t,s,a,r);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?_:n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{K as CodexSdkAdapter};
3
+ `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const r=n.emittedTextLengths.get(e)??0,l=s.slice(r);n.emittedTextLengths.set(e,s.length),l&&(n.currentAssistantText+=l,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:l}}))}emitReasoningDelta(t,n,e,s,a){const r=n.emittedReasoningLengths.get(e)??0,l=s.slice(r);n.emittedReasoningLengths.set(e,s.length),l&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:l}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...E(e.toolName,e.toolInput,e.metadata),actionId:e.id,actionInput:k(e.toolInput)};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=I(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:h(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const r=n.idleCommands?.idleInputCommand;!!(r&&this.isMessagePollingIdleCommand(r))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!(!n||!e)){if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:s=>this.isMessagePollingIdleCommand(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,a)=>this.sendIdlePrompt(t,s,{keepWaitingStatus:!0,injected:a}),dispatchRegularIdleCommand:s=>this.sendIdlePrompt(t,s),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new g({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:s=>this.isMessagePollingIdleCommand(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,a)=>this.sendIdlePrompt(t,s,{keepWaitingStatus:!0,injected:a}),dispatchRegularIdleCommand:s=>this.sendIdlePrompt(t,s),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now(),this.armIdleCheck(t)}}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearTimeout(n.idleTimer),n.idleTimer=void 0)}armIdleCheck(t){const n=this.sessions.get(t);if(!n)return;n.idleTimer&&clearTimeout(n.idleTimer);const e=setTimeout(()=>{n.idleTimer===e&&(n.idleTimer=void 0,this.armIdleCheck(t),this.checkIdleState(t))},500);n.idleTimer=e}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=e?.injected?n.trim():this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const r=new AbortController;s.currentAbortController=r,s.runningTurn=this.runTurn(t,s,a,r);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?T:n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{K as CodexSdkAdapter};
4
4
 
@@ -30,7 +30,9 @@ export declare class OpencodeSdkAdapter extends EventEmitter implements BaseProv
30
30
  nonInputCommand: string;
31
31
  }): void;
32
32
  abortCurrentTurn(sessionId: string): Promise<void>;
33
- terminateSession(sessionId: string): Promise<void>;
33
+ terminateSession(sessionId: string, _options?: {
34
+ discardContext?: boolean;
35
+ }): Promise<void>;
34
36
  getConversation(sessionId: string): ConversationMessage[];
35
37
  hasSession(sessionId: string): boolean;
36
38
  getProviderSessionId(sessionId: string): string | undefined;
@@ -1,4 +1,4 @@
1
- import{spawn as T}from"node:child_process";import{EventEmitter as E}from"node:events";import*as S from"node:fs";import*as x from"node:net";import*as A from"node:os";import*as g from"node:path";import{v4 as P}from"uuid";import{getAcodeDataHome as _}from"../config.js";import{registerListenerWakeHook as M,unregisterListenerWakeHook as D}from"../services/browser-session-manager.js";import{logger as $}from"../utils/logger.js";import{BRIDGE_PACKAGE_ROOT as L,importBridgeSdkPackage as N}from"../utils/sdk-package-loader.js";import{IdlePollLoop as C}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as R}from"./prompts.js";import{getToolActionInfo as I,redactTransientClipboardPastePaths as O,redactTransientClipboardPastePathsInValue as U}from"./types.js";function j(d){if(d&&g.isAbsolute(d)&&S.existsSync(d))return d;const t=d?.trim()||"opencode";if(process.platform==="win32"){const e=process.env.USERPROFILE||process.env.HOME||A.homedir(),s=process.env.LOCALAPPDATA||"",o=[g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64","bin"),g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64-baseline","bin")];for(const i of o){const r=g.join(i,"opencode.exe");if(S.existsSync(r))return r}const n=[g.join(e,"AppData","Roaming","npm"),g.join(e,"AppData","Local","Volta","bin")];for(const i of n)for(const r of["opencode.cmd","opencode.exe","opencode"]){const a=g.join(i,r);if(S.existsSync(a))return a}}return t}async function H(d=14096){for(let t=d;t<d+100;t++)if(await new Promise(s=>{const o=x.createServer();o.once("error",()=>s(!1)),o.once("listening",()=>{o.close(()=>s(!0))}),o.listen(t,"127.0.0.1")}))return t;throw new Error(`No available port found in range ${d}\u2013${d+99}`)}function W(d){return d instanceof Error&&"code"in d&&typeof d.code=="string"}function F(d,t){return W(d)&&d.code==="ERR_MODULE_NOT_FOUND"&&d.message.includes(t)}function v(d){if(!d||!d.trim())return;const t=d.trim(),e=t.indexOf("/");return e>0?{providerID:t.slice(0,e),modelID:t.slice(e+1)}:{modelID:t}}class Y extends E{constructor(){super(...arguments),this.providerId="opencode",this.displayName="OpenCode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const s={adapterSession:{sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}},config:e,sseActive:!1,pendingPermissions:new Map,emittedToolStarts:new Set,workingDirectory:e.workingDirectory,userMessageIds:new Set,currentAssistantText:"",seenTextPartIds:new Set};if(this.sessions.set(t,s),e.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),M(e.agentId,o)}this.emit("status-change",t,"starting");try{const o=await H();s.port=o;const n=j(e.command),i=n.endsWith(".cmd")||n.endsWith(".CMD")||process.platform==="win32"&&!g.isAbsolute(n),r={...process.env,...e.envOverrides},a={},m=v(e.model),h=e.model;m?.modelID&&h!==null&&h!==void 0&&(a.model=h.trim()),e.systemPrompt&&typeof e.systemPrompt=="string"&&(a.systemPrompt=e.systemPrompt),Object.keys(a).length>0&&(r.OPENCODE_CONFIG_CONTENT=JSON.stringify(a),$.info(`[OpencodeSdkAdapter] OPENCODE_CONFIG_CONTENT keys=${Object.keys(a).join(",")}`));const l=T(n,["serve","--port",String(o)],{cwd:e.workingDirectory,stdio:["ignore","pipe","pipe"],env:r,shell:i});s.serverProcess=l,s.startupOutput=[],l.stdout?.on("data",u=>{const k=u.toString();this.recordStartupOutput(s,k)}),l.stderr?.on("data",u=>{const k=u.toString();this.recordStartupOutput(s,k)}),l.on("error",u=>{console.error("[OpencodeSdkAdapter] Server process error:",u),s.adapterSession.status!=="terminated"&&(s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode server error: ${u.message}`}}))}),l.on("exit",u=>{s.sseActive=!1});const p=new Promise(u=>{l.once("exit",(k,b)=>u({code:k,signal:b}))}),c=(await this.loadSdk()).createOpencodeClient({baseUrl:`http://127.0.0.1:${o}`});s.client=c,await Promise.race([this.waitForServer(c,e.workingDirectory,1e4,o),p.then(u=>{throw new Error(this.formatStartupExitMessage(u,s.startupOutput))})]);const y=(await c.session.create({body:{title:`aws-bridge-${t.slice(0,8)}`},query:{directory:e.workingDirectory}})).data;if(!y?.id)throw new Error("OpenCode session.create() did not return an ID");s.opencodeSessionId=y.id,s.adapterSession.providerSessionId=y.id,this.startSseLoop(t,s),s.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:s.adapterSession.totalUsage}),e.initialPrompt&&this.dispatchInitialPrompt(t,e.initialPrompt)}catch(o){e.agentId&&D(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const n=o instanceof Error?o.message:String(o);throw console.error("[OpencodeSdkAdapter] startSession failed:",o),s.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode start failed: ${n}`}}),o}}async sendMessage(t,e,s){const o=this.sessions.get(t);if(!o)throw new Error(`Session ${t} not found`);if(!o.client||!o.opencodeSessionId)throw new Error(`Session ${t} not ready`);const n={id:P(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};o.adapterSession.messages.push(n),this.emit("conversation-message",t,n),s?.keepWaitingStatus||(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t));try{const i=v(o.config.model),r={parts:[{type:"text",text:e}]};i?.providerID&&i?.modelID&&(r.model={providerID:i.providerID,modelID:i.modelID}),await o.client.session.prompt({path:{id:o.opencodeSessionId},body:r,query:{directory:o.workingDirectory}})}catch(i){const r=i instanceof Error?i.message:String(i);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:r}})}}async sendConfirmation(t,e){const s=this.sessions.get(t);if(!s?.client||!s.opencodeSessionId)return;const o=e?"once":"reject",n=s.opencodeSessionId;for(const[i]of s.pendingPermissions)try{await s.client.postSessionIdPermissionsPermissionId({path:{id:n,permissionID:i},body:{response:o},query:{directory:s.workingDirectory}})}catch(r){console.warn("[OpencodeSdkAdapter] Permission response failed:",r)}s.pendingPermissions.clear()}async sendQuestionAnswer(t,e){}setIdleCommands(t,e){const s=this.sessions.get(t);s&&(s.idleCommands=e,s.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){const e=this.sessions.get(t);if(!(!e?.client||!e.opencodeSessionId))try{await e.client.session.abort({path:{id:e.opencodeSessionId},query:{directory:e.workingDirectory}})}catch(s){console.warn("[OpencodeSdkAdapter] Abort failed:",s)}}async terminateSession(t){const e=this.sessions.get(t);if(e){if(this.stopIdleDetection(t),e.sseActive=!1,e.sseAbortController?.abort(),e.serverProcess)try{e.serverProcess.kill()}catch{}e.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),e.config.agentId&&D(e.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t)}}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.opencodeSessionId}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){const e=this.sessions.get(t);if(e)return e.serverProcess?.pid}cleanup(){for(const[t]of this.sessions)try{this.terminateSession(t)}catch{}this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await N("@opencode-ai/sdk")}catch(t){throw F(t,"@opencode-ai/sdk")?new Error(["OpenCode SDK provider is not installed.","","aws-runtime-bridge keeps Codex/OpenCode provider SDKs optional to reduce default install size.",'To use SDK mode with command "opencode", install the SDK into the aws-runtime-bridge package root:',"",` npm install --prefix "${L}" @opencode-ai/sdk@latest opencode-ai@latest`,"","If aws-runtime-bridge is installed locally, run the same command with that local package path.","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
- `)):t}return this.sdkModule}async waitForServer(t,e,s,o){const n=Date.now()+s;for(;Date.now()<n;){try{if((await t.session.list({query:{directory:e}})).data!==void 0)return}catch{}await new Promise(i=>setTimeout(i,300))}throw new Error(`OpenCode server (port ${o}) did not start within ${s}ms`)}recordStartupOutput(t,e){const s=e.trim();s&&(t.startupOutput=[...t.startupOutput??[],s].slice(-8))}formatStartupExitMessage(t,e){const s=t.signal?`signal ${t.signal}`:`code ${t.code??"unknown"}`,o=(e??[]).join(`
3
- `).trim();return o?`OpenCode server exited during startup (${s}): ${o}`:`OpenCode server exited during startup (${s}). Please check whether opencode serve can run in this workspace.`}dispatchInitialPrompt(t,e){this.sendMessage(t,e).catch(s=>{const o=s instanceof Error?s.message:String(s);this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`OpenCode initial prompt failed: ${o}`}})})}startSseLoop(t,e){e.sseActive=!0;const s=new AbortController;e.sseAbortController=s,this.runSseLoop(t,e,s).catch(o=>{s.signal.aborted||console.error("[OpencodeSdkAdapter] SSE loop error:",o)})}async runSseLoop(t,e,s){if(e.client)try{const o=await e.client.event.subscribe({query:{directory:e.workingDirectory},signal:s.signal});for await(const n of o.stream){if(!e.sseActive||s.signal.aborted)break;this.handleOpenCodeEvent(t,e,n)}}catch(o){if(s.signal.aborted)return;console.error("[OpencodeSdkAdapter] SSE stream ended:",o)}}handleOpenCodeEvent(t,e,s){const o=new Date().toISOString(),n=e.opencodeSessionId;switch(s.type){case"message.updated":{const i=s.properties.info;if(i.sessionID!==n)break;if(i.role==="user")e.userMessageIds.add(i.id);else if(i.role==="assistant"){const r=i.tokens;r&&(e.adapterSession.totalUsage.inputTokens=Math.max(e.adapterSession.totalUsage.inputTokens,r.input),e.adapterSession.totalUsage.outputTokens=Math.max(e.adapterSession.totalUsage.outputTokens,r.output))}break}case"message.part.updated":{const{part:i,delta:r}=s.properties;if(i.sessionID!==n||e.userMessageIds.has(i.messageID))break;this.handlePartUpdate(t,e,i,r,o);break}case"session.idle":{if(s.properties.sessionID!==n)break;if(e.currentAssistantText){const a={id:P(),sessionId:t,role:"assistant",content:e.currentAssistantText,timestamp:o};e.adapterSession.messages.push(a),e.currentAssistantText=""}e.seenTextPartIds.clear(),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:o,data:{usage:e.adapterSession.totalUsage}}),e.adapterSession.status="waiting_input";const i=e.idleCommands?.idleInputCommand;!!(i&&this.isMessagePollingIdleCommand(i))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.adapterSession.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),this.startIdleDetection(t);break}case"permission.updated":{const i=s.properties;if(i.sessionID!==n)break;const r=i.id;e.pendingPermissions.set(r,i),e.config.autoAccept&&e.client&&n?e.client.postSessionIdPermissionsPermissionId({path:{id:n,permissionID:r},body:{response:"once"},query:{directory:e.workingDirectory}}).then(()=>{e.pendingPermissions.delete(r)}).catch(a=>{console.warn("[OpencodeSdkAdapter] Auto-accept permission failed:",a)}):this.emitEvent({type:"permission_request",sessionId:t,timestamp:o,data:{permissionPrompt:i.title,toolName:i.type}});break}case"session.error":{const{sessionID:i,error:r}=s.properties;if(i&&i!==n)break;let a="OpenCode session error";if(r){const m=r.data;typeof m?.message=="string"?a=`${r.name}: ${m.message}`:a=r.name}this.emitEvent({type:"error",sessionId:t,timestamp:o,data:{text:a}});break}}}handlePartUpdate(t,e,s,o,n){switch(s.type){case"text":{let i;if(o!==void 0)i=o,e.seenTextPartIds.add(s.id);else if(!e.seenTextPartIds.has(s.id))i=s.text,i&&e.seenTextPartIds.add(s.id);else break;if(!i)break;e.currentAssistantText+=i,this.emitEvent({type:"text_delta",sessionId:t,timestamp:n,data:{text:i}});break}case"reasoning":{const i=o??s.text;if(!i)break;this.emitEvent({type:"thinking",sessionId:t,timestamp:n,data:{text:i}});break}case"tool":{const i=s.callID,r=s.tool,a=s.state,m=a.input,h=s.metadata,l=U(m),p=l&&typeof l=="object"&&!Array.isArray(l)?l:{},f=()=>{if(e.emittedToolStarts.has(i))return;e.emittedToolStarts.add(i);const c={...I(r,m,h),actionId:i};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:n,data:{toolName:r,toolInput:p,toolUseId:i,...c}}),e.adapterSession.messages.push({id:P(),sessionId:t,role:"tool_use",content:`${r}: ${JSON.stringify(p).slice(0,100)}`,timestamp:n,toolName:r,toolInput:p,toolUseId:i})};if(a.status==="running"){f();const c={...I(r,m,h),actionId:i};this.emit("status-change",t,"tool_using",{...c,usage:e.adapterSession.totalUsage})}else if(a.status==="completed"){(r==="todowrite"||r==="todo_write")&&this.syncTodosFromToolCall(e,m).catch(w=>{console.warn("[OpencodeSdkAdapter] \u540C\u6B65 todo \u5230\u6587\u4EF6\u5931\u8D25:",w)}),f();const c=O(a.output);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:n,data:{toolName:r,toolResult:c,isError:!1,toolUseId:i}}),e.emittedToolStarts.delete(i)}else if(a.status==="error"){f();const c=O(a.error);this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:n,data:{toolName:r,toolResult:c,isError:!0,toolUseId:i}}),e.emittedToolStarts.delete(i)}break}}}getTodoStoreDir(){return g.join(_(),"todos")}async syncTodosFromToolCall(t,e){const s=t.config.agentId;if(!s)return;const o=e.todos;if(!Array.isArray(o)||o.length===0)return;const n=[];for(const l of o)if(l&&typeof l=="object"){const p=l,f=typeof p.content=="string"?p.content.trim():"",c=typeof p.status=="string"?p.status:"",w=typeof p.priority=="string"?p.priority:"";f&&c&&w&&n.push({content:f,status:c,priority:w})}if(n.length===0)return;const i=String(s).replace(/[^a-zA-Z0-9_-]/g,"_"),r=this.getTodoStoreDir(),a=g.join(r,`${i}.json`),m={agentId:s,updatedAt:new Date().toISOString(),background:"OpenCode runtime todos",todos:n};await S.promises.mkdir(r,{recursive:!0});const h=`${a}.tmp`;await S.promises.writeFile(h,JSON.stringify(m,null,2),"utf-8"),await S.promises.rename(h,a)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.sessions.get(t),s=e?.idleCommands?.idleInputCommand;if(!(!e||!s)){if(this.isMessagePollingIdleCommand(s)){e.idlePollLoop||(e.idlePollLoop=new C({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendMessage(t,n?o.trim():this.toIdlePrompt(o),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendMessage(t,this.toIdlePrompt(o)),pollDelayMs:1500})),e.idlePollLoop.start();return}e.idlePollLoop||(e.idlePollLoop=new C({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendMessage(t,n?o.trim():this.toIdlePrompt(o),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendMessage(t,this.toIdlePrompt(o)),pollDelayMs:1500})),this.armIdleCheck(t)}}armIdleCheck(t){const e=this.sessions.get(t);if(!e)return;e.idleTimer&&clearTimeout(e.idleTimer);const s=setTimeout(()=>{e.idleTimer===s&&(e.idleTimer=void 0,this.armIdleCheck(t),this.checkIdleState(t))},500);e.idleTimer=s}stopIdleDetection(t){const e=this.sessions.get(t);e?.idlePollLoop?.stop(),e?.idleTimer&&(clearTimeout(e.idleTimer),e.idleTimer=void 0)}checkIdleState(t){const e=this.sessions.get(t);!e||e.adapterSession.status!=="waiting_input"||e.idleCommands?.idleInputCommand&&(this.sendMessage(t,this.toIdlePrompt(e.idleCommands.idleInputCommand)),this.stopIdleDetection(t))}toIdlePrompt(t){const e=t.trim();return this.isMessagePollingIdleCommand(e)?R:e}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const s=e.toLowerCase();return s.includes("poll_message")||s.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}}export{Y as OpencodeSdkAdapter};
1
+ import{spawn as T}from"node:child_process";import{EventEmitter as E}from"node:events";import*as S from"node:fs";import*as x from"node:net";import*as A from"node:os";import*as g from"node:path";import{v4 as P}from"uuid";import{getAcodeDataHome as _}from"../config.js";import{registerListenerWakeHook as M,unregisterListenerWakeHook as D}from"../services/browser-session-manager.js";import{logger as $}from"../utils/logger.js";import{BRIDGE_PACKAGE_ROOT as L,importBridgeSdkPackage as N}from"../utils/sdk-package-loader.js";import{IdlePollLoop as C}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as R}from"./prompts.js";import{getToolActionInfo as I,redactTransientClipboardPastePaths as O,redactTransientClipboardPastePathsInValue as U}from"./types.js";function j(d){if(d&&g.isAbsolute(d)&&S.existsSync(d))return d;const e=d?.trim()||"opencode";if(process.platform==="win32"){const t=process.env.USERPROFILE||process.env.HOME||A.homedir(),s=process.env.LOCALAPPDATA||"",o=[g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64","bin"),g.join(s,"Volta","tools","shared","opencode-ai","node_modules","opencode-windows-x64-baseline","bin")];for(const i of o){const r=g.join(i,"opencode.exe");if(S.existsSync(r))return r}const n=[g.join(t,"AppData","Roaming","npm"),g.join(t,"AppData","Local","Volta","bin")];for(const i of n)for(const r of["opencode.cmd","opencode.exe","opencode"]){const a=g.join(i,r);if(S.existsSync(a))return a}}return e}async function H(d=14096){for(let e=d;e<d+100;e++)if(await new Promise(s=>{const o=x.createServer();o.once("error",()=>s(!1)),o.once("listening",()=>{o.close(()=>s(!0))}),o.listen(e,"127.0.0.1")}))return e;throw new Error(`No available port found in range ${d}\u2013${d+99}`)}function W(d){return d instanceof Error&&"code"in d&&typeof d.code=="string"}function F(d,e){return W(d)&&d.code==="ERR_MODULE_NOT_FOUND"&&d.message.includes(e)}function v(d){if(!d||!d.trim())return;const e=d.trim(),t=e.indexOf("/");return t>0?{providerID:e.slice(0,t),modelID:e.slice(t+1)}:{modelID:e}}class Y extends E{constructor(){super(...arguments),this.providerId="opencode",this.displayName="OpenCode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(e,t){const s={adapterSession:{sessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}},config:t,sseActive:!1,pendingPermissions:new Map,emittedToolStarts:new Set,workingDirectory:t.workingDirectory,userMessageIds:new Set,currentAssistantText:"",seenTextPartIds:new Set};if(this.sessions.set(e,s),t.agentId){const o=()=>{this.sessions.get(e)?.idlePollLoop?.start()};this.listenerWakeHooks.set(e,o),M(t.agentId,o)}this.emit("status-change",e,"starting");try{const o=await H();s.port=o;const n=j(t.command),i=n.endsWith(".cmd")||n.endsWith(".CMD")||process.platform==="win32"&&!g.isAbsolute(n),r={...process.env,...t.envOverrides},a={},m=v(t.model),h=t.model;m?.modelID&&h!==null&&h!==void 0&&(a.model=h.trim()),t.systemPrompt&&typeof t.systemPrompt=="string"&&(a.systemPrompt=t.systemPrompt),Object.keys(a).length>0&&(r.OPENCODE_CONFIG_CONTENT=JSON.stringify(a),$.info(`[OpencodeSdkAdapter] OPENCODE_CONFIG_CONTENT keys=${Object.keys(a).join(",")}`));const l=T(n,["serve","--port",String(o)],{cwd:t.workingDirectory,stdio:["ignore","pipe","pipe"],env:r,shell:i});s.serverProcess=l,s.startupOutput=[],l.stdout?.on("data",u=>{const k=u.toString();this.recordStartupOutput(s,k)}),l.stderr?.on("data",u=>{const k=u.toString();this.recordStartupOutput(s,k)}),l.on("error",u=>{console.error("[OpencodeSdkAdapter] Server process error:",u),s.adapterSession.status!=="terminated"&&(s.adapterSession.status="error",this.emit("status-change",e,"error"),this.emitEvent({type:"error",sessionId:e,timestamp:new Date().toISOString(),data:{text:`OpenCode server error: ${u.message}`}}))}),l.on("exit",u=>{s.sseActive=!1});const c=new Promise(u=>{l.once("exit",(k,b)=>u({code:k,signal:b}))}),p=(await this.loadSdk()).createOpencodeClient({baseUrl:`http://127.0.0.1:${o}`});s.client=p,await Promise.race([this.waitForServer(p,t.workingDirectory,1e4,o),c.then(u=>{throw new Error(this.formatStartupExitMessage(u,s.startupOutput))})]);const y=(await p.session.create({body:{title:`aws-bridge-${e.slice(0,8)}`},query:{directory:t.workingDirectory}})).data;if(!y?.id)throw new Error("OpenCode session.create() did not return an ID");s.opencodeSessionId=y.id,s.adapterSession.providerSessionId=y.id,this.startSseLoop(e,s),s.adapterSession.status="waiting_input",this.emit("status-change",e,"waiting_input",{usage:s.adapterSession.totalUsage}),t.initialPrompt&&this.dispatchInitialPrompt(e,t.initialPrompt)}catch(o){t.agentId&&D(t.agentId,this.listenerWakeHooks.get(e)),this.listenerWakeHooks.delete(e);const n=o instanceof Error?o.message:String(o);throw console.error("[OpencodeSdkAdapter] startSession failed:",o),s.adapterSession.status="error",this.emit("status-change",e,"error"),this.emitEvent({type:"error",sessionId:e,timestamp:new Date().toISOString(),data:{text:`OpenCode start failed: ${n}`}}),o}}async sendMessage(e,t,s){const o=this.sessions.get(e);if(!o)throw new Error(`Session ${e} not found`);if(!o.client||!o.opencodeSessionId)throw new Error(`Session ${e} not ready`);const n={id:P(),sessionId:e,role:"user",content:t,timestamp:new Date().toISOString()};o.adapterSession.messages.push(n),this.emit("conversation-message",e,n),s?.keepWaitingStatus||(o.adapterSession.status="thinking",this.emit("status-change",e,"thinking"),this.stopIdleDetection(e));try{const i=v(o.config.model),r={parts:[{type:"text",text:t}]};i?.providerID&&i?.modelID&&(r.model={providerID:i.providerID,modelID:i.modelID}),await o.client.session.prompt({path:{id:o.opencodeSessionId},body:r,query:{directory:o.workingDirectory}})}catch(i){const r=i instanceof Error?i.message:String(i);this.emitEvent({type:"error",sessionId:e,timestamp:new Date().toISOString(),data:{text:r}})}}async sendConfirmation(e,t){const s=this.sessions.get(e);if(!s?.client||!s.opencodeSessionId)return;const o=t?"once":"reject",n=s.opencodeSessionId;for(const[i]of s.pendingPermissions)try{await s.client.postSessionIdPermissionsPermissionId({path:{id:n,permissionID:i},body:{response:o},query:{directory:s.workingDirectory}})}catch(r){console.warn("[OpencodeSdkAdapter] Permission response failed:",r)}s.pendingPermissions.clear()}async sendQuestionAnswer(e,t){}setIdleCommands(e,t){const s=this.sessions.get(e);s&&(s.idleCommands=t,s.adapterSession.status==="waiting_input"&&(t.idleInputCommand||t.nonInputCommand)&&this.startIdleDetection(e))}async abortCurrentTurn(e){const t=this.sessions.get(e);if(!(!t?.client||!t.opencodeSessionId))try{await t.client.session.abort({path:{id:t.opencodeSessionId},query:{directory:t.workingDirectory}})}catch(s){console.warn("[OpencodeSdkAdapter] Abort failed:",s)}}async terminateSession(e,t){const s=this.sessions.get(e);if(s){if(this.stopIdleDetection(e),s.sseActive=!1,s.sseAbortController?.abort(),s.serverProcess)try{s.serverProcess.kill()}catch{}s.adapterSession.status="terminated",this.emit("status-change",e,"terminated"),this.emitEvent({type:"session_complete",sessionId:e,timestamp:new Date().toISOString(),data:{exitCode:0}}),s.config.agentId&&D(s.config.agentId,this.listenerWakeHooks.get(e)),this.listenerWakeHooks.delete(e),this.sessions.delete(e)}}getConversation(e){return this.sessions.get(e)?.adapterSession.messages??[]}hasSession(e){return this.sessions.has(e)}getProviderSessionId(e){return this.sessions.get(e)?.opencodeSessionId}getSessionStatus(e){return this.sessions.get(e)?.adapterSession.status}getSessionPid(e){const t=this.sessions.get(e);if(t)return t.serverProcess?.pid}cleanup(){for(const[e]of this.sessions)try{this.terminateSession(e)}catch{}this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await N("@opencode-ai/sdk")}catch(e){throw F(e,"@opencode-ai/sdk")?new Error(["OpenCode SDK provider is not installed.","","aws-runtime-bridge keeps Codex/OpenCode provider SDKs optional to reduce default install size.",'To use SDK mode with command "opencode", install the SDK into the aws-runtime-bridge package root:',"",` npm install --prefix "${L}" @opencode-ai/sdk@latest opencode-ai@latest`,"","If aws-runtime-bridge is installed locally, run the same command with that local package path.","",`Original error: ${e instanceof Error?e.message:String(e)}`].join(`
2
+ `)):e}return this.sdkModule}async waitForServer(e,t,s,o){const n=Date.now()+s;for(;Date.now()<n;){try{if((await e.session.list({query:{directory:t}})).data!==void 0)return}catch{}await new Promise(i=>setTimeout(i,300))}throw new Error(`OpenCode server (port ${o}) did not start within ${s}ms`)}recordStartupOutput(e,t){const s=t.trim();s&&(e.startupOutput=[...e.startupOutput??[],s].slice(-8))}formatStartupExitMessage(e,t){const s=e.signal?`signal ${e.signal}`:`code ${e.code??"unknown"}`,o=(t??[]).join(`
3
+ `).trim();return o?`OpenCode server exited during startup (${s}): ${o}`:`OpenCode server exited during startup (${s}). Please check whether opencode serve can run in this workspace.`}dispatchInitialPrompt(e,t){this.sendMessage(e,t).catch(s=>{const o=s instanceof Error?s.message:String(s);this.emitEvent({type:"error",sessionId:e,timestamp:new Date().toISOString(),data:{text:`OpenCode initial prompt failed: ${o}`}})})}startSseLoop(e,t){t.sseActive=!0;const s=new AbortController;t.sseAbortController=s,this.runSseLoop(e,t,s).catch(o=>{s.signal.aborted||console.error("[OpencodeSdkAdapter] SSE loop error:",o)})}async runSseLoop(e,t,s){if(t.client)try{const o=await t.client.event.subscribe({query:{directory:t.workingDirectory},signal:s.signal});for await(const n of o.stream){if(!t.sseActive||s.signal.aborted)break;this.handleOpenCodeEvent(e,t,n)}}catch(o){if(s.signal.aborted)return;console.error("[OpencodeSdkAdapter] SSE stream ended:",o)}}handleOpenCodeEvent(e,t,s){const o=new Date().toISOString(),n=t.opencodeSessionId;switch(s.type){case"message.updated":{const i=s.properties.info;if(i.sessionID!==n)break;if(i.role==="user")t.userMessageIds.add(i.id);else if(i.role==="assistant"){const r=i.tokens;r&&(t.adapterSession.totalUsage.inputTokens=Math.max(t.adapterSession.totalUsage.inputTokens,r.input),t.adapterSession.totalUsage.outputTokens=Math.max(t.adapterSession.totalUsage.outputTokens,r.output))}break}case"message.part.updated":{const{part:i,delta:r}=s.properties;if(i.sessionID!==n||t.userMessageIds.has(i.messageID))break;this.handlePartUpdate(e,t,i,r,o);break}case"session.idle":{if(s.properties.sessionID!==n)break;if(t.currentAssistantText){const a={id:P(),sessionId:e,role:"assistant",content:t.currentAssistantText,timestamp:o};t.adapterSession.messages.push(a),t.currentAssistantText=""}t.seenTextPartIds.clear(),this.emitEvent({type:"turn_complete",sessionId:e,timestamp:o,data:{usage:t.adapterSession.totalUsage}}),t.adapterSession.status="waiting_input";const i=t.idleCommands?.idleInputCommand;!!(i&&this.isMessagePollingIdleCommand(i))?this.emit("status-change",e,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:t.adapterSession.totalUsage}):this.emit("status-change",e,"waiting_input",{usage:t.adapterSession.totalUsage}),this.startIdleDetection(e);break}case"permission.updated":{const i=s.properties;if(i.sessionID!==n)break;const r=i.id;t.pendingPermissions.set(r,i),t.config.autoAccept&&t.client&&n?t.client.postSessionIdPermissionsPermissionId({path:{id:n,permissionID:r},body:{response:"once"},query:{directory:t.workingDirectory}}).then(()=>{t.pendingPermissions.delete(r)}).catch(a=>{console.warn("[OpencodeSdkAdapter] Auto-accept permission failed:",a)}):this.emitEvent({type:"permission_request",sessionId:e,timestamp:o,data:{permissionPrompt:i.title,toolName:i.type}});break}case"session.error":{const{sessionID:i,error:r}=s.properties;if(i&&i!==n)break;let a="OpenCode session error";if(r){const m=r.data;typeof m?.message=="string"?a=`${r.name}: ${m.message}`:a=r.name}this.emitEvent({type:"error",sessionId:e,timestamp:o,data:{text:a}});break}}}handlePartUpdate(e,t,s,o,n){switch(s.type){case"text":{let i;if(o!==void 0)i=o,t.seenTextPartIds.add(s.id);else if(!t.seenTextPartIds.has(s.id))i=s.text,i&&t.seenTextPartIds.add(s.id);else break;if(!i)break;t.currentAssistantText+=i,this.emitEvent({type:"text_delta",sessionId:e,timestamp:n,data:{text:i}});break}case"reasoning":{const i=o??s.text;if(!i)break;this.emitEvent({type:"thinking",sessionId:e,timestamp:n,data:{text:i}});break}case"tool":{const i=s.callID,r=s.tool,a=s.state,m=a.input,h=s.metadata,l=U(m),c=l&&typeof l=="object"&&!Array.isArray(l)?l:{},f=()=>{if(t.emittedToolStarts.has(i))return;t.emittedToolStarts.add(i);const p={...I(r,m,h),actionId:i};this.emitEvent({type:"tool_use_start",sessionId:e,timestamp:n,data:{toolName:r,toolInput:c,toolUseId:i,...p}}),t.adapterSession.messages.push({id:P(),sessionId:e,role:"tool_use",content:`${r}: ${JSON.stringify(c).slice(0,100)}`,timestamp:n,toolName:r,toolInput:c,toolUseId:i})};if(a.status==="running"){f();const p={...I(r,m,h),actionId:i};this.emit("status-change",e,"tool_using",{...p,usage:t.adapterSession.totalUsage})}else if(a.status==="completed"){(r==="todowrite"||r==="todo_write")&&this.syncTodosFromToolCall(t,m).catch(w=>{console.warn("[OpencodeSdkAdapter] \u540C\u6B65 todo \u5230\u6587\u4EF6\u5931\u8D25:",w)}),f();const p=O(a.output);this.emitEvent({type:"tool_use_end",sessionId:e,timestamp:n,data:{toolName:r,toolResult:p,isError:!1,toolUseId:i}}),t.emittedToolStarts.delete(i)}else if(a.status==="error"){f();const p=O(a.error);this.emitEvent({type:"tool_use_end",sessionId:e,timestamp:n,data:{toolName:r,toolResult:p,isError:!0,toolUseId:i}}),t.emittedToolStarts.delete(i)}break}}}getTodoStoreDir(){return g.join(_(),"todos")}async syncTodosFromToolCall(e,t){const s=e.config.agentId;if(!s)return;const o=t.todos;if(!Array.isArray(o)||o.length===0)return;const n=[];for(const l of o)if(l&&typeof l=="object"){const c=l,f=typeof c.content=="string"?c.content.trim():"",p=typeof c.status=="string"?c.status:"",w=typeof c.priority=="string"?c.priority:"";f&&p&&w&&n.push({content:f,status:p,priority:w})}if(n.length===0)return;const i=String(s).replace(/[^a-zA-Z0-9_-]/g,"_"),r=this.getTodoStoreDir(),a=g.join(r,`${i}.json`),m={agentId:s,updatedAt:new Date().toISOString(),background:"OpenCode runtime todos",todos:n};await S.promises.mkdir(r,{recursive:!0});const h=`${a}.tmp`;await S.promises.writeFile(h,JSON.stringify(m,null,2),"utf-8"),await S.promises.rename(h,a)}emitEvent(e){this.emit("event",e)}startIdleDetection(e){this.stopIdleDetection(e);const t=this.sessions.get(e),s=t?.idleCommands?.idleInputCommand;if(!(!t||!s)){if(this.isMessagePollingIdleCommand(s)){t.idlePollLoop||(t.idlePollLoop=new C({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendMessage(e,n?o.trim():this.toIdlePrompt(o),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendMessage(e,this.toIdlePrompt(o)),pollDelayMs:1500})),t.idlePollLoop.start();return}t.idlePollLoop||(t.idlePollLoop=new C({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>this.isMessagePollingIdleCommand(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,n)=>this.sendMessage(e,n?o.trim():this.toIdlePrompt(o),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.sendMessage(e,this.toIdlePrompt(o)),pollDelayMs:1500})),this.armIdleCheck(e)}}armIdleCheck(e){const t=this.sessions.get(e);if(!t)return;t.idleTimer&&clearTimeout(t.idleTimer);const s=setTimeout(()=>{t.idleTimer===s&&(t.idleTimer=void 0,this.armIdleCheck(e),this.checkIdleState(e))},500);t.idleTimer=s}stopIdleDetection(e){const t=this.sessions.get(e);t?.idlePollLoop?.stop(),t?.idleTimer&&(clearTimeout(t.idleTimer),t.idleTimer=void 0)}checkIdleState(e){const t=this.sessions.get(e);!t||t.adapterSession.status!=="waiting_input"||t.idleCommands?.idleInputCommand&&(this.sendMessage(e,this.toIdlePrompt(t.idleCommands.idleInputCommand)),this.stopIdleDetection(e))}toIdlePrompt(e){const t=e.trim();return this.isMessagePollingIdleCommand(t)?R:t}isMessagePollingIdleCommand(e){const t=e.trim();if(!t)return!1;const s=t.toLowerCase();return s.includes("poll_message")||s.includes("get_message")||t.includes("\u53D6\u6D88\u606F")}}export{Y as OpencodeSdkAdapter};
4
4
 
@@ -534,7 +534,13 @@ export declare abstract class BaseProviderAdapter extends EventEmitter {
534
534
 
535
535
 
536
536
 
537
- abstract terminateSession(sessionId: string): Promise<void>;
537
+
538
+
539
+
540
+
541
+ abstract terminateSession(sessionId: string, options?: {
542
+ discardContext?: boolean;
543
+ }): Promise<void>;
538
544
 
539
545
 
540
546
 
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync as T,readFileSync as D}from"node:fs";import M from"node:os";import S from"node:path";import{pathToFileURL as E}from"node:url";import x from"cors";import P from"express";import{adapterRegistry as F}from"./adapter/index.js";import{attachBrowserWebSocketServer as L}from"./browser/browser-ws-bridge.js";import{getAcodeDataHome as G,getActiveBridgeHttpPort as y,getAutoRegisterConfigFilePath as O,getBridgeDataHome as j,getBridgeListenHost as K,getBridgeRuntimePropertiesFilePath as N,getBridgeTemplateConfigFile as _,reserveBridgeListenPort as H,validateProductionToken as W,writeBridgeRuntimePropertiesFile as U}from"./config.js";import{attachRemoteDesktopWebSocketServer as z}from"./remote-desktop/index.js";import{acodeTodosRouter as J}from"./routes/acode-todos.js";import{agentStateRouter as Y}from"./routes/agent-state.js";import{aiSourcesRouter as Z}from"./routes/ai-sources.js";import{backgroundTasksRouter as q}from"./routes/background-tasks.js";import{bridgeTempFilesRouter as Q}from"./routes/bridge-temp-files.js";import{browserListenersRouter as V}from"./routes/browser-listeners.js";import{browserSessionsRouter as X}from"./routes/browser-sessions.js";import{capabilitiesRouter as ee}from"./routes/capabilities.js";import{computerRouter as re}from"./routes/computer.js";import{dashboardRouter as te}from"./routes/dashboard.js";import{debugMountRouter as ie}from"./routes/debug-mount.js";import{desktopControlRouter as oe}from"./routes/desktop-control.js";import{eventsRouter as ne}from"./routes/events.js";import{fileBrowserRouter as se}from"./routes/file-browser.js";import{fileChangeDiffRouter as ae}from"./routes/file-change-diff.js";import{fileDiffRollbackRouter as me}from"./routes/file-diff-rollback.js";import{fileSnapshotRouter as ue}from"./routes/file-snapshot.js";import{gitRouter as ce}from"./routes/git.js";import{instanceRouter as de,setGracefulShutdownFn as ge}from"./routes/instance.js";import{jdksRouter as pe}from"./routes/jdks.js";import{launchRouter as fe}from"./routes/launch.js";import{lspProvidersRouter as le}from"./routes/lsp-providers.js";import{attachLspWebSocketServer as be}from"./routes/lsp.js";import{ltrRouter as he}from"./routes/ltr.js";import{mcpExtraRouter as we}from"./routes/mcp-extra.js";import{mcpRouter as Re}from"./routes/mcp.js";import{pluginsRouter as Se}from"./routes/plugins.js";import{processesRouter as Pe}from"./routes/processes.js";import{propertiesRouter as ye}from"./routes/properties.js";import{attachPtyWebSocketServer as Ie,closeAllPtySessions as $e,ptyRouter as ke,ptySessions as Ce}from"./routes/pty.js";import{runtimeBindingRouter as Ae,logRuntimeBindingStartupState as ve}from"./routes/runtime-binding.js";import{sessionsRouter as Be}from"./routes/sessions.js";import{skillsRouter as Te}from"./routes/skills.js";import{subAgentsRouter as De}from"./routes/sub-agents.js";import{systemMetricsRouter as Me}from"./routes/system-metrics.js";import{taskContextRouter as Ee}from"./routes/task-context.js";import{techStackRouter as xe}from"./routes/tech-stack.js";import{terminalRouter as Fe,sdkSessions as w}from"./routes/terminal.js";import{workspaceIndexRouter as Le}from"./routes/workspace-index.js";import{ymlRouter as Ge}from"./routes/yml.js";import{accessControlMiddleware as Oe}from"./services/access-control.js";import{ensureAcodePackageReleased as je,getReleasedAcodeEntryPath as Ke}from"./services/acode-package.js";import{getAgentProcessManager as I}from"./services/agent-process-manager.js";import{autoRegister as Ne,unregister as _e,bridgeRestartCleanup as He,cancelBackgroundRegisterRetries as We}from"./services/auto-register.js";import{ensureAwsClientAgentMcpReleased as Ue}from"./services/aws-client-agent-mcp.js";import{disposeBrowserSessionManager as ze}from"./services/browser-session-manager.js";import{handleCliCommand as Je}from"./services/cli-commands.js";import{disposeDesktopMcpManager as Ye}from"./services/desktop-mcp-manager.js";import{getLaunchManager as Ze}from"./services/launch-manager.js";import{migrateOldPathsOnStartup as qe}from"./services/legacy-path-migration.js";import{deliverPendingBridgeLifecycleNotifications as Qe}from"./services/lifecycle-state.js";import{startLogRetention as Ve}from"./services/log-retention.js";import{startOrphanMonitor as Xe,stopOrphanMonitor as er}from"./services/orphan-monitor.js";import{pluginManager as rr}from"./services/plugin-manager.js";import{detectOrphanProcesses as tr}from"./services/process-detector.js";import{buildGracefulShutdownPlan as ir,shouldCleanupPersistedSessionsOnStartup as or}from"./services/runtime-lifecycle-policy.js";import{ensureStartupConfig as nr}from"./services/startup-config-wizard.js";import{subAgentStore as sr}from"./services/sub-agent-manager-instance.js";import{loadPersistedSessions as $,savePersistedSessions as k}from"./services/terminal-persistence.js";import{stopTunnelClient as ar}from"./services/tunnel-client.js";import{logger as e}from"./utils/logger.js";const C=await Je();C.handled&&process.exit(C.exitCode),await nr(),W(),Ue(),je(),qe(),ve(),await H(),U(),e.info(`[runtime-bridge] \u5DF2\u5199\u5165\u8FD0\u884C\u65F6\u914D\u7F6E ${N()}\uFF08port=${y()}\uFF09`),e.info(`[runtime-bridge] ACode \u6570\u636E\u76EE\u5F55(\u7528\u6237): ${G()}`),e.info(`[runtime-bridge] Bridge \u6570\u636E\u76EE\u5F55: ${j()}`),e.info(`[runtime-bridge] \u6A21\u677F\u914D\u7F6E: ${_()}`);async function mr(){try{if(await Ne())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:n}=await import("./services/auto-register.js"),o=n();!!o.userKey&&o.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 ${O()}`))}}catch(r){const n=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",n.message)}}mr().then(()=>ur()).then(()=>Qe()).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)}),import("./services/update-notifier.js").then(({startUpdateNotifier:r})=>r()).catch(r=>{e.warn("[runtime-bridge] \u7248\u672C\u68C0\u67E5\u670D\u52A1\u542F\u52A8\u5931\u8D25:",r.message)});async function ur(){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"),n=r();if(!n.registered||!n.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 o=await He();o.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${o.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${o.error}`)}catch(r){const n=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",n.message)}}async function cr(){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 I().rebuildRegistry(r.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const n=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",n.message)}}cr().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",r)}),import(E(S.join(Ke(),"..","background-command-manager.js")).href).then(async r=>{const n=r.backgroundCommandManager;if(!n||typeof n.reconcileAllAgents!="function"){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u7BA1\u7406\u5668\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u542F\u52A8\u5B64\u513F\u5BF9\u8D26");return}const o=await n.reconcileAllAgents();o>0&&e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5B8C\u6210\uFF1A\u4FEE\u590D ${o} \u6761\u540E\u53F0\u547D\u4EE4\u72B6\u6001`)}).catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5931\u8D25:",r.message)});async function dr(){try{const r=await import("node:fs/promises"),n=await import("node:path"),o=await import("node:os"),d=n.join(o.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(d,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(d),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(!or(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 I().rebuildRegistry(a.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.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 g=await tr(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(g.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of g)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 g)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:s}=await import("node:child_process");s(`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(s){const c=s;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 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const n=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",n.message)}}dr().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),Xe().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const i=P();i.use(Oe),i.use(x()),i.use(P.json({limit:"1mb"})),i.use("/runtime",Ae),i.use("/runtime",ye),i.use("/runtime",Ge),i.use("/runtime",de),i.use("/runtime",Te),i.use("/runtime",Re),i.use("/runtime",ee),i.use("/runtime",Fe),i.use("/runtime",Be),i.use("/runtime",Pe),i.use("/runtime",fe),i.use("/runtime",pe),i.use("/runtime",xe),i.use("/runtime",Me),i.use("/runtime",ne),i.use("/runtime",ce),i.use("/runtime",ue),i.use("/runtime",J),i.use("/runtime",Y),i.use("/runtime",q),i.use("/runtime",De),i.use("/runtime",X),i.use("/runtime",oe),i.use("/runtime",V),i.use("/runtime",Se),i.use("/runtime",we),i.use("/runtime",ie),i.use("/runtime",Z),i.use("/runtime",Ee),i.use("/runtime",me),i.use("/runtime",ae),i.use("/runtime",le),i.use("/runtime/computer",re),i.use("/pty",ke),i.use("/",te),i.use("/api/file-browser",se),i.use("/api",Le),i.use("/api/ltr",he),i.use("/api/bridge-temp-files",Q);function gr(){const r=y(),n=K(),o=n?i.listen(r,n,()=>{e.info(`[runtime-bridge] listening on ${n}:${r}`)}):i.listen(r,()=>{e.info(`[runtime-bridge] listening on ${r}`)});return Ie(o),z(o),L(o),be(o),o.on("error",d=>{if(d.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${r} became unavailable after reservation (another process grabbed it concurrently). Set AWS_RUNTIME_BRIDGE_PORT to a free port and restart.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",d),process.exitCode=1}),o}let A=!1;async function b(r,n,o=!1){if(A){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}A=!0,o||R()&&(o=!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=${o})`);const d=Date.now(),u=ir(o);try{const a=w.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,s]of w.entries())try{const c=s.providerId||"claude-code",p=F.get(c);let f="";try{const m=p.getSessionPid?.(t);m&&(f=` (PID: ${m})`)}catch{}await p.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${f}`),w.delete(t)}catch(c){const p=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,p.message),w.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=Ce.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),$e("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`);try{const{running:t,stopped:s}=await Ze().stopAll();t>0&&e.info(`[runtime-bridge] \u542F\u52A8\u9879\u8FDB\u7A0B\u5DF2\u505C\u6B62: running=${t}, stopped=${s}`)}catch(t){e.warn("[runtime-bridge] \u505C\u6B62\u542F\u52A8\u9879\u8FDB\u7A0B\u5931\u8D25:",t.message)}e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+S.join(import.meta.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(er(),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:s}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),p=await c();if(p.length>0){const f=await t(p.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(f.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${f.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of f)if(m.process.pid){const B=await s(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 ${B.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const s=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",s.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 _e()}catch(t){const s=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",s.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(We(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),ar()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await k([])}catch(t){const s=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",s.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 ze(),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)}try{await Ye(),e.info("[runtime-bridge] desktop \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] desktop \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await rr.stopAll(),e.info("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u6E05\u7406\u5931\u8D25:",t.message)}const g=Date.now()-d;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${g}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),n.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)}}sr.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 h=gr();Ve();const v=S.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(T(v)){const r=D(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}ge(async(r,n)=>{await b(r,h,n)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",h,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",h,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",h,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",h)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
2
+ import{existsSync as T,readFileSync as D}from"node:fs";import M from"node:os";import S from"node:path";import{pathToFileURL as E}from"node:url";import{sweepExpiredJournals as x}from"@agentswork/acode";import F from"cors";import P from"express";import{adapterRegistry as L}from"./adapter/index.js";import{attachBrowserWebSocketServer as G}from"./browser/browser-ws-bridge.js";import{getAcodeDataHome as O,getActiveBridgeHttpPort as $,getAutoRegisterConfigFilePath as j,getBridgeDataHome as K,getBridgeListenHost as N,getBridgeRuntimePropertiesFilePath as _,getBridgeTemplateConfigFile as H,reserveBridgeListenPort as W,validateProductionToken as U,writeBridgeRuntimePropertiesFile as J}from"./config.js";import{attachRemoteDesktopWebSocketServer as z}from"./remote-desktop/index.js";import{acodeTodosRouter as Y}from"./routes/acode-todos.js";import{agentStateRouter as Z}from"./routes/agent-state.js";import{aiSourcesRouter as q}from"./routes/ai-sources.js";import{backgroundTasksRouter as Q}from"./routes/background-tasks.js";import{bridgeTempFilesRouter as V}from"./routes/bridge-temp-files.js";import{browserListenersRouter as X}from"./routes/browser-listeners.js";import{browserSessionsRouter as ee}from"./routes/browser-sessions.js";import{capabilitiesRouter as re}from"./routes/capabilities.js";import{computerRouter as te}from"./routes/computer.js";import{dashboardRouter as ie}from"./routes/dashboard.js";import{debugMountRouter as oe}from"./routes/debug-mount.js";import{desktopControlRouter as ne}from"./routes/desktop-control.js";import{eventsRouter as se}from"./routes/events.js";import{fileBrowserRouter as ae}from"./routes/file-browser.js";import{fileChangeDiffRouter as me}from"./routes/file-change-diff.js";import{fileDiffRollbackRouter as ue}from"./routes/file-diff-rollback.js";import{fileSnapshotRouter as ce}from"./routes/file-snapshot.js";import{gitRouter as de}from"./routes/git.js";import{instanceRouter as ge,setGracefulShutdownFn as pe}from"./routes/instance.js";import{jdksRouter as fe}from"./routes/jdks.js";import{launchRouter as le}from"./routes/launch.js";import{lspProvidersRouter as be}from"./routes/lsp-providers.js";import{attachLspWebSocketServer as he}from"./routes/lsp.js";import{ltrRouter as we}from"./routes/ltr.js";import{mcpExtraRouter as Re}from"./routes/mcp-extra.js";import{mcpRouter as Se}from"./routes/mcp.js";import{pluginsRouter as Pe}from"./routes/plugins.js";import{processesRouter as $e}from"./routes/processes.js";import{propertiesRouter as ye}from"./routes/properties.js";import{attachPtyWebSocketServer as Ie,closeAllPtySessions as ke,ptyRouter as Ce,ptySessions as Ae}from"./routes/pty.js";import{runtimeBindingRouter as ve,logRuntimeBindingStartupState as Be}from"./routes/runtime-binding.js";import{sessionsRouter as Te}from"./routes/sessions.js";import{skillsRouter as De}from"./routes/skills.js";import{subAgentsRouter as Me}from"./routes/sub-agents.js";import{systemMetricsRouter as Ee}from"./routes/system-metrics.js";import{taskContextRouter as xe}from"./routes/task-context.js";import{techStackRouter as Fe}from"./routes/tech-stack.js";import{terminalRouter as Le,sdkSessions as w}from"./routes/terminal.js";import{workspaceIndexRouter as Ge}from"./routes/workspace-index.js";import{ymlRouter as Oe}from"./routes/yml.js";import{accessControlMiddleware as je}from"./services/access-control.js";import{ensureAcodePackageReleased as Ke,getReleasedAcodeEntryPath as Ne}from"./services/acode-package.js";import{getAgentProcessManager as y}from"./services/agent-process-manager.js";import{autoRegister as _e,unregister as He,bridgeRestartCleanup as We,cancelBackgroundRegisterRetries as Ue}from"./services/auto-register.js";import{ensureAwsClientAgentMcpReleased as Je}from"./services/aws-client-agent-mcp.js";import{disposeBrowserSessionManager as ze}from"./services/browser-session-manager.js";import{handleCliCommand as Ye}from"./services/cli-commands.js";import{disposeDesktopMcpManager as Ze}from"./services/desktop-mcp-manager.js";import{getLaunchManager as qe}from"./services/launch-manager.js";import{migrateOldPathsOnStartup as Qe}from"./services/legacy-path-migration.js";import{deliverPendingBridgeLifecycleNotifications as Ve}from"./services/lifecycle-state.js";import{startLogRetention as Xe}from"./services/log-retention.js";import{startOrphanMonitor as er,stopOrphanMonitor as rr}from"./services/orphan-monitor.js";import{pluginManager as tr}from"./services/plugin-manager.js";import{detectOrphanProcesses as ir}from"./services/process-detector.js";import{buildGracefulShutdownPlan as or,shouldCleanupPersistedSessionsOnStartup as nr}from"./services/runtime-lifecycle-policy.js";import{ensureStartupConfig as sr}from"./services/startup-config-wizard.js";import{subAgentStore as ar}from"./services/sub-agent-manager-instance.js";import{loadPersistedSessions as I,savePersistedSessions as k}from"./services/terminal-persistence.js";import{stopTunnelClient as mr}from"./services/tunnel-client.js";import{logger as e}from"./utils/logger.js";const C=await Ye();C.handled&&process.exit(C.exitCode),await sr(),U(),Je(),Ke(),Qe(),Be(),await W(),J(),e.info(`[runtime-bridge] \u5DF2\u5199\u5165\u8FD0\u884C\u65F6\u914D\u7F6E ${_()}\uFF08port=${$()}\uFF09`),e.info(`[runtime-bridge] ACode \u6570\u636E\u76EE\u5F55(\u7528\u6237): ${O()}`),e.info(`[runtime-bridge] Bridge \u6570\u636E\u76EE\u5F55: ${K()}`),e.info(`[runtime-bridge] \u6A21\u677F\u914D\u7F6E: ${H()}`),x().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u626B ${r} \u4E2A\u8D85\u671F\u4F11\u7720 journal`)}).catch(()=>{});async function ur(){try{if(await _e())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:n}=await import("./services/auto-register.js"),o=n();!!o.userKey&&o.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 ${j()}`))}}catch(r){const n=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",n.message)}}ur().then(()=>cr()).then(()=>Ve()).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)}),import("./services/update-notifier.js").then(({startUpdateNotifier:r})=>r()).catch(r=>{e.warn("[runtime-bridge] \u7248\u672C\u68C0\u67E5\u670D\u52A1\u542F\u52A8\u5931\u8D25:",r.message)});async function cr(){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"),n=r();if(!n.registered||!n.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 o=await We();o.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${o.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${o.error}`)}catch(r){const n=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",n.message)}}async function dr(){try{const r=await I();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 y().rebuildRegistry(r.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const n=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",n.message)}}dr().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",r)}),import(E(S.join(Ne(),"..","background-command-manager.js")).href).then(async r=>{const n=r.backgroundCommandManager;if(!n||typeof n.reconcileAllAgents!="function"){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u7BA1\u7406\u5668\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u542F\u52A8\u5B64\u513F\u5BF9\u8D26");return}const o=await n.reconcileAllAgents();o>0&&e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5B8C\u6210\uFF1A\u4FEE\u590D ${o} \u6761\u540E\u53F0\u547D\u4EE4\u72B6\u6001`)}).catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5931\u8D25:",r.message)});async function gr(){try{const r=await import("node:fs/promises"),n=await import("node:path"),o=await import("node:os"),d=n.join(o.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(d,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(d),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await I();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(!nr(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 y().rebuildRegistry(a.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.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 g=await ir(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(g.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of g)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 g)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:s}=await import("node:child_process");s(`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(s){const c=s;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 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const n=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",n.message)}}gr().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),er().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const i=P();i.use(je),i.use(F()),i.use(P.json({limit:"1mb"})),i.use("/runtime",ve),i.use("/runtime",ye),i.use("/runtime",Oe),i.use("/runtime",ge),i.use("/runtime",De),i.use("/runtime",Se),i.use("/runtime",re),i.use("/runtime",Le),i.use("/runtime",Te),i.use("/runtime",$e),i.use("/runtime",le),i.use("/runtime",fe),i.use("/runtime",Fe),i.use("/runtime",Ee),i.use("/runtime",se),i.use("/runtime",de),i.use("/runtime",ce),i.use("/runtime",Y),i.use("/runtime",Z),i.use("/runtime",Q),i.use("/runtime",Me),i.use("/runtime",ee),i.use("/runtime",ne),i.use("/runtime",X),i.use("/runtime",Pe),i.use("/runtime",Re),i.use("/runtime",oe),i.use("/runtime",q),i.use("/runtime",xe),i.use("/runtime",ue),i.use("/runtime",me),i.use("/runtime",be),i.use("/runtime/computer",te),i.use("/pty",Ce),i.use("/",ie),i.use("/api/file-browser",ae),i.use("/api",Ge),i.use("/api/ltr",we),i.use("/api/bridge-temp-files",V);function pr(){const r=$(),n=N(),o=n?i.listen(r,n,()=>{e.info(`[runtime-bridge] listening on ${n}:${r}`)}):i.listen(r,()=>{e.info(`[runtime-bridge] listening on ${r}`)});return Ie(o),z(o),G(o),he(o),o.on("error",d=>{if(d.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${r} became unavailable after reservation (another process grabbed it concurrently). Set AWS_RUNTIME_BRIDGE_PORT to a free port and restart.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",d),process.exitCode=1}),o}let A=!1;async function b(r,n,o=!1){if(A){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}A=!0,o||R()&&(o=!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=${o})`);const d=Date.now(),u=or(o);try{const a=w.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,s]of w.entries())try{const c=s.providerId||"claude-code",p=L.get(c);let f="";try{const m=p.getSessionPid?.(t);m&&(f=` (PID: ${m})`)}catch{}await p.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${f}`),w.delete(t)}catch(c){const p=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,p.message),w.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=Ae.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),ke("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`);try{const{running:t,stopped:s}=await qe().stopAll();t>0&&e.info(`[runtime-bridge] \u542F\u52A8\u9879\u8FDB\u7A0B\u5DF2\u505C\u6B62: running=${t}, stopped=${s}`)}catch(t){e.warn("[runtime-bridge] \u505C\u6B62\u542F\u52A8\u9879\u8FDB\u7A0B\u5931\u8D25:",t.message)}e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+S.join(import.meta.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(rr(),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:s}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),p=await c();if(p.length>0){const f=await t(p.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(f.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${f.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of f)if(m.process.pid){const B=await s(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 ${B.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const s=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",s.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 s=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",s.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(Ue(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),mr()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await k([])}catch(t){const s=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",s.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 ze(),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)}try{await Ze(),e.info("[runtime-bridge] desktop \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] desktop \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await tr.stopAll(),e.info("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u6E05\u7406\u5931\u8D25:",t.message)}const g=Date.now()-d;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${g}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),n.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)}}ar.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 h=pr();Xe();const v=S.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(T(v)){const r=D(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}pe(async(r,n)=>{await b(r,h,n)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",h,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",h,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",h,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",h)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
3
3
 
@@ -72,9 +72,22 @@ export declare function parseResumeTranscript(raw: unknown): unknown[] | undefin
72
72
 
73
73
 
74
74
  export declare function parseResumeTokenUsage(raw: unknown): AdapterSessionConfig["resumeTokenUsage"];
75
+
76
+
77
+
78
+
79
+
80
+ export declare const CRASH_RECOVERY_NOTICE_INTERRUPTED: string;
81
+ export declare const CRASH_RECOVERY_NOTICE_CLEAN = "\u6CE8\u610F\uFF1A\u672C\u5B9E\u4F8B\u4E0A\u6B21\u6B63\u5E38\u7ED3\u675F\u8FD0\u884C\u5E76\u81EA\u52A8\u4FDD\u5B58\u4E86\u5B8C\u6574\u8FDB\u5EA6\u3002\u8BF7\u57FA\u4E8E\u5FEB\u7167\u7EE7\u7EED\u63A8\u8FDB\u672A\u5B8C\u6210\u7684\u4E8B\u9879\u3002";
75
82
  export interface RuntimeStopOptions {
76
83
  statusNotified: boolean;
77
84
  reason: string | undefined;
85
+
86
+
87
+
88
+
89
+
90
+ discardContext: boolean;
78
91
  }
79
92
  export type RuntimeContextResetSupport = {
80
93
  supported: true;