aws-runtime-bridge 1.9.153 → 1.9.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +766 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +57 -6
- package/dist/adapter/AcodeSdkAdapter.js +4 -8
- package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +3 -3
- package/dist/adapter/prompts.d.ts +1 -1
- package/dist/adapter/prompts.js +1 -1
- package/dist/adapter/types.d.ts +41 -20
- package/dist/adapter/types.js +1 -1
- package/dist/browser/frame-encode.d.ts +25 -0
- package/dist/browser/frame-encode.js +2 -0
- package/dist/browser/screencast-differ.d.ts +2 -3
- package/dist/browser/screencast-differ.js +1 -1
- package/dist/browser/screencast-manager.js +1 -1
- package/dist/browser/types.d.ts +5 -1
- package/dist/browser/types.js +1 -1
- package/dist/desktop/desktop-mcp-client.js +2 -2
- package/dist/routes/acode-todos.js +1 -1
- package/dist/routes/background-tasks.js +3 -3
- package/dist/routes/capabilities.js +1 -1
- package/dist/routes/dashboard.d.ts +2 -0
- package/dist/routes/dashboard.js +4 -4
- package/dist/routes/git.js +22 -22
- package/dist/routes/instance.js +1 -1
- package/dist/routes/launch.js +10 -10
- package/dist/routes/ltr.js +1 -1
- package/dist/routes/mcp-extra.js +2 -2
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/plugins.js +1 -1
- package/dist/routes/pty.d.ts +11 -3
- package/dist/routes/pty.js +3 -3
- package/dist/routes/runtime-binding.js +1 -1
- package/dist/routes/sessions.d.ts +18 -74
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/sub-agents.js +8 -8
- package/dist/routes/terminal.d.ts +24 -2
- package/dist/routes/terminal.js +34 -36
- package/dist/services/agent-process-manager.js +1 -1
- package/dist/services/agent-pty-manager.js +4 -4
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/capability-config.d.ts +8 -0
- package/dist/services/capability-config.js +2 -2
- package/dist/services/desktop-mcp-manager.d.ts +3 -1
- package/dist/services/desktop-mcp-manager.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-features.d.ts +26 -2
- package/dist/services/instance-features.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/launch-manager.d.ts +9 -1
- package/dist/services/launch-manager.js +6 -6
- package/dist/services/launch-metrics.d.ts +1 -1
- package/dist/services/launch-metrics.js +4 -3
- package/dist/services/mcp-deploy.d.ts +4 -0
- package/dist/services/mcp-env-injector.d.ts +12 -0
- package/dist/services/mcp-env-injector.js +2 -0
- package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
- package/dist/services/mcp-launch-binding-queue.js +1 -1
- package/dist/services/orphan-monitor.js +1 -1
- package/dist/services/panel-env.d.ts +6 -2
- package/dist/services/panel-env.js +1 -1
- package/dist/services/plugin-manager.js +9 -9
- package/dist/services/process-detector.d.ts +23 -3
- package/dist/services/process-detector.js +13 -13
- package/dist/services/runtime-resources-snapshot.d.ts +3 -0
- package/dist/services/runtime-resources-snapshot.js +3 -0
- package/dist/services/session-output.d.ts +13 -0
- package/dist/services/session-output.js +4 -4
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspace-watch.js +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/utils/env-safety.d.ts +15 -0
- package/dist/utils/env-safety.js +2 -0
- package/dist/utils/lifecycle-log.d.ts +2 -0
- package/dist/utils/lifecycle-log.js +3 -0
- package/dist/utils/mcp-utils.js +1 -1
- package/package/acode/dist/ask-user-question-tool.js +1 -1
- package/package/acode/dist/await-complete-tool.js +1 -1
- package/package/acode/dist/background-command-manager.js +4 -4
- package/package/acode/dist/background-command-tools.js +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts +31 -2
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/built-in-symbols-tool.js +1 -1
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
- package/package/acode/dist/compaction.d.ts +10 -0
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/context-overflow.d.ts +19 -0
- package/package/acode/dist/context-overflow.js +2 -0
- package/package/acode/dist/grammars/grammars/tree-sitter-lua.wasm +0 -0
- package/package/acode/dist/index.d.ts +4 -1
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/mcpToolNames.d.ts +4 -0
- package/package/acode/dist/mcpToolNames.js +1 -1
- package/package/acode/dist/parsers/ast-cache.d.ts +12 -1
- package/package/acode/dist/parsers/ast-cache.js +1 -1
- package/package/acode/dist/parsers/language-queries.js +1 -1
- package/package/acode/dist/parsers/symbol-extractor.js +2 -2
- package/package/acode/dist/parsers/tree-sitter-loader.d.ts +1 -1
- package/package/acode/dist/parsers/tree-sitter-loader.js +1 -1
- package/package/acode/dist/plugin-types.d.ts +5 -0
- package/package/acode/dist/plugin-types.js +1 -0
- package/package/acode/dist/read-file-state.d.ts +48 -0
- package/package/acode/dist/read-file-state.js +2 -0
- package/package/acode/dist/runtime-environment.d.ts +2 -0
- package/package/acode/dist/runtime-environment.js +3 -2
- package/package/acode/dist/runtime.d.ts +124 -10
- package/package/acode/dist/runtime.js +27 -23
- package/package/acode/dist/skill-tool.js +3 -3
- package/package/acode/dist/sub-agent-manager.js +1 -1
- package/package/acode/dist/sub-agent-tools.js +5 -5
- package/package/acode/dist/todo-tool.js +3 -3
- package/package/acode/dist/tool-allocation.js +1 -1
- package/package/acode/dist/tool-concurrency/index.d.ts +5 -0
- package/package/acode/dist/tool-concurrency/index.js +2 -0
- package/package/acode/dist/tool-concurrency/observability.d.ts +46 -0
- package/package/acode/dist/tool-concurrency/observability.js +3 -0
- package/package/acode/dist/tool-concurrency/resource-lock.d.ts +25 -0
- package/package/acode/dist/tool-concurrency/resource-lock.js +2 -0
- package/package/acode/dist/tool-concurrency/scheduler.d.ts +30 -0
- package/package/acode/dist/tool-concurrency/scheduler.js +2 -0
- package/package/acode/dist/tool-concurrency/types.d.ts +80 -0
- package/package/acode/dist/tool-concurrency/types.js +2 -0
- package/package/acode/dist/tool-group-manager.d.ts +128 -0
- package/package/acode/dist/tool-group-manager.js +18 -0
- package/package/acode/dist/types.d.ts +20 -2
- package/package/acode/package.json +3 -3
- package/package/aws-client-agent-mcp/README.md +1 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +20 -32
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
- package/package/aws-client-agent-mcp/dist/logger.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +65 -10
- package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -30
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +42 -7
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +196 -21
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
- package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
- package/package/aws-client-agent-mcp/dist/office/office-equation.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/office/office-equation.js +2 -0
- package/package/aws-client-agent-mcp/dist/office/office-image.d.ts +12 -0
- package/package/aws-client-agent-mcp/dist/office/office-image.js +2 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +40 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.js +2 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
- package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +56 -3
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package/aws-client-agent-mcp/package.json +2 -1
- package/package.json +1 -1
- package/package/acode/dist/capability-prompt.d.ts +0 -16
- package/package/acode/dist/capability-prompt.js +0 -3
- package/package/acode/dist/plugin-tools.d.ts +0 -14
- package/package/acode/dist/plugin-tools.js +0 -9
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import{Router as
|
|
1
|
+
import{Router as m}from"express";import{validateToken as c}from"../middleware/auth.js";import{noteDashboardActivity as l}from"./dashboard.js";import{subAgentManager as u,subAgentStore as g}from"../services/sub-agent-manager-instance.js";import{createLogger as f}from"../utils/logger.js";const b=f("sub-agents"),p=m();p.get("/sub-agents/:agentId",c,async(r,t)=>{const s=String(r.params.agentId??"");if(!s.trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}try{const e=await g.list(s),n=u.listActiveByParent(s),o=new Set(n.map(a=>a.subId)),i=n.map(a=>({subId:a.subId,parentAgentId:a.parentAgentId,parentSessionId:a.parentSessionId,subagentType:a.subagentType,description:a.description,prompt:a.prompt,status:a.status,startedAt:a.startedAt,contextSnapshot:a.contextSnapshot,availableTools:a.availableTools})),d=e.filter(a=>!o.has(a.subId)&&a.status!=="running"&&a.status!=="pending"),I=await g.read(s);t.json({ok:!0,agentId:s,updatedAt:I.updatedAt,running:i,history:d})}catch(e){const n=e;b.error("[sub-agents] \u5217\u8868\u5931\u8D25: %s",n.message),t.status(500).json({ok:!1,error:n.message})}}),p.get("/sub-agents/:agentId/events",c,async(r,t)=>{l();const s=String(r.params.agentId??"");if(!s.trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.write(`: connected
|
|
2
2
|
|
|
3
|
-
`);const e=
|
|
3
|
+
`);const e=u.listActiveByParent(s);e.length>0&&t.write(`data: ${JSON.stringify({type:"snapshot",agentId:s,timestamp:new Date().toISOString(),data:{running:e.map(i=>({subId:i.subId,subagentType:i.subagentType,description:i.description,status:i.status,startedAt:i.startedAt}))}})}
|
|
4
4
|
|
|
5
|
-
`);const n=
|
|
5
|
+
`);const n=u.subscribe("*",i=>{const d=u.getSubAgent(i.subId);!d||d.parentAgentId!==s||t.write(`data: ${JSON.stringify(i)}
|
|
6
6
|
|
|
7
7
|
`)}),o=setInterval(()=>{try{t.write(`: heartbeat
|
|
8
8
|
|
|
9
|
-
`)}catch{}},3e4);r.on("close",()=>{n(),clearInterval(o);try{t.end()}catch{}})}),p.get("/sub-agents/:agentId/:subId",c,async(r,t)=>{const s=String(r.params.agentId??""),e=String(r.params.subId??"");if(!s.trim()||!e.trim()){t.status(400).json({ok:!1,error:"agentId and subId are required"});return}try{const n=
|
|
9
|
+
`)}catch{}},3e4);r.on("close",()=>{n(),clearInterval(o);try{t.end()}catch{}})}),p.get("/sub-agents/:agentId/:subId",c,async(r,t)=>{const s=String(r.params.agentId??""),e=String(r.params.subId??"");if(!s.trim()||!e.trim()){t.status(400).json({ok:!1,error:"agentId and subId are required"});return}try{const n=u.getSubAgent(e);if(n){const i=await g.readEvents(s,e).catch(()=>{});t.json({ok:!0,subAgent:{subId:n.subId,parentAgentId:n.parentAgentId,parentSessionId:n.parentSessionId,subagentType:n.subagentType,description:n.description,prompt:n.prompt,status:n.status,startedAt:n.startedAt,contextSnapshot:n.contextSnapshot,availableTools:n.availableTools,events:i}});return}const o=await g.get(s,e);if(!o){t.status(404).json({ok:!1,error:"sub-agent not found"});return}t.json({ok:!0,subAgent:o})}catch(n){const o=n;b.error("[sub-agents] \u8BE6\u60C5\u5931\u8D25: %s",o.message),t.status(500).json({ok:!1,error:o.message})}}),p.get("/sub-agents/:agentId/:subId/events",c,async(r,t)=>{l();const s=String(r.params.agentId??""),e=String(r.params.subId??"");if(!s.trim()||!e.trim()){t.status(400).json({ok:!1,error:"agentId and subId are required"});return}t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.write(`: connected
|
|
10
10
|
|
|
11
|
-
`);try{const
|
|
11
|
+
`);try{const d=await g.readEvents(s,e);for(const I of d)t.write(`data: ${JSON.stringify(I)}
|
|
12
12
|
|
|
13
|
-
`)}catch(
|
|
13
|
+
`)}catch(d){b.error("[sub-agents] \u8865\u53D1\u5386\u53F2\u4E8B\u4EF6\u5931\u8D25: %s",d.message)}const n=u.getSubAgent(e);n&&t.write(`data: ${JSON.stringify({type:n.status==="pending"?"spawned":"running",subId:e,timestamp:new Date().toISOString(),data:{snapshot:n.contextSnapshot}})}
|
|
14
14
|
|
|
15
|
-
`);const o=
|
|
15
|
+
`);const o=u.subscribe(e,d=>{t.write(`data: ${JSON.stringify(d)}
|
|
16
16
|
|
|
17
17
|
`)}),i=setInterval(()=>{try{t.write(`: heartbeat
|
|
18
18
|
|
|
19
|
-
`)}catch{}},3e4);r.on("close",()=>{o(),clearInterval(i);try{t.end()}catch{}})}),p.post("/sub-agents/:agentId/:subId/abort",c,async(r,t)=>{const s=String(r.params.agentId??""),e=String(r.params.subId??"");if(!s.trim()||!e.trim()){t.status(400).json({ok:!1,error:"agentId and subId are required"});return}try{await
|
|
19
|
+
`)}catch{}},3e4);r.on("close",()=>{o(),clearInterval(i);try{t.end()}catch{}})}),p.post("/sub-agents/:agentId/:subId/abort",c,async(r,t)=>{const s=String(r.params.agentId??""),e=String(r.params.subId??"");if(!s.trim()||!e.trim()){t.status(400).json({ok:!1,error:"agentId and subId are required"});return}try{await u.abort(e),t.json({ok:!0,subId:e,status:"cancelled"})}catch(n){const o=n;b.error("[sub-agents] \u53D6\u6D88\u5931\u8D25: %s",o.message),t.status(500).json({ok:!1,error:o.message})}});export{p as subAgentsRouter};
|
|
20
20
|
|
|
@@ -22,6 +22,18 @@ export interface SdkSessionEntry {
|
|
|
22
22
|
cachedCapabilitiesActionDetail?: string;
|
|
23
23
|
}
|
|
24
24
|
export declare const sdkSessions: Map<string, SdkSessionEntry>;
|
|
25
|
+
|
|
26
|
+
export declare function renderSessionSnapshot(messages: Array<{
|
|
27
|
+
role: string;
|
|
28
|
+
content: string;
|
|
29
|
+
toolName?: string;
|
|
30
|
+
isError?: boolean;
|
|
31
|
+
}>): {
|
|
32
|
+
snapshot: string;
|
|
33
|
+
truncated: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export declare function parseResumeTranscript(raw: unknown): unknown[] | undefined;
|
|
25
37
|
export interface RuntimeStopOptions {
|
|
26
38
|
statusNotified: boolean;
|
|
27
39
|
reason: string | undefined;
|
|
@@ -52,6 +64,14 @@ export declare function resolveStatusChangeRuntimeState(status: string, actionIn
|
|
|
52
64
|
status: string;
|
|
53
65
|
actionInfo?: RuntimeStatusActionInfo;
|
|
54
66
|
};
|
|
67
|
+
|
|
68
|
+
export declare function isIdleStatusChangeRetryable(params: {
|
|
69
|
+
status: string;
|
|
70
|
+
actionInfo?: RuntimeStatusActionInfo;
|
|
71
|
+
restoredActionInfo?: RuntimeStatusActionInfo;
|
|
72
|
+
currentRuntimeActionType?: string;
|
|
73
|
+
shouldPreservePrevAction: boolean;
|
|
74
|
+
}): boolean;
|
|
55
75
|
export declare function buildAcodeCommandOutputPath(agentId: string, now?: Date): string;
|
|
56
76
|
export declare function countTerminalOutputLines(output: string): number;
|
|
57
77
|
export declare function formatCommandOutputSpilloverNotice(outputPath: string, lineLimit?: number): string;
|
|
@@ -79,12 +99,12 @@ export interface PersistedSessionReuseDecision {
|
|
|
79
99
|
reason: "active-pid" | "missing-pid" | "dead-pid" | "in-process-provider";
|
|
80
100
|
}
|
|
81
101
|
|
|
82
|
-
export declare function evaluatePersistedSessionReuse(session: Pick<PersistedSession, "pid"> & Partial<Pick<PersistedSession, "command">>, isPidRunning?: (pid: number) => boolean): PersistedSessionReuseDecision
|
|
102
|
+
export declare function evaluatePersistedSessionReuse(session: Pick<PersistedSession, "pid"> & Partial<Pick<PersistedSession, "command">>, isPidRunning?: (pid: number) => boolean | Promise<boolean>): Promise<PersistedSessionReuseDecision>;
|
|
83
103
|
|
|
84
104
|
export declare function cleanupSdkSessionByAgentId(agentId: string): string | undefined;
|
|
85
105
|
|
|
86
106
|
export declare function formatTerminalPrompt(currentDirectory: string): string;
|
|
87
|
-
export declare function buildRuntimeEnv(agentId: string, workspacePath: string | undefined, baseEnv: NodeJS.ProcessEnv, envOverrides?: Record<string, unknown
|
|
107
|
+
export declare function buildRuntimeEnv(agentId: string, workspacePath: string | undefined, baseEnv: NodeJS.ProcessEnv, envOverrides?: Record<string, unknown>, projectRoot?: string | undefined): Record<string, string>;
|
|
88
108
|
|
|
89
109
|
export declare function resolveSdkInputMessage(input: unknown): Promise<string>;
|
|
90
110
|
export interface ClaudeCodeLaunchConfig {
|
|
@@ -106,4 +126,6 @@ export declare function resolveRuntimeStatusFromProviderEvent(event: ProviderEve
|
|
|
106
126
|
|
|
107
127
|
export declare function raceSendOutputWithRetry(factory: (signal: AbortSignal) => Promise<void>, timeoutMs?: number, maxRetries?: number): Promise<void>;
|
|
108
128
|
export declare function resolveSdkProviderId(command?: string): string;
|
|
129
|
+
|
|
130
|
+
export declare function withSenderSignature(input: unknown, sender: unknown): unknown;
|
|
109
131
|
export {};
|
package/dist/routes/terminal.js
CHANGED
|
@@ -1,54 +1,52 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as pt}from"node:child_process";import{promises as v}from"node:fs";import gt from"node:os";import j from"node:path";import{TextDecoder as re}from"node:util";import Pe from"axios";import{Router as yt}from"express";import{v4 as ht}from"uuid";import{adapterRegistry as _,getToolActionInfo as be,isTransientClipboardPasteFilePath as Oe,redactTransientClipboardPastePaths as K,registerSdkProviders as It,resolveSdkProviderIdByCommand as St}from"../adapter/index.js";import{MESSAGE_POLLING_IDLE_PROMPT as Le}from"../adapter/prompts.js";import{getActiveBridgeHttpPort as At,getAcodeDataHome as Me}from"../config.js";import{buildResumeContextBlock as Tt}from"@agentswork/acode";import{validateToken as I}from"../middleware/auth.js";import{getAgentProcessManager as ke}from"../services/agent-process-manager.js";import{createAiConfigService as _t}from"../services/ai-config-service.js";import{resolveSchedulerBaseUrlFromToken as Ue}from"../services/auto-register.js";import{setChangeCacheRetentionDays as bt}from"../services/change-cache-retention.js";import{getAllPushStats as kt,startHeartbeatScheduler as Ct}from"../services/event-delta-pusher.js";import{prepareAcodeInstanceConfig as $t,redactForLog as oe}from"../services/instance-ai-config-service.js";import{setAgentFeatures as wt,setAgentCapabilities as Et,setAgentInheritedFeatures as Rt,setAgentCapabilitiesInherited as Dt,getAgentFeatures as Pt,getAgentInheritedFeatures as Ot,getFeatureState as T,LAUNCH_ITEM_FEATURE_KEY as xe,HIRE_FEATURE_KEY as Ne,PENCIL_FEATURE_KEY as je,DRAW_FEATURE_KEY as Be,OFFICE_FEATURE_KEY as Fe,COLLABORATION_TASK_FEATURE_KEY as ve,COLLABORATION_MEETING_FEATURE_KEY as Ke,COLLABORATION_DEBUG_FEATURE_KEY as He,COLLABORATION_FILE_HISTORY_FEATURE_KEY as qe,EMAIL_FEATURE_KEY as ze}from"../services/instance-features.js";import{enqueueMcpLaunchBinding as Lt}from"../services/mcp-launch-binding-queue.js";import{setPanelEnvVars as Mt}from"../services/panel-env.js";import{findClaudeCodeProcesses as Ut,isProcessRunning as xt}from"../services/process-detector.js";import{forgetSession as H,onSdkToolUseEnd as Nt,onSdkToolUseStart as jt}from"../services/sdk-tool-file-change-recorder.js";import{bridgeEventBuffer as We,sendOutput as J,sendQuestionRequest as Bt,sendToolAuthRequest as Ft,sendStatus as E}from"../services/session-output.js";import{findPersistedSessionByAgentId as vt,removePersistedSession as q,savePersistedSessions as Kt,updatePersistedSessionAutoCommands as Ht,updatePersistedSessionRuntimeState as qt,upsertPersistedSession as zt}from"../services/terminal-persistence.js";import{getInstanceAiConfigDebugLogger as Wt}from"../utils/instance-ai-config-debug-logger.js";import{logger as f}from"../utils/logger.js";const S=yt();function Ge(e){const n=e.header("X-Runtime-Token");return n&&n.trim()?n.trim():(e.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||void 0}const g=new Map,Gt=45e3,se=new Map;function Xt(e){if(se.has(e))return;const n=setInterval(()=>{const t=g.get(e);if(!t){M(e);return}const r=t.currentRuntimeStatus;if(r!=="thinking"&&r!=="tool_using"&&r!=="compacting"){M(e);return}E(t.agentId,e,r,void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl}).catch(()=>{})},Gt);se.set(e,n)}function M(e){const n=se.get(e);n&&(clearInterval(n),se.delete(e))}const Xe=4e3,Yt=200,Jt=2e3,Ye=24e3,Je=200,Ve=8e3;function Vt(e){if(!Array.isArray(e)||e.length===0)return{snapshot:"",truncated:!1};const n=[];let t=null,r=[];const s=()=>{if(t===null)return;const u=r.join("").trim();if(r=[],!u){t=null;return}const d=t==="user"?"\u7528\u6237":t==="assistant"?"\u52A9\u624B":t;n.push(`\u3010${d}\u3011${ie(u,Jt)}`),t=null};for(const u of e){const d=String(u?.role||"").trim();if(!d||d==="system")continue;if(d==="tool_use"||d==="tool_result"){s();const m=String(u.toolName||"").trim()||"\u672A\u77E5\u5DE5\u5177";if(Qt(m))continue;if(d==="tool_use"){const p=en(String(u.content||""));n.push(`\u3010\u5DE5\u5177\u8C03\u7528\u3011${m}${p?` ${p}`:""}`)}else{const p=ie(String(u.content||"").trim(),Yt);n.push(`\u3010\u5DE5\u5177\u7ED3\u679C\u3011${m}${u.isError?"\uFF08\u5931\u8D25\uFF09":""}${p?`\uFF1A${p}`:""}`)}continue}const l=String(u.content||"");l.trim()&&(t===d||(s(),t=d),r.push(l))}if(s(),n.length===0)return{snapshot:"",truncated:!1};const o=n.join(`
|
|
2
|
+
`);if(o.length<=Ye)return{snapshot:o,truncated:!1};const i=Ye-Ve,a=o.slice(0,Ve),c=o.slice(o.length-i);return{snapshot:`${a}
|
|
2
3
|
|
|
3
|
-
\
|
|
4
|
-
`;function je(e){if(e==null||typeof e!="object"||Array.isArray(e))return;const n=e,t={};return typeof n.model=="string"&&n.model.trim()&&(t.model=n.model.trim()),typeof n.baseURL=="string"&&n.baseURL.trim()&&(t.baseURL=n.baseURL.trim()),typeof n.apiKey=="string"&&n.apiKey.trim()&&(t.apiKey=n.apiKey.trim()),typeof n.effort=="string"&&n.effort.trim()&&(t.effort=n.effort.trim()),t}const Pt=`
|
|
4
|
+
...\uFF08\u6B64\u5904\u7701\u7565\u4E2D\u6BB5 ${o.length-a.length-c.length} \u5B57\u7B26\u5386\u53F2\uFF09...
|
|
5
5
|
|
|
6
|
-
\
|
|
7
|
-
|
|
8
|
-
${d.content}`);i.push(`\u3010\u77ED\u671F\u8BB0\u5FC6\u3011
|
|
6
|
+
${c}`,truncated:!0}}function ie(e,n){const t=String(e??"");return t.length<=n?t:`${t.slice(0,n)}...\uFF08\u622A\u65AD ${t.length-n} \u5B57\u7B26\uFF09`}function Qt(e){const n=e.toLowerCase();return n.includes("poll_message")||n.includes("get_message")||n.includes("await_complete")}function Zt(e){if(typeof e!="string"||!e.trim())return Array.isArray(e)&&e.length>0?e:void 0;try{const n=JSON.parse(e);if(!Array.isArray(n)||n.length===0)return;const t=new Set(["system","user","assistant","tool"]),r=1e6,o=n.filter(i=>!!i&&typeof i=="object"&&t.has(String(i.role))).filter(i=>JSON.stringify(i).length<=r).slice(0,5e3);return o.length>0?o:void 0}catch{return}}function en(e){const n=String(e??"").trim();if(!n)return"";let t;try{const s=JSON.parse(n);if(!s||typeof s!="object"||Array.isArray(s))return"";t=s}catch{return ie(n,Je)}const r=[];for(const s of["file_path","path","filePath","pattern","query","command","cmd","url"]){const o=t[s];if(typeof o=="string"&&o.trim()&&r.push(`${s}=${o.trim()}`),r.length>=3)break}if(r.length===0){const s=Object.keys(t).slice(0,5);return s.length>0?`(${s.join(", ")})`:""}return ie(r.join(" "),Je)}function Qe(e){if(e==null||typeof e!="object"||Array.isArray(e))return;const n=e,t={};return typeof n.model=="string"&&n.model.trim()&&(t.model=n.model.trim()),typeof n.baseURL=="string"&&n.baseURL.trim()&&(t.baseURL=n.baseURL.trim()),typeof n.apiKey=="string"&&n.apiKey.trim()&&(t.apiKey=n.apiKey.trim()),typeof n.effort=="string"&&n.effort.trim()&&(t.effort=n.effort.trim()),t}const z=new Set;async function tn(e,n){const t=[],r=[],s=j.join(e,".agentswork","memory");try{const c=(await v.readdir(s)).filter(d=>d.endsWith(".json")),u=await Promise.all(c.map(async d=>{try{const l=await v.readFile(j.join(s,d),"utf-8");return JSON.parse(l)}catch{return f.warn("[loadAgentStartupMemories] Failed to parse memory file: %s",j.join(s,d)),null}}));for(const d of u)if(d?.by_uri)for(const l of Object.values(d.by_uri)){const m=l.memory_type||"memory",p=(l.content||"").trim();p&&(m==="recently_memory"?t.push({title:l.title,content:p,uri:l.uri||""}):m==="agent_memory"&&r.push({title:l.title,content:p,uri:l.uri||""}))}}catch{f.debug("[loadAgentStartupMemories] \u65E0\u6CD5\u8BFB\u53D6\u8BB0\u5FC6\u76EE\u5F55: %s",s)}if(t.length===0&&r.length===0&&n?.schedulerBaseUrl&&n?.runtimeAccessToken&&n?.agentId){const a=`${n.schedulerBaseUrl.replace(/\/+$/,"")}/mcp/call`,c={"Content-Type":"application/json","X-Runtime-Token":n.runtimeAccessToken,Authorization:`Bearer ${n.runtimeAccessToken}`},u=["recently_memory","agent_memory"],d=await Promise.allSettled(u.map(l=>fetch(a,{method:"POST",headers:c,body:JSON.stringify({tool:"list_memories",arguments:{agentId:n.agentId,memory_type:l}})}).then(m=>{if(!m.ok)throw new Error(`Server returned ${m.status}`);return m.json()})));for(let l=0;l<d.length;l++){const m=d[l];if(m.status!=="fulfilled")continue;const p=m.value;if(!Array.isArray(p))continue;const b=u[l]==="recently_memory"?t:r;for(const y of p){const h=(y.content||"").trim();h&&b.push({title:y.title,content:h,uri:y.uri||""})}}(t.length>0||r.length>0)&&f.info(`[loadAgentStartupMemories] Loaded ${t.length} task(s) and ${r.length} memory(s) from server for ${n.agentId}`)}const o=10;t.sort((a,c)=>c.uri.localeCompare(a.uri)),r.sort((a,c)=>c.uri.localeCompare(a.uri));const i=[];if(t.length>0){const c=t.slice(0,o).map((u,d)=>`${u.title?`\u3010${u.title}\u3011`:`\u6761\u76EE ${d+1}`}
|
|
7
|
+
${u.content}`);i.push(`\u3010\u77ED\u671F\u8BB0\u5FC6\u3011
|
|
9
8
|
${c.join(`
|
|
10
9
|
|
|
11
|
-
`)}`),t.length>
|
|
12
|
-
${
|
|
10
|
+
`)}`),t.length>o&&i.push(`... \u53CA\u53E6\u5916 ${t.length-o} \u6761\u77ED\u671F\u8BB0\u5FC6`)}if(r.length>0){const c=r.slice(0,o).map(u=>{const d=u.title?`\u3010${u.title}\u3011`:"";return d?`${d}
|
|
11
|
+
${u.content}`:u.content});i.push(`\u3010agent\u8BA4\u77E5\u3011
|
|
13
12
|
${c.join(`
|
|
14
13
|
|
|
15
|
-
`)}`),r.length>
|
|
14
|
+
`)}`),r.length>o&&i.push(`... \u53CA\u53E6\u5916 ${r.length-o} \u6761 agent \u8BA4\u77E5`)}if(i.length!==0)return i.join(`
|
|
16
15
|
|
|
17
|
-
`)}function
|
|
16
|
+
`)}function nn(e,n){return e!=="acode"?{supported:!1,statusCode:400,error:"context reset without restart is only supported by ACode"}:n?{supported:!0}:{supported:!1,statusCode:500,error:"ACode adapter does not expose resetContext"}}function rn(e){return e!=="acode"}function on(e){const n=typeof e=="object"&&e!==null&&"suppressStatus"in e&&e.suppressStatus===!0,t=typeof e=="object"&&e!==null&&"reason"in e&&typeof e.reason=="string"&&e.reason.trim()?e.reason.trim():void 0;return{statusNotified:!n,reason:t}}function ae(e){const n=e?.usage;if(!n)return;const t=Number.isFinite(n.inputTokens)?n.inputTokens:0,r=Number.isFinite(n.outputTokens)?n.outputTokens:0;if(t<=0&&r<=0&&!n.contextLimit&&!n.maxOutput&&!n.inputLimit&&!n.compactionThreshold)return;const s={inputTokens:t,outputTokens:r,...n.contextLimit?{contextLimit:n.contextLimit}:{},...n.maxOutput?{maxOutput:n.maxOutput}:{},...n.inputLimit?{inputLimit:n.inputLimit}:{},...n.compactionThreshold?{compactionThreshold:n.compactionThreshold}:{},...n.cacheHitTokens!==void 0?{cacheHitTokens:n.cacheHitTokens}:{},...n.cacheMissTokens!==void 0?{cacheMissTokens:n.cacheMissTokens}:{}};return process.env.ACODE_TOKEN_DEBUG==="1"&&(s.inputTokens>0||s.outputTokens>0||s.cacheHitTokens!==void 0||s.cacheMissTokens!==void 0)&&f.info(`[TokenDebug][Terminal] resolveStatusChangeUsage: input=${s.inputTokens} output=${s.outputTokens} cacheHit=${s.cacheHitTokens??"(none)"} cacheMiss=${s.cacheMissTokens??"(none)"} actionType=${e?.actionType??"(none)"}`),s}function sn(e,n){const t=String(e||"").trim().toLowerCase(),r=String(n?.actionType||"").trim().toLowerCase();return t==="tool_using"&&r==="idle"?n?{status:"waiting_input",actionInfo:n}:{status:"waiting_input"}:n?{status:e,actionInfo:n}:{status:e}}function an(e){return e.restoredActionInfo?.actionType==="idle"||e.currentRuntimeActionType==="idle"&&e.shouldPreservePrevAction||e.status==="waiting_input"&&!e.actionInfo?.actionType}const V=new Map,cn="utf-8",Ze="utf-8",et=300,tt=6e4;function Q(e){return String(e).padStart(2,"0")}function un(e,n=new Date){const t=n.getFullYear(),r=Q(n.getMonth()+1),s=Q(n.getDate()),o=Q(n.getHours()),i=Q(n.getMinutes()),a=`${t}${r}${s}-${o}${i}${Q(n.getSeconds())}-${String(n.getMilliseconds()).padStart(3,"0")}`;return j.join(Me(),"cmd-dist",e,`${t}-${r}-${s}`,o,i,`${a}-cmd.out`)}function dn(e){if(!e)return 0;const n=e.replace(/\r\n/g,`
|
|
18
17
|
`).replace(/\r/g,`
|
|
19
18
|
`),t=n.endsWith(`
|
|
20
19
|
`)?n.slice(0,-1):n;return t?t.split(`
|
|
21
|
-
`).length:1}function
|
|
20
|
+
`).length:1}function ln(e,n=et){return`\r
|
|
22
21
|
[ACode] \u547D\u4EE4\u8F93\u51FA\u8D85\u8FC7 ${n} \u884C\uFF0C\u5B8C\u6574\u8F93\u51FA\u5DF2\u5199\u5165: ${e}\r
|
|
23
22
|
[ACode] Agent \u53EF\u81EA\u884C\u8BFB\u53D6\u8BE5\u6587\u4EF6\uFF0C\u6216\u5728\u8BE5\u6587\u4EF6\u4E2D\u641C\u7D22\u9700\u8981\u7684\u5185\u5BB9\u3002\r
|
|
24
|
-
`}function
|
|
23
|
+
`}function fn(e=tt){return`\r
|
|
25
24
|
[ACode] \u547D\u4EE4\u8D85\u8FC7 ${Math.round(e/1e3)} \u79D2\u6CA1\u6709\u65B0\u7684\u8F93\u51FA\uFF0C\u5DF2\u505C\u6B62\u6267\u884C\u5E76\u4FDD\u7559\u6B64\u524D\u8F93\u51FA\u3002\r
|
|
26
|
-
`}async function
|
|
27
|
-
`).trim()}function
|
|
28
|
-
`),!0;const
|
|
29
|
-
`),!0):(
|
|
30
|
-
`),!0)}catch(
|
|
31
|
-
`),!0}}async function
|
|
32
|
-
`),
|
|
33
|
-
`),
|
|
34
|
-
[ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${
|
|
35
|
-
`)});return}
|
|
36
|
-
[Terminal Error] ${
|
|
37
|
-
`)}),a.on("close",(
|
|
38
|
-
[ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${
|
|
39
|
-
`)}),
|
|
40
|
-
[exit ${
|
|
41
|
-
`)
|
|
42
|
-
[signal ${
|
|
43
|
-
`),
|
|
44
|
-
...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function
|
|
25
|
+
`}async function nt(e){const n=e.outputPath||un(e.agentId,e.startedAt);return e.outputPath=n,await v.mkdir(j.dirname(n),{recursive:!0}),await v.writeFile(n,e.chunks.join(""),"utf-8"),n}function mn(e){return String(e??"").replace(/\r/g,`
|
|
26
|
+
`).trim()}function pn(e=process.platform,n=process.env){const t=n.AWS_TERMINAL_OUTPUT_ENCODING?.trim();return t||(e==="win32"?cn:Ze)}function rt(e=pn()){if(e!=="utf-8")try{return new re(e,{fatal:!1})}catch{return new re(Ze,{fatal:!1})}return gn()}function gn(){let e=null,n=null,t=null;const r=[];function s(o){try{return new re(o,{fatal:!1})}catch{return new re("utf-8",{fatal:!1})}}return{decode(o,i){if(o!=null&&r.push(o instanceof ArrayBuffer?Buffer.from(o):Buffer.isBuffer(o)?o:Buffer.from(o.buffer,o.byteOffset,o.byteLength)),t==="gb18030")return n||(n=s("gb18030")),n.decode(o,i);e||(e=s("utf-8"));const a=e.decode(o,i);if(t===null&&a.includes("\uFFFD")){t="gb18030",n=s("gb18030");const c=Buffer.concat(r);return n.decode(c)}return t===null&&!i?.stream&&(t="utf-8"),a}}}function ce(e,n,t=!1){return t?e.decode():!n||n.length===0?"":e.decode(n,{stream:!0})}function yn(e){const n=e.trim().match(/^cd(?:\s+(.*))?$/i);if(!n)return;const t=n[1]?.trim();if(!t)return null;const r=t.replace(/^\/d\s+/i,"").trim();return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function hn(e){const n=V.get(e.sessionId);if(n)return n;const t={currentDirectory:e.workspacePath,runningProcess:null};return V.set(e.sessionId,t),t}function ot(e){for(const n of g.values())if(n.agentId===e)return n}async function In(e){const n=_.get(e.providerId||"claude-code"),t=ue(n.getSessionStatus(e.sessionId),e.currentRuntimeStatus,e.currentRuntimeActionType);return{sessionId:e.sessionId,status:t,runtimeStatus:t,runtimeActionType:e.currentRuntimeActionType,runtimeActionLabel:e.currentRuntimeActionLabel,runtimeActionDetail:e.currentRuntimeActionDetail,agentId:e.agentId,workspacePath:e.workspacePath,command:e.config.command,mode:"sdk",providerSessionId:n.getProviderSessionId(e.sessionId),reused:!0}}function ue(e,n,t){const r=String(e||"").trim();if(r){const o=String(n||"").trim(),i=String(t||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&o.toLowerCase()==="waiting_input"&&i==="idle"?o:r}return String(n||"").trim()||"running"}async function Sn(e,n=xt){return e.pid?await n(e.pid)?dt(e.command)==="acode"?{reusable:!1,reason:"in-process-provider"}:{reusable:!0,reason:"active-pid"}:{reusable:!1,reason:"dead-pid"}:{reusable:!1,reason:"missing-pid"}}function Er(e){const n=ot(e);if(!n)f.info(`[cleanupSdkSessionByAgentId] No active SDK session found for agentId=${e}, cleaning residual state anyway`);else{const t=n.sessionId;return f.info(`[cleanupSdkSessionByAgentId] Cleaning up SDK session for agentId=${e}, sessionId=${t}`),M(t),g.delete(t),H(t),de(t),q(t).catch(r=>{f.warn(`[cleanupSdkSessionByAgentId] Failed to remove persisted session for agentId=${e}: ${r}`)}),t}z.has(e)&&(z.delete(e),f.info(`[cleanupSdkSessionByAgentId] Released startingAgents lock for agentId=${e}`))}function de(e){const n=V.get(e);if(!n?.runningProcess){V.delete(e);return}try{n.runningProcess.kill()}catch{}finally{n.runningProcess=null,V.delete(e)}}function C(e,n){n&&(e.seq+=1,J(e.agentId,n,e.sessionId,e.seq,void 0,{runtimeAccessToken:e.runtimeAccessToken,schedulerBaseUrl:e.schedulerBaseUrl}).catch(()=>{}))}function Ce(e){return`\x1B[36m${e}>\x1B[0m `}function An(e,n){return n==="~"?gt.homedir():j.resolve(e,n)}async function Tn(e,n,t){const r=yn(t);if(r===void 0)return!1;if(r===null)return C(e,`${n.currentDirectory}\r
|
|
27
|
+
`),!0;const s=An(n.currentDirectory,r);try{return(await v.stat(s)).isDirectory()?(n.currentDirectory=s,C(e,`${n.currentDirectory}\r
|
|
28
|
+
`),!0):(C(e,`cd: not a directory: ${s}\r
|
|
29
|
+
`),!0)}catch(o){const i=o instanceof Error?o.message:String(o);return C(e,`cd: ${i}\r
|
|
30
|
+
`),!0}}async function _n(e,n){const t=g.get(e);if(!t)throw new Error("SDK session not found");const r=mn(n),s=hn(t);if(!r)return{started:!1,cwd:s.currentDirectory};if(s.runningProcess)throw new Error("A terminal command is already running for this session");const o=K(r);if(C(t,`${Ce(s.currentDirectory)}${o}\r
|
|
31
|
+
`),Oe(r))return C(t,`[Terminal Warning] \u68C0\u6D4B\u5230\u526A\u8D34\u677F\u4E34\u65F6 paste \u6587\u4EF6\u8DEF\u5F84\uFF0C\u5DF2\u8DF3\u8FC7\u6267\u884C\u3002\u8BF7\u7C98\u8D34\u6587\u4EF6\u5185\u5BB9\u6216\u4F7F\u7528\u663E\u5F0F\u8BFB\u53D6\u547D\u4EE4\u3002\r
|
|
32
|
+
`),C(t,Ce(s.currentDirectory)),{started:!1,cwd:s.currentDirectory};if(await Tn(t,s,r))return{started:!1,cwd:s.currentDirectory};await E(t.agentId,e,"tool_using",{actionType:"bash",actionLabel:"\u7EC8\u7AEF\u547D\u4EE4",actionDetail:o},void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl});const a=pt(r,{cwd:s.currentDirectory,shell:!0,env:st(t.agentId,t.workspacePath,process.env,t.config.envOverrides)});s.runningProcess=a;const c=rt(),u=rt(),d=t.providerId==="acode",l={agentId:t.agentId,startedAt:new Date,chunks:[],spilled:!1};let m;const p=()=>{m&&(clearTimeout(m),m=void 0)},b=()=>{p(),m=setTimeout(()=>{s.runningProcess===a&&(C(t,fn()),a.kill())},tt)},y=(h,$=!0)=>{if(h&&(d&&l.chunks.push(h),d&&$&&b(),!(d&&l.spilled))){if(d&&dn(l.chunks.join(""))>et){l.spilled=!0,nt(l).then(R=>{C(t,ln(R))}).catch(R=>{const D=R instanceof Error?R.message:String(R);C(t,`\r
|
|
33
|
+
[ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${D}\r
|
|
34
|
+
`)});return}C(t,h)}};return d&&b(),a.stdout.on("data",h=>{y(ce(c,h))}),a.stderr.on("data",h=>{y(ce(u,h))}),a.on("error",h=>{C(t,`\r
|
|
35
|
+
[Terminal Error] ${h.message}\r
|
|
36
|
+
`)}),a.on("close",(h,$)=>{p(),s.runningProcess=null,y(ce(c,void 0,!0),!1),y(ce(u,void 0,!0),!1),l.spilled&&nt(l).catch(R=>{const D=R instanceof Error?R.message:String(R);C(t,`\r
|
|
37
|
+
[ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${D}\r
|
|
38
|
+
`)}),h&&h!==0?C(t,`\r
|
|
39
|
+
[exit ${h}]\r
|
|
40
|
+
`):$&&C(t,`\r
|
|
41
|
+
[signal ${$}]\r
|
|
42
|
+
`),C(t,Ce(s.currentDirectory)),E(t.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl})}),{started:!0,cwd:s.currentDirectory}}function st(e,n,t,r,s){const o={};for(const[i,a]of Object.entries(t))a!==void 0&&(o[i]=a);if(n&&(o.AWS_WORKSPACE_PATH=String(n)),s&&String(s).trim()&&(o.AWS_PROJECT_ROOT=String(s).trim()),r)for(const[i,a]of Object.entries(r)){const c=i.trim();if(!c||a===void 0||a===null)continue;const u=String(a).trim();u&&(o[c]=u)}return o.AWS_AGENT_ID=String(e),o.AWS_MCP_CLAIM_LAUNCH_BINDING="true",o.AWS_RUNTIME_BRIDGE_BASE_URL=`http://127.0.0.1:${At()}`,String(o.ACODE_HOME||"").trim()||(o.ACODE_HOME=Me()),T(e,xe)!=="disabled"&&(o.AWS_LAUNCH_CONFIG_TOOLS=T(e,xe)),T(e,Ne)!=="disabled"&&(o.AWS_HIRE_TOOLS=T(e,Ne)),T(e,je)!=="disabled"&&(o.AWS_PENCIL_TOOLS=T(e,je)),T(e,Be)!=="disabled"&&(o.AWS_DRAW_TOOLS=T(e,Be)),T(e,Fe)!=="disabled"&&(o.AWS_OFFICE_TOOLS=T(e,Fe)),T(e,ve)!=="disabled"&&(o.AWS_COLLABORATION_TASK_TOOLS=T(e,ve)),T(e,Ke)!=="disabled"&&(o.AWS_COLLABORATION_MEETING_TOOLS=T(e,Ke)),T(e,He)!=="disabled"&&(o.AWS_COLLABORATION_DEBUG_TOOLS=T(e,He)),T(e,qe)!=="disabled"&&(o.AWS_COLLABORATION_FILE_HISTORY_TOOLS=T(e,qe)),T(e,ze)!=="disabled"&&(o.AWS_EMAIL_TOOLS=T(e,ze)),o}function bn(e){const n=e.trim(),t=n[0],r=n[n.length-1];return(t==='"'||t==="'")&&t===r?n.slice(1,-1):n}async function kn(e){const n=String(e);if(!Oe(n))return n;const t=bn(n);return j.isAbsolute(t)?v.readFile(t,"utf-8"):n}function it(e,n){const t={};for(const s of[e?.env,n])if(s)for(const[o,i]of Object.entries(s)){const a=o.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(t[a]=c)}const r=t.ANTHROPIC_MODEL?.trim()||t.CODEX_MODEL?.trim()||void 0;return{envOverrides:t,model:r}}async function Cn(){try{return await _t().readClaudeCodeConfig()}catch(e){return console.warn(`[Runtime] Failed to read saved ClaudeCode AI config: ${e.message}`),{}}}function $n(e){if(e==null)return;const t=(typeof e=="string"?e:JSON.stringify(e,null,2)).trim();if(t)return t.length<=Xe?t:`${t.slice(0,Xe)}
|
|
43
|
+
...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function wn(e){try{const n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return["directMessages","groupMessages","messages"].some(t=>Array.isArray(n[t])&&n[t].length>0)}catch{}return e.trim().length>0}function En(e){if(e.data.actionType==="mcp")return!0;const t=String(e.data.toolName||"").toLowerCase();return t.startsWith("mcp__")||t.includes("-mcp__")||t.includes("mcp_")}function Rn(e){if(e.type!=="tool_use_end")return;const n=$n(e.data.toolResult??e.data.actionResult);if(!n)return;const t=be(e.data.toolName,e.data.toolInput),r=e.data.actionType||t.actionType;if(r==="idle"){const s=String(e.data.rawToolName||e.data.toolName||"").toLowerCase();if((s.includes("poll_message")||s.includes("get_message"))&&!wn(n))return}return r==="mcp"&&En(e)?{actionType:"mcp",actionLabel:"MCP\u8FD4\u56DE",actionDetail:e.data.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:n,...e.data.parentId?{parentId:e.data.parentId}:{}}:{actionType:r,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:e.data.actionDetail||t.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:n,...e.data.parentId?{parentId:e.data.parentId}:{}}}function Dn(e){if(e.type==="ai_request"){const n=e.data.model?` ${e.data.model}`:"",t=e.data.lastUserMessagePreview?`\uFF1A${e.data.lastUserMessagePreview}`:"";return`\r
|
|
45
44
|
[ACode] \u6B63\u5728\u8BF7\u6C42\u6A21\u578B${n}${t}\r
|
|
46
45
|
`}if(e.type==="text_delta"||e.type==="thinking"||e.type==="command_output")return e.data.text||void 0;if(e.type==="error")return e.data.text?`\r
|
|
47
46
|
[SDK Error] ${e.data.text}\r
|
|
48
|
-
`:void 0}function
|
|
49
|
-
...\uFF08\u8F93\u5165\u53C2\u6570\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:n}catch{return}}function yn(e){const n=[e.model?`\u6A21\u578B: ${e.model}`:void 0,e.endpoint||e.requestUrl?`\u63A5\u53E3: ${e.endpoint||e.requestUrl}`:void 0,e.requestMethod?`\u65B9\u6CD5: ${e.requestMethod}`:void 0,typeof e.stream=="boolean"?`\u6D41\u5F0F: ${e.stream?"\u662F":"\u5426"}`:void 0,typeof e.messageCount=="number"?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${e.messageCount}`:void 0,typeof e.toolCount=="number"?`\u53EF\u7528\u5DE5\u5177: ${e.toolCount}`:void 0,e.lastUserMessagePreview?`\u6700\u540E\u8BF7\u6C42: ${e.lastUserMessagePreview}`:void 0].filter(i=>!!i),t=hn(e.requestHeaders),r=n.join(`
|
|
50
|
-
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",o=t.length>0?`${Pt}${t.join(`
|
|
51
|
-
`)}`:"",s=e.requestBody?`${Rt}${e.requestBody}`:"";return`${r}${o}${s}`}function hn(e){return e?Object.entries(e).map(([n,t])=>`${n}: ${t}`).filter(n=>n.trim().length>0):[]}function In(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function Sn(e){for(const n of["estimatedContextTokens","contextTokens","context_tokens","contextUsedTokens","context_used_tokens"]){const t=e[n],r=Number(t);if(Number.isFinite(r)&&r>0)return r}}function An(e,n){if(!In(e,n)){if(e.type==="ai_request"){const t=Sn(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:yn(e.data),...t!==void 0?{usage:{inputTokens:t,outputTokens:0}}:{}}}}if(e.type==="background_command_completed")return{status:"tool_result",actionInfo:{actionType:"background_command",actionLabel:"\u540E\u53F0\u547D\u4EE4",actionDetail:"background_command_completed"}};if(e.type==="thinking"||e.type==="text_delta")return{status:"thinking"};if(e.type==="tool_use_start"){const t=he(e.data.toolName,e.data.toolInput),r=We(e,t),o=gn(e.data.toolInput);return e.data.actionType==="idle"||t.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:n||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}}}}const U=new Map,ce=new Map,ue=new Map,J=new Map,Tn=20,kn=500,bn=3e4;async function de(e,n=bn,t=2){for(let r=0;r<=t;r++){const o=new AbortController;let s;try{const i=e(o.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{s=setTimeout(()=>{o.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),s&&clearTimeout(s);return}catch(i){s&&clearTimeout(s);const a=i instanceof Error?i.message:String(i);if(r<t){const c=1e3*(r+1);m.warn(`sendOutput attempt ${r+1}/${t+1} failed (${a}), retrying in ${c}ms...`),await new Promise(d=>setTimeout(d,c));continue}m.warn(`sendOutput failed after ${t+1} attempts (${a}), giving up to unblock serial queue`)}}}function le(e,n){const t=n?`${e}:${n}`:void 0;let r,o;if(t)r=J.get(t),o=t;else{const g=[];for(const[T,h]of J)T.startsWith(e+":")&&h.buffer&&g.push(h.sourceEventType);for(const T of g)le(e,T);return}if(!r||!r.buffer)return;r.timer=null;const s=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",o&&J.delete(o);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},f=(U.get(e)??Promise.resolve()).then(()=>de(g=>Q(a.agentId,s,e,i,d,u,g)),()=>de(g=>Q(a.agentId,s,e,i,d,u,g)));U.set(e,f),f.finally(()=>{U.get(e)===f&&U.delete(e)})}function wn(e,n){const t=on(e);if(!t)return;n.seq+=1;const r=n.seq,o=sn(e),s={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&t.length<Tn){const c=`${e.sessionId}:${e.type}`;let d=J.get(c);if(d||(d={buffer:"",seq:0,timer:null,entry:n,sourceEventType:e.type}),d.buffer+=t,d.seq=r,d.entry=n,!d.timer){const u=e.sessionId,l=e.type;d.timer=setTimeout(()=>le(u,l),kn)}J.set(c,d);return}le(e.sessionId);const a=(U.get(e.sessionId)??Promise.resolve()).then(()=>de(c=>Q(n.agentId,t,e.sessionId,r,o,s,c)),()=>de(c=>Q(n.agentId,t,e.sessionId,r,o,s,c)));U.set(e.sessionId,a),a.finally(()=>{U.get(e.sessionId)===a&&U.delete(e.sessionId)})}function Ge(e){return rt(e)}let Qe=!1;function _n(){Qe||(nt(b,Cn),ct(),Qe=!0)}function Cn(e,n){e.on("event",t=>{const r=p.get(t.sessionId);if(r){if(t.type==="tool_use_start"?It(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&ht(t,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),m.info(`[${n.displayName} Adapter] Event: ${t.type} for session ${t.sessionId}`),!(t.type==="thinking"||t.type==="text_delta"||t.type==="tool_use_start"||t.type==="context_compaction"||t.type==="ai_request")){t.type==="runtime_capabilities"&&t.data.actionDetail&&(r.cachedCapabilitiesActionDetail=t.data.actionDetail);const i=An(t,r.currentRuntimeStatus);i&&C(r.agentId,t.sessionId,i.status,i.actionInfo,oe(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.timestamp?new Date(t.timestamp).getTime():void 0,t.type)}wn(t,r);const s=rn(t);if(s){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=t.timestamp?new Date(t.timestamp).getTime():void 0,c=String(t.data?.toolName||"").toLowerCase()==="browser_launch",d=t.type==="tool_use_end"&&String(t.data?.rawToolName||t.data?.toolName||"").toLowerCase().replace(/[_-]/g,"").includes("todowrite");c?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,3e3*(l+1)))}})().catch(u=>console.warn("[Runtime] browser_launch sendStatus retry exhausted:",u)):d?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,1e3*(l+1)))}})().catch(u=>console.warn("[Runtime] todo_write sendStatus retry exhausted:",u)):C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)}}}),e.on("status-change",(t,r,o)=>{const s=p.get(t);if(s){le(t),r==="thinking"||r==="tool_using"||r==="compacting"?Dt(t):L(t);const i=Ut(r,o);s.currentRuntimeStatus=i.status;const a=s.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(s.currentRuntimeActionType==="idle"||s.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(s.currentRuntimeActionType=i.actionInfo?.actionType,s.currentRuntimeActionLabel=i.actionInfo?.actionLabel,s.currentRuntimeActionDetail=i.actionInfo?.actionDetail,s.currentRuntimeActionInput=i.actionInfo?.actionInput),m.info(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${s.agentId}`,i.actionInfo||""),wt(t,{runtimeStatus:i.status,runtimeActionType:s.currentRuntimeActionType,runtimeActionLabel:s.currentRuntimeActionLabel,runtimeActionDetail:s.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:s.currentRuntimeActionType?{actionType:s.currentRuntimeActionType,actionLabel:s.currentRuntimeActionLabel??"",actionDetail:s.currentRuntimeActionDetail,actionInput:s.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const g=(ce.get(t)??Promise.resolve()).then(async()=>{for(let h=0;h<=2;h++){if(await C(s.agentId,t,i.status,l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;h<2&&(m.warn(`[${n.displayName}] compaction sendStatus attempt ${h+1} failed (HTTP), retrying in ${1e3*(h+1)}ms...`),await new Promise(_=>setTimeout(_,1e3*(h+1))))}m.warn(`[${n.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(T=>{m.warn(`[${n.displayName}] compaction status chain error:`,T)});ce.set(t,g),g.finally(()=>{ce.get(t)===g&&ce.delete(t)})}else{const f=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||s.currentRuntimeActionType==="idle"&&u){const h=(ue.get(t)??Promise.resolve()).then(async()=>{for(let _=0;_<=2;_++){if(await C(s.agentId,t,i.status,f?void 0:l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;_<2&&await new Promise(M=>setTimeout(M,1e3*(_+1)))}m.warn(`[${n.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(y=>{m.warn(`[${n.displayName}] idle status chain error:`,y)});ue.set(t,h),h.finally(()=>{ue.get(t)===h&&ue.delete(t)})}else C(s.agentId,t,i.status,f?void 0:l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}if(i.status==="waiting_input"&&s.cachedCapabilitiesActionDetail){const f=s.cachedCapabilitiesActionDetail;s.cachedCapabilitiesActionDetail=void 0,m.info(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${s.agentId} (session stabilized to waiting_input)`),C(s.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:f},void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=p.get(t.sessionId);r&&(m.info(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),St(r.agentId,t.sessionId,Array.isArray(t.questions)?t.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.toolCallId))}),e.on("tool-permission-request",t=>{const r=p.get(t.sessionId);r&&t.requestId&&(m.info(`[${n.displayName} Adapter] Tool permission request (${t.capability}) for agent ${r.agentId}`),At(r.agentId,t.sessionId,{requestId:t.requestId,capability:t.capability,...t.detail||{}},{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}))}),e.on("permission-request",t=>{const r=p.get(t.sessionId);if(r){m.info(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const o=t.toolInput?F(JSON.stringify(t.toolInput).slice(0,400)):void 0;C(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:o||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}S.post("/start",I,async(e,n)=>{const{agentId:t,workspacePath:r,mode:o="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const s=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(xe(e))||void 0;ft({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||s,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:s}),e.body?.runtimeFeatures!==null&&e.body?.runtimeFeatures!==void 0&&(dt(String(t),e.body.runtimeFeatures),m.info(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(mt(String(t)))}`)),e.body?.capabilities!==void 0&<(String(t),e.body.capabilities),e.body?.envVars!==null&&e.body?.envVars!==void 0&&typeof e.body.envVars=="object"&&(pt(e.body.envVars),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u9762\u677F\u73AF\u5883\u53D8\u91CF: ${Object.keys(e.body.envVars).length} \u9879 \u2192 \u684C\u9762\u5DE5\u5177\u5B50\u8FDB\u7A0B`)),e.body?.changeCacheRetentionDays!==void 0&&(it(e.body.changeCacheRetentionDays),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u53D8\u66F4\u7F13\u5B58\u4FDD\u7559\u5929\u6570: ${e.body.changeCacheRetentionDays??"\u4E0D\u6E05\u7406"}`)),o&&o!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${o}" requested for agent ${t}; starting SDK session instead.`),await $n(e,n)});async function $n(e,n){const{agentId:t,workspacePath:r,command:o,autoAccept:s=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:f,envOverrides:g,idleInputAutoCommand:T,nonInputAutoCommand:h,model:y,instanceAiConfig:_,subAgentModel:$,subAgentEffort:M,scopeKey:Te,browserAllowPrivate:ke}=e.body||{},W=Ct();W.log({level:"info",category:"launch",message:"startSdkSession: \u6536\u5230\u542F\u52A8\u8BF7\u6C42",source:"bridge",agentId:String(t||"").trim()||void 0,details:{reqBodyKeys:Object.keys(e.body||{}),perInstanceAiConfig:_?ne(_):null,perAgentModel:y??null}});let D=null;const A=String(t||"").trim(),me=String(e.body?.runtimeAccessToken||"").trim()||void 0,N=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(xe(e))||void 0;N?m.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${N} (agentId=${A})`):m.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${A})`);try{if(_n(),!A){n.status(400).json({error:"agentId is required"});return}const q=Fe(A);if(q){n.json(await Wt(q));return}const k=await Tt(A);if(k){const R=Xt(k);if(!R.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${A}, sessionId=${k.sessionId}, reason=${R.reason}`),await z(k.sessionId);else{const P=ie(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);n.json({sessionId:k.sessionId,status:P,runtimeStatus:P,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(H.has(A)){n.status(409).json({error:"SDK session is already starting for this agent"});return}H.add(A);const E=Ge(o),Ve=b.get(E);D=tt();const Ye=E==="claude-code"?await Zt():null,Z=ze(E==="claude-code"?Ye:null,g),X=E==="acode"?y?String(y).trim():void 0:(()=>{const R=y?String(y).trim():void 0,P=Z.model?String(Z.model).trim():void 0;return R||P})();W.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:A,sessionId:D??void 0,details:{perAgentModel:y??null,globalModel:Z.model??null,resolvedModel:X??null,providerId:E,note:E==="acode"?"adapter handles full priority":"request > global"}});const fe={...Z.envOverrides};X&&(fe.ANTHROPIC_MODEL=X,fe.CODEX_MODEL=X);let G,pe=l;if(E==="acode"){const R=_||{},P=await ut({apiOverrides:je(R)??void 0,agentId:A,sessionId:D??void 0,runtimeBridgeBaseUrl:N});G=P.instanceConfig.config,pe=P.perInstanceConfigPath,W.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:A,sessionId:D??void 0,details:{sanitizedApiOverrides:(()=>{const O=je(R);return O?ne(O):null})(),resolvedInstanceAiConfig:G?ne(G):null,perInstanceConfigPath:pe,instanceConfigSources:P.instanceConfig.source??null}})}let be=a||void 0,ge,ye,ee;if(E==="acode")if(ge=typeof c=="string"&&c.trim()||void 0,ye=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())ee=u.trim();else{const R=await Et(r,{schedulerBaseUrl:N,runtimeAccessToken:me,agentId:A});R&&(ee=R,m.info(`[startSdkSession] Auto-loaded memories for ACode agent ${A}`))}else if(typeof c=="string"&&c.trim()||typeof d=="string"&&d.trim()||typeof u=="string"&&u.trim()){const P=[c,d,u,a].filter(O=>typeof O=="string"&&O.trim().length>0).map(O=>O.trim());be=P.length>0?P.join(`
|
|
47
|
+
`:void 0}function Pn(e){const n=Mn(e);return{sourceEventType:e.type,logCategory:"acode",...Ln(e),...n?{logLevel:On(e),logMessage:n}:{}}}function On(e){return e.type==="error"?"error":e.type==="command_output"&&e.data.stream==="stderr"?"warn":"info"}function Ln(e){return e.type!=="command_output"?{}:{...typeof e.data.stream=="string"?{stream:e.data.stream}:{},...typeof e.data.sequence=="number"?{sequence:e.data.sequence}:{},...typeof e.data.cwd=="string"?{cwd:e.data.cwd}:{},...typeof e.data.commandFilePath=="string"?{commandFilePath:e.data.commandFilePath}:{},...typeof e.data.commandLineCount=="number"?{commandLineCount:e.data.commandLineCount}:{}}}function Mn(e){if(e.type==="ai_request"){const n=e.data.model||"unknown-model",t=e.data.endpoint?` @ ${e.data.endpoint}`:"",r=typeof e.data.toolCount=="number"?`, tools=${e.data.toolCount}`:"";return`AI request started: ${n}${t}${r}`}if(e.type==="tool_use_start")return at(e,"\u5F00\u59CB");if(e.type==="tool_use_end")return at(e,"\u5B8C\u6210");if(e.type==="command_output")return Nn(e);if(e.type==="turn_complete")return`Turn completed${e.data.finishReason?`, finish=${e.data.finishReason}`:""}`;if(e.type==="session_complete")return`Session completed: exitCode=${e.data.exitCode??0}`;if(e.type==="error")return e.data.text||"ACode runtime error"}const Un=/\x1b\[[0-9;?]*[a-zA-Z]/g;function xn(e){return e.replace(Un,"")}function Nn(e){const n=typeof e.data.stream=="string"?e.data.stream:"mixed",t=typeof e.data.sequence=="number"?` #${e.data.sequence}`:"",r=xn(String(e.data.text||"")).replace(/\s+/g," ").trim(),s=r.length>240?`${r.slice(0,240)}...`:r;return`\u547D\u4EE4\u8F93\u51FA(${n}${t}): ${s||"(empty)"}`}function at(e,n){const t=be(e.data.toolName,e.data.toolInput),r=e.data.actionLabel||t.actionLabel||"\u8C03\u7528\u5DE5\u5177",s=ct(e,t);return s?`${n}${r}: ${s}`:`${n}${r}: ${e.data.actionDetail||e.data.toolName||"tool"}`}function ct(e,n){const t=e.data.toolInput;return n.actionType==="bash"?jn(t)||e.data.actionDetail||n.actionDetail:n.actionType==="read_file"||n.actionType==="edit_file"||n.actionType==="write_file"?Bn(t)||e.data.actionDetail||n.actionDetail:e.data.actionDetail||n.actionDetail}function jn(e){const n=$e(e?.command,e?.cmd);if(n)return n;if(Array.isArray(e?.argv)){const t=e.argv.map(r=>String(r??"").trim()).filter(Boolean).join(" ");return t?K(t):void 0}return $e(e?.args)}function Bn(e){const n=ut(e?.paths);return n.length>0?n.length===1?n[0]:`${n.length}\u4E2A\u6587\u4EF6: ${n.join(", ")}`:$e(e?.file_path,e?.filePath,e?.path,e?.target_file,e?.targetFile)}function $e(...e){for(const n of e){if(typeof n=="string"&&n.trim())return K(n.trim());if(Array.isArray(n)){const t=ut(n)[0];if(t)return t}}}function ut(e){return Array.isArray(e)?e.map(n=>typeof n=="string"?n.trim():"").filter(Boolean).map(n=>K(n)):[]}function Fn(e){if(!(!e||Object.keys(e).length===0))try{const n=K(JSON.stringify(e,null,2));return n.length>8e3?`${n.slice(0,8e3)}
|
|
48
|
+
...\uFF08\u8F93\u5165\u53C2\u6570\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:n}catch{return}}function vn(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function Kn(e,n){if(!vn(e,n)){if(e.type==="background_command_completed")return{status:"tool_result",actionInfo:{actionType:"background_command",actionLabel:"\u540E\u53F0\u547D\u4EE4",actionDetail:"background_command_completed"}};if(e.type==="thinking"||e.type==="text_delta")return{status:"thinking"};if(e.type==="tool_use_start"){const t=be(e.data.toolName,e.data.toolInput),r=ct(e,t),s=Fn(e.data.toolInput);return e.data.actionType==="idle"||t.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:s,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:s,actionId:e.data.actionId||e.data.toolUseId,...e.data.batchId?{parentId:e.data.batchId}:{}}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:n||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}};if(e.type==="tool_batch_start"){const t=e.data.batchId;return t?{status:"tool_result",actionInfo:{actionType:"tool_batch",actionLabel:"\u5E76\u884C\u6267\u884C\u5DE5\u5177",actionDetail:e.data.actionDetail,actionId:t}}:void 0}if(e.type==="tool_batch_metrics"){const t=e.data.batchId;return t?{status:"tool_result",actionInfo:{actionType:"tool_batch",actionLabel:"\u5E76\u884C\u6267\u884C\u5DE5\u5177",actionId:t,batchId:t,...e.data.batchMetrics?{batchMetrics:e.data.batchMetrics}:{}}}:void 0}}}const U=new Map,le=new Map,fe=new Map;async function we(e){const{entry:n,sessionId:t,actionInfo:r,timestamp:s,sourceEventType:o,backoffBaseMs:i,label:a}=e,c={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl},u=3;for(let d=0;d<u;d++){if(await E(n.agentId,t,"tool_result",r,void 0,c,s,o)!==void 0)return;d<u-1&&await new Promise(m=>setTimeout(m,i*(d+1)))}f.warn(`[Runtime] ${a} tool_result sendStatus retry exhausted (result may be lost): agentId=${n.agentId}`)}const Z=new Map,Hn=20,qn=500,zn=3e4;async function me(e,n=zn,t=2){for(let r=0;r<=t;r++){const s=new AbortController;let o;try{const i=e(s.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{o=setTimeout(()=>{s.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),o&&clearTimeout(o);return}catch(i){o&&clearTimeout(o);const a=i instanceof Error?i.message:String(i);if(r<t){const c=1e3*(r+1);f.warn(`sendOutput attempt ${r+1}/${t+1} failed (${a}), retrying in ${c}ms...`),await new Promise(u=>setTimeout(u,c));continue}f.warn(`sendOutput failed after ${t+1} attempts (${a}), giving up to unblock serial queue`)}}}function pe(e,n){const t=n?`${e}:${n}`:void 0;let r,s;if(t)r=Z.get(t),s=t;else{const p=[];for(const[b,y]of Z)b.startsWith(e+":")&&y.buffer&&p.push(y.sourceEventType);for(const b of p)pe(e,b);return}if(!r||!r.buffer)return;r.timer=null;const o=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",s&&Z.delete(s);const u={sourceEventType:c,logCategory:"acode"},d={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},m=(U.get(e)??Promise.resolve()).then(()=>me(p=>J(a.agentId,o,e,i,u,d,p)),()=>me(p=>J(a.agentId,o,e,i,u,d,p)));U.set(e,m),m.finally(()=>{U.get(e)===m&&U.delete(e)})}function Wn(e,n){const t=Dn(e);if(!t)return;n.seq+=1;const r=n.seq,s=Pn(e),o={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&t.length<Hn){const c=`${e.sessionId}:${e.type}`;let u=Z.get(c);if(u||(u={buffer:"",seq:0,timer:null,entry:n,sourceEventType:e.type}),u.buffer+=t,u.seq=r,u.entry=n,!u.timer){const d=e.sessionId,l=e.type;u.timer=setTimeout(()=>pe(d,l),qn)}Z.set(c,u);return}pe(e.sessionId);const a=(U.get(e.sessionId)??Promise.resolve()).then(()=>me(c=>J(n.agentId,t,e.sessionId,r,s,o,c)),()=>me(c=>J(n.agentId,t,e.sessionId,r,s,o,c)));U.set(e.sessionId,a),a.finally(()=>{U.get(e.sessionId)===a&&U.delete(e.sessionId)})}function dt(e){return St(e)}let lt=!1;function Gn(){lt||(It(_,Xn),Ct(),lt=!0)}function Xn(e,n){e.on("event",t=>{const r=g.get(t.sessionId);if(r){if(t.type==="tool_use_start"?jt(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&Nt(t,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),f.info(`[${n.displayName} Adapter] Event: ${t.type} for session ${t.sessionId}`),!(t.type==="thinking"||t.type==="text_delta"||t.type==="tool_use_start"||t.type==="context_compaction"||t.type==="ai_request"||t.type==="error")){t.type==="runtime_capabilities"&&t.data.actionDetail&&(r.cachedCapabilitiesActionDetail=t.data.actionDetail);const i=Kn(t,r.currentRuntimeStatus);i&&E(r.agentId,t.sessionId,i.status,i.actionInfo,ae(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.timestamp?new Date(t.timestamp).getTime():void 0,t.type)}Wn(t,r);const o=Rn(t);if(o){const i=t.timestamp?new Date(t.timestamp).getTime():void 0,a=String(t.data?.toolName||"").toLowerCase()==="browser_launch",c=t.type==="tool_use_end"&&String(t.data?.rawToolName||t.data?.toolName||"").toLowerCase().replace(/[_-]/g,"").includes("todowrite");we(a?{entry:r,sessionId:t.sessionId,actionInfo:o,timestamp:i,sourceEventType:t.type,backoffBaseMs:3e3,label:"browser_launch"}:c?{entry:r,sessionId:t.sessionId,actionInfo:o,timestamp:i,sourceEventType:t.type,backoffBaseMs:1e3,label:"todo_write"}:{entry:r,sessionId:t.sessionId,actionInfo:o,timestamp:i,sourceEventType:t.type,backoffBaseMs:1e3,label:"tool_result"})}}}),e.on("status-change",(t,r,s)=>{const o=g.get(t);if(o){pe(t),r==="thinking"||r==="tool_using"||r==="compacting"?Xt(t):M(t);const i=sn(r,s);o.currentRuntimeStatus=i.status;const a=o.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),d=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(o.currentRuntimeActionType==="idle"||o.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!d)&&(o.currentRuntimeActionType=i.actionInfo?.actionType,o.currentRuntimeActionLabel=i.actionInfo?.actionLabel,o.currentRuntimeActionDetail=i.actionInfo?.actionDetail,o.currentRuntimeActionInput=i.actionInfo?.actionInput),f.info(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${o.agentId}`,i.actionInfo||""),qt(t,{runtimeStatus:i.status,runtimeActionType:o.currentRuntimeActionType,runtimeActionLabel:o.currentRuntimeActionLabel,runtimeActionDetail:o.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:o.currentRuntimeActionType?{actionType:o.currentRuntimeActionType,actionLabel:o.currentRuntimeActionLabel??"",actionDetail:o.currentRuntimeActionDetail,actionInput:o.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const p=(le.get(t)??Promise.resolve()).then(async()=>{for(let y=0;y<=2;y++){if(await E(o.agentId,t,i.status,l,ae(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})!==void 0)return;y<2&&(f.warn(`[${n.displayName}] compaction sendStatus attempt ${y+1} failed (HTTP), retrying in ${1e3*(y+1)}ms...`),await new Promise($=>setTimeout($,1e3*(y+1))))}f.warn(`[${n.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(b=>{f.warn(`[${n.displayName}] compaction status chain error:`,b)});le.set(t,p),p.finally(()=>{le.get(t)===p&&le.delete(t)})}else{const m=d&&!i.actionInfo?.actionType;if(an({status:i.status,actionInfo:i.actionInfo,restoredActionInfo:l,currentRuntimeActionType:o.currentRuntimeActionType,shouldPreservePrevAction:d})){const y=(fe.get(t)??Promise.resolve()).then(async()=>{for(let $=0;$<=2;$++){if(await E(o.agentId,t,i.status,m?void 0:l,ae(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})!==void 0)return;$<2&&await new Promise(D=>setTimeout(D,1e3*($+1)))}f.warn(`[${n.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(h=>{f.warn(`[${n.displayName}] idle status chain error:`,h)});fe.set(t,y),y.finally(()=>{fe.get(t)===y&&fe.delete(t)})}else E(o.agentId,t,i.status,m?void 0:l,ae(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}if(i.status==="waiting_input"&&o.cachedCapabilitiesActionDetail){const m=o.cachedCapabilitiesActionDetail;o.cachedCapabilitiesActionDetail=void 0,f.info(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${o.agentId} (session stabilized to waiting_input)`),E(o.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:m},void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=g.get(t.sessionId);r&&(f.info(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),Bt(r.agentId,t.sessionId,Array.isArray(t.questions)?t.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.toolCallId))}),e.on("tool-permission-request",t=>{const r=g.get(t.sessionId);r&&t.requestId&&(f.info(`[${n.displayName} Adapter] Tool permission request (${t.capability}) for agent ${r.agentId}`),Ft(r.agentId,t.sessionId,{requestId:t.requestId,capability:t.capability,...t.detail||{}},{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}))}),e.on("permission-request",t=>{const r=g.get(t.sessionId);if(r){f.info(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const s=t.toolInput?K(JSON.stringify(t.toolInput).slice(0,400)):void 0;E(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:s||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}S.post("/start",I,async(e,n)=>{const{agentId:t,workspacePath:r,mode:s="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const o=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||Ue(Ge(e))||void 0;Lt({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||o,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:o}),e.body?.runtimeFeatures!==null&&e.body?.runtimeFeatures!==void 0&&(wt(String(t),e.body.runtimeFeatures),f.info(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(Pt(String(t)))}`)),e.body?.inheritedFeatures!==null&&e.body?.inheritedFeatures!==void 0&&(Rt(String(t),e.body.inheritedFeatures),f.info(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u7EE7\u627F\u4E09\u6001\u5C42: ${JSON.stringify(Ot(String(t)))}`)),e.body?.capabilities!==void 0&&Et(String(t),e.body.capabilities),e.body?.capabilitiesInherited!==void 0&&Dt(String(t),e.body.capabilitiesInherited),e.body?.envVars!==null&&e.body?.envVars!==void 0&&typeof e.body.envVars=="object"&&(Mt(String(t),e.body.envVars),f.info(`[Runtime] agent ${t} \u4E0B\u53D1\u6709\u6548\u73AF\u5883\u53D8\u91CF: ${Object.keys(e.body.envVars).length} \u9879 \u2192 \u5DE5\u5177\u5B50\u8FDB\u7A0B + MCP spec`)),e.body?.changeCacheRetentionDays!==void 0&&(bt(e.body.changeCacheRetentionDays),f.info(`[Runtime] agent ${t} \u4E0B\u53D1\u53D8\u66F4\u7F13\u5B58\u4FDD\u7559\u5929\u6570: ${e.body.changeCacheRetentionDays??"\u4E0D\u6E05\u7406"}`)),s&&s!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${s}" requested for agent ${t}; starting SDK session instead.`),await Yn(e,n)});async function Yn(e,n){const{agentId:t,workspacePath:r,command:s,projectRoot:o,autoAccept:i=!0,initialPrompt:a,systemPrompt:c,globalPrompt:u,rolePrompt:d,memory:l,resumeContext:m,resumeTranscript:p,mcpConfigPath:b,extraMcpServers:y,envOverrides:h,idleInputAutoCommand:$,nonInputAutoCommand:R,model:D,instanceAiConfig:ge,subAgentModel:ye,subAgentEffort:he,scopeKey:Ee,browserAllowPrivate:Re}=e.body||{},W=Zt(p);f.info(`[HIBERNATE-IMPORT] \u542F\u52A8\u8BF7\u6C42\u643A\u5E26\u4F11\u7720\u6062\u590D: agentId=${String(t||"").trim()||"?"} resumeContext=${typeof m=="string"?`${m.length}\u5B57`:"\u65E0"} resumeTranscript\u539F\u59CB=${typeof p=="string"?`${p.length}\u5B57`:typeof p} \u89E3\u6790\u7ED3\u679C=${W?`${W.length}\u6761`:"null"}`);const G=Wt();G.log({level:"info",category:"launch",message:"startSdkSession: \u6536\u5230\u542F\u52A8\u8BF7\u6C42",source:"bridge",agentId:String(t||"").trim()||void 0,details:{reqBodyKeys:Object.keys(e.body||{}),perInstanceAiConfig:ge?oe(ge):null,perAgentModel:D??null}});let w=null;const A=String(t||"").trim(),Ie=String(e.body?.runtimeAccessToken||"").trim()||void 0,B=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||Ue(Ge(e))||void 0;B?f.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${B} (agentId=${A})`):f.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${A})`);try{if(Gn(),!A){n.status(400).json({error:"agentId is required"});return}const F=ot(A);if(F){n.json(await In(F));return}const k=await vt(A);if(k){const O=await Sn(k);if(!O.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${A}, sessionId=${k.sessionId}, reason=${O.reason}`),await q(k.sessionId);else{const L=ue(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);n.json({sessionId:k.sessionId,status:L,runtimeStatus:L,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(z.has(A)){n.status(409).json({error:"SDK session is already starting for this agent"});return}z.add(A);const P=dt(s),ft=_.get(P);w=ht();const mt=P==="claude-code"?await Cn():null,ee=it(P==="claude-code"?mt:null,h),X=P==="acode"?D?String(D).trim():void 0:(()=>{const O=D?String(D).trim():void 0,L=ee.model?String(ee.model).trim():void 0;return O||L})();G.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:A,sessionId:w??void 0,details:{perAgentModel:D??null,globalModel:ee.model??null,resolvedModel:X??null,providerId:P,note:P==="acode"?"adapter handles full priority":"request > global"}});const Se={...ee.envOverrides};X&&(Se.ANTHROPIC_MODEL=X,Se.CODEX_MODEL=X);let Y,Ae=b;if(P==="acode"){const O=ge||{},L=await $t({apiOverrides:Qe(O)??void 0,agentId:A,sessionId:w??void 0,runtimeBridgeBaseUrl:B});Y=L.instanceConfig.config,Ae=L.perInstanceConfigPath,G.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:A,sessionId:w??void 0,details:{sanitizedApiOverrides:(()=>{const N=Qe(O);return N?oe(N):null})(),resolvedInstanceAiConfig:Y?oe(Y):null,perInstanceConfigPath:Ae,instanceConfigSources:L.instanceConfig.source??null}})}let De=c||void 0,Te,_e,te;const ne=typeof m=="string"&&m.trim()?Tt(m):void 0;if(P==="acode")if(Te=typeof u=="string"&&u.trim()||void 0,_e=typeof d=="string"&&d.trim()||void 0,typeof l=="string"&&l.trim())te=l.trim();else{const O=await tn(r,{schedulerBaseUrl:B,runtimeAccessToken:Ie,agentId:A});O&&(te=O,f.info(`[startSdkSession] Auto-loaded memories for ACode agent ${A}`))}else if(typeof u=="string"&&u.trim()||typeof d=="string"&&d.trim()||typeof l=="string"&&l.trim()||ne!==void 0){const L=[u,d,l,ne,c].filter(N=>typeof N=="string"&&N.trim().length>0).map(N=>N.trim());De=L.length>0?L.join(`
|
|
52
49
|
|
|
53
|
-
`):void 0}const j={command:o||"acode",workingDirectory:r,agentId:A,...Te?{scopeKey:Te}:{},...typeof ke=="boolean"?{browserAllowPrivate:ke}:{},autoAccept:!!s,initialPrompt:i,systemPrompt:be,...ge!==void 0?{globalPrompt:ge}:{},...ye!==void 0?{rolePrompt:ye}:{},...ee!==void 0?{memory:ee}:{},model:X,mcpConfigPath:pe,...G?{instanceAiConfig:G}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof M=="string"&&M.trim()?{subAgentEffort:M.trim()}:{},extraMcpServers:f||{},envOverrides:Ke(String(t),String(r),process.env,fe)};W.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:A,sessionId:D,details:{adapterModel:j.model??null,adapterInstanceAiConfig:j.instanceAiConfig?ne(j.instanceAiConfig):null,adapterMcpConfigPath:j.mcpConfigPath??null}}),await W.flush(),p.set(D,{agentId:A,workspacePath:r,sessionId:D,config:j,providerId:E,seq:0,runtimeAccessToken:me,schedulerBaseUrl:N}),n.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:A,workspacePath:r,command:j.command,mode:"sdk"}),Dn({sessionId:D,agentId:A,config:j,adapter:Ve,providerId:E,idleInputAutoCommand:T,nonInputAutoCommand:h,runtimeAccessToken:me,requestedSchedulerBaseUrl:N})}catch(q){if(D&&(L(D),p.delete(D),K(D)),A&&H.delete(A),!n.headersSent){const k=q instanceof Error?q.message:String(q);n.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function Dn(e){const{sessionId:n,agentId:t,config:r,adapter:o,providerId:s,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await o.startSession(n,r),o.setIdleCommands?.(n,{idleInputCommand:i||Ce,nonInputCommand:a||""});let u;if(Lt(s))try{if(await new Promise(f=>setTimeout(f,500)),u=o.getSessionPid?.(n),!u){const g=(await gt()).find(T=>T.agentId===t||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));g&&(u=g.pid,m.info(`[Runtime] Found SDK process PID: ${u} for agentId=${t}`))}}catch(f){console.warn(`[Runtime] Failed to get SDK PID for agentId=${t}:`,f)}const l=ie(o.getSessionStatus(n),p.get(n)?.currentRuntimeStatus,p.get(n)?.currentRuntimeActionType);await _t({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:o.getProviderSessionId(n)}),u&&await Ie().startProcess({agentId:t,sessionId:n,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await Rn({agentId:t,sessionId:n,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){L(n),p.delete(n),K(n),await z(n);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${t}: ${l}`),await Pn({agentId:t,sessionId:n,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{H.delete(t)}}async function Rn(e){const{agentId:n,sessionId:t,sdkPid:r,status:o,schedulerBaseUrl:s,runtimeAccessToken:i}=e;if(!s||!i){m.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${s.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(a,{agentId:n,sessionId:t,status:o,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session ready: agentId=${n}, sessionId=${t}, status=${o}`)}catch(c){const d=c instanceof Error?c.message:String(c);m.warn(`[Runtime] Failed to notify server session ready: agentId=${n}, error=${d}`)}}async function Pn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:o}=e;if(!r||!o)return;const s=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(s,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":o,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session failed: agentId=${n}, sessionId=${t}`)}catch(i){const a=i instanceof Error?i.message:String(i);m.warn(`[Runtime] Failed to notify server session failed: agentId=${n}, error=${a}`)}}S.post("/sdk/message",I,async(e,n)=>{const{sessionId:t,message:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and message are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendMessage(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/answer",I,async(e,n)=>{const{sessionId:t,answers:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and answers are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code",i=b.get(s);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/tool-auth/answer",I,async(e,n)=>{const{sessionId:t,requestId:r,allowed:o}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and requestId are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(!a.submitToolPermissionDecision){n.status(400).json({error:"adapter does not support tool authorization"});return}const c=a.submitToolPermissionDecision(t,String(r),!!o);n.json({ok:!0,existed:c})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.get("/tool-auth/pending/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingToolAuthRequests?.(t)??[];n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingRequests:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/confirm",I,async(e,n)=>{const{sessionId:t,accept:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendConfirmation(t,!!r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/abort",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code";await b.get(o).abortCurrentTurn(t),n.json({ok:!0})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const o=r.providerId||"claude-code",s=b.get(o);s.abortCurrentTurn(t).catch(()=>{}),await s.terminateSession(t),L(t),p.delete(t),K(t),ae(t),await z(t),await Ie().removeProcess(r.agentId),await C(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),n.json({ok:!0,status:"stopped"})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/status/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",s=b.get(o),i=s.getSessionStatus(t),a=s.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/capabilities/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/pending-questions/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingQuestion?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/command",I,async(e,n)=>{const{sessionId:t,command:r}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and command are required"});return}try{const o=await Vt(String(t),r);n.json({ok:!0,mode:"terminal",...o})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/input",I,async(e,n)=>{const{sessionId:t,input:r,mode:o}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(o==="shortcut"){if(!a.sendShortcutInput){n.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await a.sendShortcutInput(t,String(r)),n.json({ok:!0,mode:"shortcut"});return}await a.sendMessage(t,await Jt(r)),n.json({ok:!0,mode:"sdk"})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.post("/update-auto-commands",I,async(e,n)=>{const{agentId:t,idleInputAutoCommand:r="",nonInputAutoCommand:o=""}=e.body||{},s=String(t||"").trim();if(!s){n.status(400).json({error:"agentId is required"});return}const i=[...p.values()].find(c=>c.agentId===s),a={idleInputCommand:String(r||"").trim()||Ce,nonInputCommand:String(o||"")};try{let c=!1;i&&(b.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await bt(s,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});n.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:d})}catch(c){const d=c instanceof Error?c.message:String(c);n.status(500).json({ok:!1,mode:"sdk",error:d})}}),S.post("/resize",I,(e,n)=>{const{sessionId:t,cols:r,rows:o}=e.body||{};if(!t||!r||!o){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!p.has(t)){n.status(404).json({error:"SDK session not found"});return}n.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(o)})}),S.post("/reset-context",I,async(e,n)=>{const{sessionId:t,reason:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}const s=o.providerId||"claude-code",i=b.get(s),a=i.resetContext?.bind(i),c=Mt(s,!!a);if(!c.supported){n.status(c.statusCode).json({error:c.error});return}if(!a){n.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(t));const d=ie(i.getSessionStatus(String(t)),o.currentRuntimeStatus,o.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:d,runtimeStatus:d,agentId:o.agentId,mode:"sdk",providerId:s,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(d){const u=d instanceof Error?d.message:String(d);n.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:u})}}),S.post("/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{},r=xt(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){await z(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const s=o.agentId;try{m.info(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=o.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),L(t),p.delete(t),K(t),ae(t),await z(t),await Ie().removeProcess(s),r.statusNotified?await C(s,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl}):m.info(`[Runtime] Stopped status notification suppressed for SDK session ${t}; reason=${r.reason||"unspecified"}`),n.json({ok:!0,status:"stopped",mode:"sdk",statusNotified:r.statusNotified,reason:r.reason})}catch(i){const a=i instanceof Error?i.message:String(i);console.error(`[Runtime] Failed to terminate SDK session ${t}:`,a),n.status(500).json({ok:!1,status:"stop_failed",mode:"sdk",error:a})}}),S.post("/stop-all",I,async(e,n)=>{const t=[],r=[];for(const[o,s]of p.entries())try{const i=s.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(o).catch(()=>{}),await a.terminateSession(o),L(o),p.delete(o),K(o),ae(o),t.push(o),await C(s.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${o}: ${a}`)}try{await kt([]),m.info("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(o){const s=o instanceof Error?o.message:String(o);r.push(`Persistence: ${s}`)}n.json({ok:!0,stopped:{sdk:t.length},errors:r.length>0?r:void 0})}),S.get("/events/last/:n",I,(e,n)=>{const t=parseInt(e.params.n,10);if(!Number.isFinite(t)||t<1){n.status(400).json({error:":n must be a positive integer"});return}const r=Le.getLastN(t);n.json({ok:!0,count:r.length,entries:r})}),S.get("/events/since/:index",I,(e,n)=>{const t=parseInt(e.params.index,10);if(!Number.isFinite(t)||t<0){n.status(400).json({error:":index must be a non-negative integer"});return}const r=Le.getSinceIndex(t);n.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>t+1})}),S.get("/events/push-stats",I,(e,n)=>{const t=at();n.json({ok:!0,count:t.length,agents:t})});export{Ot as buildAcodeCommandOutputPath,ze as buildClaudeCodeLaunchConfig,Ke as buildRuntimeEnv,sn as buildSdkOutputMetadata,rn as buildToolResultTimelineActionInfo,or as cleanupSdkSessionByAgentId,Bt as countTerminalOutputLines,ve as createTerminalOutputDecoder,se as decodeTerminalOutputChunk,Xt as evaluatePersistedSessionReuse,qt as formatCommandInactivityTimeoutNotice,Nt as formatCommandOutputSpilloverNotice,on as formatSdkOutputEvent,Se as formatTerminalPrompt,vt as normalizeTerminalCommandInput,xt as parseRuntimeStopOptions,zt as parseTerminalDirectoryChangeTarget,de as raceSendOutputWithRetry,Mt as resolveRuntimeContextResetSupport,An as resolveRuntimeStatusFromProviderEvent,Jt as resolveSdkInputMessage,Ge as resolveSdkProviderId,ie as resolveSdkSessionDisplayStatus,Ut as resolveStatusChangeRuntimeState,oe as resolveStatusChangeUsage,Ft as resolveTerminalOutputEncoding,p as sdkSessions,Lt as shouldProbeSdkProcessPid,S as terminalRouter};
|
|
50
|
+
`):void 0}const x={command:s||"acode",workingDirectory:r,agentId:A,...Ee?{scopeKey:Ee}:{},...typeof Re=="boolean"?{browserAllowPrivate:Re}:{},autoAccept:!!i,initialPrompt:a,systemPrompt:De,...Te!==void 0?{globalPrompt:Te}:{},..._e!==void 0?{rolePrompt:_e}:{},...te!==void 0?{memory:te}:{},...ne!==void 0?{resumeContext:ne}:{},...P==="acode"&&Array.isArray(W)&&W.length>0?{resumeTranscript:W}:{},model:X,mcpConfigPath:Ae,...Y?{instanceAiConfig:Y}:{},...typeof ye=="string"&&ye.trim()?{subAgentModel:ye.trim()}:{},...typeof he=="string"&&he.trim()?{subAgentEffort:he.trim()}:{},extraMcpServers:y||{},envOverrides:st(String(t),String(r),process.env,Se,typeof o=="string"?o:void 0)};G.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:A,sessionId:w,details:{adapterModel:x.model??null,adapterInstanceAiConfig:x.instanceAiConfig?oe(x.instanceAiConfig):null,adapterMcpConfigPath:x.mcpConfigPath??null}}),await G.flush(),g.set(w,{agentId:A,workspacePath:r,sessionId:w,config:x,providerId:P,seq:0,runtimeAccessToken:Ie,schedulerBaseUrl:B}),n.json({sessionId:w,status:"starting",runtimeStatus:"starting",agentId:A,workspacePath:r,command:x.command,mode:"sdk"}),Jn({sessionId:w,agentId:A,config:x,adapter:ft,providerId:P,idleInputAutoCommand:$,nonInputAutoCommand:R,runtimeAccessToken:Ie,requestedSchedulerBaseUrl:B})}catch(F){if(w&&(M(w),g.delete(w),H(w)),A&&z.delete(A),!n.headersSent){const k=F instanceof Error?F.message:String(F);n.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function Jn(e){const{sessionId:n,agentId:t,config:r,adapter:s,providerId:o,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:u}=e;try{await s.startSession(n,r),s.setIdleCommands?.(n,{idleInputCommand:i||Le,nonInputCommand:a||""});let d;if(rn(o))try{if(await new Promise(m=>setTimeout(m,500)),d=s.getSessionPid?.(n),!d){const p=(await Ut()).find(b=>b.agentId===t||b.cwd===r.workingDirectory||b.command.includes(r.workingDirectory));p&&(d=p.pid,f.info(`[Runtime] Found SDK process PID: ${d} for agentId=${t}`))}}catch(m){console.warn(`[Runtime] Failed to get SDK PID for agentId=${t}:`,m)}const l=ue(s.getSessionStatus(n),g.get(n)?.currentRuntimeStatus,g.get(n)?.currentRuntimeActionType);await zt({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:d,providerSessionId:s.getProviderSessionId(n)}),d&&await ke().startProcess({agentId:t,sessionId:n,pid:d,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await Vn({agentId:t,sessionId:n,sdkPid:d,status:l,schedulerBaseUrl:u,runtimeAccessToken:c})}catch(d){M(n),g.delete(n),H(n),await q(n);const l=d instanceof Error?d.message:String(d);console.error(`[Runtime] Background SDK session startup failed for agentId=${t}: ${l}`),await Qn({agentId:t,sessionId:n,schedulerBaseUrl:u,runtimeAccessToken:c,errorMessage:l})}finally{z.delete(t)}}async function Vn(e){const{agentId:n,sessionId:t,sdkPid:r,status:s,schedulerBaseUrl:o,runtimeAccessToken:i}=e;if(!o||!i){f.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${o.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Pe.post(a,{agentId:n,sessionId:t,status:s,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),f.debug(`[Runtime] Notified server session ready: agentId=${n}, sessionId=${t}, status=${s}`)}catch(c){const u=c instanceof Error?c.message:String(c);f.warn(`[Runtime] Failed to notify server session ready: agentId=${n}, error=${u}`)}}async function Qn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:s}=e;if(!r||!s)return;const o=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Pe.post(o,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":s,"Content-Type":"application/json"},timeout:5e3}),f.debug(`[Runtime] Notified server session failed: agentId=${n}, sessionId=${t}`)}catch(i){const a=i instanceof Error?i.message:String(i);f.warn(`[Runtime] Failed to notify server session failed: agentId=${n}, error=${a}`)}}S.post("/sdk/message",I,async(e,n)=>{const{sessionId:t,message:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and message are required"});return}const s=g.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await _.get(o).sendMessage(t,r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);n.status(500).json({error:i})}}),S.post("/sdk/answer",I,async(e,n)=>{const{sessionId:t,answers:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and answers are required"});return}const s=g.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code",i=_.get(o);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);n.status(500).json({error:i})}}),S.post("/tool-auth/answer",I,async(e,n)=>{const{sessionId:t,requestId:r,allowed:s}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and requestId are required"});return}const o=g.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const i=o.providerId||"claude-code",a=_.get(i);if(!a.submitToolPermissionDecision){n.status(400).json({error:"adapter does not support tool authorization"});return}const c=a.submitToolPermissionDecision(t,String(r),!!s);n.json({ok:!0,existed:c})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.get("/tool-auth/pending/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",i=_.get(s).getPendingToolAuthRequests?.(t)??[];n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingRequests:i,fetchedAt:Date.now()})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.post("/sdk/confirm",I,async(e,n)=>{const{sessionId:t,accept:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const s=g.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await _.get(o).sendConfirmation(t,!!r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);n.status(500).json({error:i})}}),S.post("/sdk/abort",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code";await _.get(s).abortCurrentTurn(t),n.json({ok:!0})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.post("/sdk/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const s=r.providerId||"claude-code",o=_.get(s);o.abortCurrentTurn(t).catch(()=>{}),await o.terminateSession(t),M(t),g.delete(t),H(t),de(t),await q(t),await ke().removeProcess(r.agentId),await E(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),n.json({ok:!0,status:"stopped"})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.get("/sdk/snapshot/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",o=_.get(s),i=o.getConversation(t),a=Vt(i);let c=null;if(s==="acode"){const d=o;typeof d.exportRawTranscript!="function"?f.warn(`[HIBERNATE-EXPORT] adapter \u65E0 exportRawTranscript \u65B9\u6CD5 \u2014 bridge \u8FDB\u7A0B\u53EF\u80FD\u8FD0\u884C\u7684\u662F\u65E7\u6784\u5EFA\uFF08\u8BF7\u91CD\u542F bridge\uFF09\u3002providerId=${s}`):(c=d.exportRawTranscript?.(t)??null,c===null&&f.warn(`[HIBERNATE-EXPORT] exportRawTranscript \u8FD4\u56DE\u7A7A \u2014 runtime \u53EF\u80FD\u672A\u5B8C\u6210 start() \u6216\u4E0D\u652F\u6301\u3002providerId=${s}`))}else f.info(`[HIBERNATE-EXPORT] provider=${s} \u4E0D\u652F\u6301\u5B8C\u6574\u91CD\u653E\uFF0C\u6309\u4EC5\u6458\u8981\u4F11\u7720`);const u=o.getTotalUsage?.(t);f.info(`[HIBERNATE-EXPORT] \u5FEB\u7167\u5BFC\u51FA: sessionId=${t} agentId=${r.agentId} providerId=${s} messages=${i.length} summaryChars=${a.snapshot.length} truncated=${a.truncated} transcript=${c?`${c.length}\u6761`:"null"} usage=${u?`in=${u.inputTokens??"?"}/out=${u.outputTokens??"?"}`:"null"}`),n.json({sessionId:t,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:i.length,truncated:a.truncated,snapshot:a.snapshot,transcript:c,tokenUsage:u?{inputTokens:u.inputTokens??null,outputTokens:u.outputTokens??null}:null,providerId:s})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.get("/sdk/status/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",o=_.get(s),i=o.getSessionStatus(t),a=o.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.get("/sdk/capabilities/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",i=_.get(s).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.get("/sdk/pending-questions/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=g.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",i=_.get(s).getPendingQuestion?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),S.post("/command",I,async(e,n)=>{const{sessionId:t,command:r}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and command are required"});return}try{const s=await _n(String(t),r);n.json({ok:!0,mode:"terminal",...s})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}});function Zn(e,n){if(typeof e!="string"||!e||!n||typeof n!="object")return e;const{userId:t,name:r,type:s}=n,o=typeof t=="string"&&t.trim()?t.trim():"",i=typeof r=="string"&&r.trim()?r.trim():o;if(!o&&!i)return e;const a=typeof s=="string"&&s.trim()?s.trim().toUpperCase():"HUMAN",c=i||o,u=o?`, userId: ${o}`:"";return`\u3010${c}\uFF08${a}${u}\uFF09\u53D1\u6765\u3011
|
|
51
|
+
${e}`}S.post("/input",I,async(e,n)=>{const{sessionId:t,input:r,mode:s,sender:o}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const i=g.get(t);if(!i){n.status(404).json({error:"SDK session not found"});return}try{const a=i.providerId||"claude-code",c=_.get(a);if(s==="shortcut"){if(!c.sendShortcutInput){n.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await c.sendShortcutInput(t,String(r)),n.json({ok:!0,mode:"shortcut"});return}await c.sendMessage(t,Zn(await kn(r),o)),n.json({ok:!0,mode:"sdk"})}catch(a){const c=a instanceof Error?a.message:String(a);n.status(500).json({error:c})}}),S.post("/update-auto-commands",I,async(e,n)=>{const{agentId:t,idleInputAutoCommand:r="",nonInputAutoCommand:s=""}=e.body||{},o=String(t||"").trim();if(!o){n.status(400).json({error:"agentId is required"});return}const i=[...g.values()].find(c=>c.agentId===o),a={idleInputCommand:String(r||"").trim()||Le,nonInputCommand:String(s||"")};try{let c=!1;i&&(_.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const u=await Ht(o,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});n.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:u})}catch(c){const u=c instanceof Error?c.message:String(c);n.status(500).json({ok:!1,mode:"sdk",error:u})}}),S.post("/resize",I,(e,n)=>{const{sessionId:t,cols:r,rows:s}=e.body||{};if(!t||!r||!s){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!g.has(t)){n.status(404).json({error:"SDK session not found"});return}n.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(s)})}),S.post("/reset-context",I,async(e,n)=>{const{sessionId:t,reason:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const s=g.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}const o=s.providerId||"claude-code",i=_.get(o),a=i.resetContext?.bind(i),c=nn(o,!!a);if(!c.supported){n.status(c.statusCode).json({error:c.error});return}if(!a){n.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(t));const u=ue(i.getSessionStatus(String(t)),s.currentRuntimeStatus,s.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:u,runtimeStatus:u,agentId:s.agentId,mode:"sdk",providerId:o,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(u){const d=u instanceof Error?u.message:String(u);n.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:d})}}),S.post("/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{},r=on(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const s=g.get(t);if(!s){await q(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const o=s.agentId;try{f.info(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=s.providerId||"claude-code",a=_.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),M(t),g.delete(t),H(t),de(t),await q(t),await ke().removeProcess(o),r.statusNotified?await E(o,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl}):f.info(`[Runtime] Stopped status notification suppressed for SDK session ${t}; reason=${r.reason||"unspecified"}`),n.json({ok:!0,status:"stopped",mode:"sdk",statusNotified:r.statusNotified,reason:r.reason})}catch(i){const a=i instanceof Error?i.message:String(i);console.error(`[Runtime] Failed to terminate SDK session ${t}:`,a),n.status(500).json({ok:!1,status:"stop_failed",mode:"sdk",error:a})}}),S.post("/stop-all",I,async(e,n)=>{const t=[],r=[];for(const[s,o]of g.entries())try{const i=o.providerId||"claude-code",a=_.get(i);a.abortCurrentTurn(s).catch(()=>{}),await a.terminateSession(s),M(s),g.delete(s),H(s),de(s),t.push(s),await E(o.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${s}: ${a}`)}try{await Kt([]),f.info("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(s){const o=s instanceof Error?s.message:String(s);r.push(`Persistence: ${o}`)}n.json({ok:!0,stopped:{sdk:t.length},errors:r.length>0?r:void 0})}),S.get("/events/last/:n",I,(e,n)=>{const t=parseInt(e.params.n,10);if(!Number.isFinite(t)||t<1){n.status(400).json({error:":n must be a positive integer"});return}const r=We.getLastN(t);n.json({ok:!0,count:r.length,entries:r})}),S.get("/events/since/:index",I,(e,n)=>{const t=parseInt(e.params.index,10);if(!Number.isFinite(t)||t<0){n.status(400).json({error:":index must be a non-negative integer"});return}const r=We.getSinceIndex(t);n.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>t+1})}),S.get("/events/push-stats",I,(e,n)=>{const t=kt();n.json({ok:!0,count:t.length,agents:t})});export{un as buildAcodeCommandOutputPath,it as buildClaudeCodeLaunchConfig,st as buildRuntimeEnv,Pn as buildSdkOutputMetadata,Rn as buildToolResultTimelineActionInfo,Er as cleanupSdkSessionByAgentId,dn as countTerminalOutputLines,rt as createTerminalOutputDecoder,ce as decodeTerminalOutputChunk,Sn as evaluatePersistedSessionReuse,fn as formatCommandInactivityTimeoutNotice,ln as formatCommandOutputSpilloverNotice,Dn as formatSdkOutputEvent,Ce as formatTerminalPrompt,an as isIdleStatusChangeRetryable,mn as normalizeTerminalCommandInput,Zt as parseResumeTranscript,on as parseRuntimeStopOptions,yn as parseTerminalDirectoryChangeTarget,me as raceSendOutputWithRetry,Vt as renderSessionSnapshot,nn as resolveRuntimeContextResetSupport,Kn as resolveRuntimeStatusFromProviderEvent,kn as resolveSdkInputMessage,dt as resolveSdkProviderId,ue as resolveSdkSessionDisplayStatus,sn as resolveStatusChangeRuntimeState,ae as resolveStatusChangeUsage,pn as resolveTerminalOutputEncoding,g as sdkSessions,rn as shouldProbeSdkProcessPid,S as terminalRouter,Zn as withSenderSignature};
|
|
54
52
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execSync as R}from"node:child_process";import v from"node:os";import{createLogger as A}from"../utils/logger.js";import{isProcessRunning as p,isProcessRunningAsync as b,findClaudeCodeProcesses as w,findOrphanProcessByAgentId as I,terminateProcessTree as u,waitForProcessExit as f,checkProcessHealth as O}from"./process-detector.js";import{getProcessRegistry as M}from"./process-registry.js";import{loadPersistedSessions as $}from"./terminal-persistence.js";const r=A("agent-process-manager");async function x(h,e,s){const t=new Array(h.length);let i=0;const o=Math.min(Math.max(e,1),h.length),a=Array.from({length:o},async()=>{for(;i<h.length;){const d=i++;t[d]=await s(h[d])}});return await Promise.all(a),t}class g{constructor(){this.registry=M()}static getInstance(){return g.instance===null&&(g.instance=new g),g.instance}async startProcess(e){const{agentId:s,sessionId:t,pid:i,mode:o,workspacePath:a,command:d}=e;if(r.info(`[startProcess] Starting process: agentId=${s}, pid=${i}, mode=${o}`),await this.registry.register({agentId:s,sessionId:t,pid:i,mode:o,state:"creating",workspacePath:a,command:d}),r.debug(`[startProcess] Verifying process is running: pid=${i}`),!p(i))throw r.error(`[startProcess] Process not running after registration: agentId=${s}, pid=${i}`),await this.registry.markTerminated(s),new Error(`Process ${i} is not running`);await this.registry.update(s,{state:"running"}),await this.registry.updateHeartbeat(s),r.info(`[startProcess] Process started successfully: agentId=${s}, pid=${i}`)}async discoverAllProcesses(){r.debug("[discoverAllProcesses] Scanning for all agent processes");const e=await w(),s=this.registry.getAll(),t=[],i=new Set(s.map(n=>n.pid)),o=new Set(s.map(n=>n.agentId)),a=new Map(s.map(n=>[n.pid,n]));for(const n of e){const l=i.has(n.pid),P=n.agentId&&o.has(n.agentId),k=a.get(n.pid),m=n.agentId||k?.agentId;if(l||P){const S=s.find(y=>y.pid===n.pid||y.agentId===n.agentId||y.agentId===m);t.push({...n,agentId:m,managementStatus:"managed",sessionId:S?.sessionId})}else m?t.push({...n,agentId:m,managementStatus:"orphan"}):t.push({...n,agentId:m,managementStatus:"unknown"})}const d=s.filter(n=>!t.some(l=>l.pid===n.pid)),c=await x(d,4,async n=>{const l=await b(n.pid);return{pid:n.pid,command:n.command,agentId:n.agentId,managementStatus:l?"managed":"orphan",sessionId:n.sessionId}});return t.push(...c),r.debug(`[discoverAllProcesses] Discovered ${t.length} processes: ${t.filter(n=>n.managementStatus==="managed").length} managed, ${t.filter(n=>n.managementStatus==="orphan").length} orphans, ${t.filter(n=>n.managementStatus==="unknown").length} unknown`),t}async healthCheckAll(){r.debug("[healthCheckAll] Starting health check for all processes");const e=new Map,s=this.registry.getAll(),t=s.map(async i=>{const o=await this.healthCheck(i.agentId);return e.set(i.agentId,o),o});return await Promise.all(t),r.debug(`[healthCheckAll] Completed health check for ${s.length} processes`),e}async healthCheck(e){const s=this.registry.get(e);if(!s)return r.warn(`[healthCheck] Process not found in registry: agentId=${e}`),{pid:-1,agentId:e,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};const t=await O(s.pid,e),i={cpu:t.cpu,memoryMB:t.memoryMB,status:t.status};return await this.registry.updateHealth(e,i),t.alive?await this.registry.updateHeartbeat(e):s.state!=="terminated"&&s.state!=="orphaned"&&(r.warn(`[healthCheck] Process died unexpectedly: agentId=${e}, pid=${s.pid}`),await this.registry.markOrphaned(e)),t}async stopProcess(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;if(r.info(`[stopProcess] Stopping process: agentId=${e}, pid=${t}`),!p(t))return r.info(`[stopProcess] Process already stopped: agentId=${e}, pid=${t}`),await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:0,terminated:1,failed:0,message:"Process was already stopped"};if(await this.registry.update(e,{state:"stopping"}),r.debug(`[stopProcess] Level 1: Sending SIGTERM to pid=${t}`),this.sendSigterm(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 1: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:1,terminated:1,failed:0,message:"Process terminated with SIGTERM"};if(r.debug(`[stopProcess] Level 2: Force killing pid=${t}`),this.sendForceKill(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 2: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:2,terminated:1,failed:0,message:"Process terminated with force kill"};r.debug(`[stopProcess] Level 3: Terminating process tree for pid=${t}`);const a=await u(t);return await f(t,5e3)?(await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 3: agentId=${e}, pid=${t}, terminated=${a.terminated}, failed=${a.failed}`),{success:!0,agentId:e,pid:t,level:3,terminated:a.terminated,failed:a.failed,message:`Process tree terminated (${a.terminated} processes)`}):(r.error(`[stopProcess] Level 4: Process is unstoppable: agentId=${e}, pid=${t}`),(p(t)?"still running":"terminated")==="terminated"?(await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:4,terminated:1,failed:0,message:"Process eventually terminated after all escalation levels"}):{success:!1,agentId:e,pid:t,level:4,terminated:a.terminated,failed:a.failed+1,message:"Process could not be terminated - marked as unstoppable"})}sendSigterm(e){try{return process.kill(e,"SIGTERM"),!0}catch(s){return r.debug(`[sendSigterm] Failed to send SIGTERM to ${e}:`,s),!1}}sendForceKill(e){try{return v.platform()==="win32"?R(`taskkill /PID ${e} /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}):process.kill(e,"SIGKILL"),!0}catch(s){return r.debug(`[sendForceKill] Failed to force kill ${e}:`,s),!1}}async forceKill(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;r.info(`[forceKill] Force killing process: agentId=${e}, pid=${t}`),await this.registry.update(e,{state:"stopping"});const i=await u(t);return await f(t,2e3)?(await this.registry.markTerminated(e),r.info(`[forceKill] Process terminated: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed,message:`Process force killed (${i.terminated} processes terminated)`}):(r.error(`[forceKill] Process could not be force killed: agentId=${e}, pid=${t}`),{success:!1,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed+1,message:"Force kill failed - process may require manual intervention"})}async reclaimOrphan(e){if(r.info(`[reclaimOrphan] Attempting to reclaim orphan: agentId=${e}`),this.registry.isManaged(e)){const o=this.registry.get(e);return o?(r.info(`[reclaimOrphan] Process already managed: agentId=${e}, pid=${o.pid}`),{success:!0,pid:o.pid,action:"adopted"}):{success:!1,pid:-1,action:"failed"}}const s=await I(e);if(!s)return r.warn(`[reclaimOrphan] No orphan process found: agentId=${e}`),{success:!1,pid:-1,action:"failed"};if(!p(s.pid))return r.warn(`[reclaimOrphan] Orphan process not running: agentId=${e}, pid=${s.pid}`),{success:!1,pid:s.pid,action:"failed"};if(this.registry.isManagedByPid(s.pid)){const o=this.registry.getByPid(s.pid);if(!o)try{const d=(await $()).find(c=>c.agentId===e);return await this.registry.register({agentId:e,sessionId:d?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:d?.workspacePath||s.cwd||"",command:s.command||d?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),{success:!0,pid:s.pid,action:"adopted"}}catch{return await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}return r.warn(`[reclaimOrphan] PID already managed by different agent: pid=${s.pid}, existingAgentId=${o.agentId}`),o.agentId===e?{success:!0,pid:s.pid,action:"adopted"}:(r.warn(`[reclaimOrphan] Terminating conflicting orphan: agentId=${e}, pid=${s.pid}`),await u(s.pid),{success:!0,pid:s.pid,action:"terminated"})}const i=(await $()).find(o=>o.agentId===e);try{return await this.registry.register({agentId:e,sessionId:i?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:i?.workspacePath||s.cwd||"",command:s.command||i?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),r.info(`[reclaimOrphan] Successfully adopted orphan: agentId=${e}, pid=${s.pid}`),{success:!0,pid:s.pid,action:"adopted"}}catch(o){return r.error(`[reclaimOrphan] Failed to adopt orphan: agentId=${e}, pid=${s.pid}`,o),await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}}async scanAndReclaimAll(){r.info("[scanAndReclaimAll] Scanning for all orphan processes");const e=[],s=await $(),t=await w(),i=new Set(this.registry.getAll().map(a=>a.pid)),o=t.filter(a=>i.has(a.pid)?!1:!!(a.agentId&&!this.registry.isManaged(a.agentId)));r.info(`[scanAndReclaimAll] Found ${o.length} orphan processes`);for(const a of o){if(!a.agentId){r.warn(`[scanAndReclaimAll] Orphan without agentId, terminating: pid=${a.pid}`),await u(a.pid),e.push({agentId:"unknown",pid:a.pid,action:"terminated"});continue}const d=await this.reclaimOrphan(a.agentId);e.push({agentId:a.agentId,pid:d.pid,action:d.action})}for(const a of s)if(a.agentId&&!this.registry.isManaged(a.agentId)&&await I(a.agentId)){const c=await this.reclaimOrphan(a.agentId);e.find(l=>l.agentId===a.agentId)||e.push({agentId:a.agentId,pid:c.pid,action:c.action})}return r.info(`[scanAndReclaimAll] Reclamation complete: ${e.length} processes processed`),e}async markOrphaned(e){return r.info(`[markOrphaned] Marking process as orphaned: agentId=${e}`),await this.registry.markOrphaned(e)}isManaged(e){return this.registry.isManaged(e)}getAllManagedProcesses(){return this.registry.getAll()}getManagedProcessesByState(e){return this.registry.getByState(e)}async getUnmanagedProcesses(){const e=await w(),s=new Set(this.registry.getAll().map(i=>i.pid)),t=new Set(this.registry.getAll().map(i=>i.agentId));return e.filter(i=>!(s.has(i.pid)||i.agentId&&t.has(i.agentId)))}async rebuildRegistry(e){r.info(`[rebuildRegistry] Rebuilding registry from ${e.length} persisted sessions`),await this.registry.clear();for(const t of e){if(!t.pid){r.debug(`[rebuildRegistry] Skipping session without PID: agentId=${t.agentId}`);continue}const i=p(t.pid),o=i?"running":"unknown";try{await this.registry.register({agentId:t.agentId,sessionId:t.sessionId,pid:t.pid,mode:"sdk",state:o,workspacePath:t.workspacePath||"",command:t.command||"",metadata:{rebuiltAt:new Date().toISOString(),wasRunningOnStartup:i}}),r.debug(`[rebuildRegistry] Registered: agentId=${t.agentId}, pid=${t.pid}, state=${o}`)}catch(a){r.warn(`[rebuildRegistry] Failed to register: agentId=${t.agentId}`,a)}}const s=this.registry.getStats();r.info(`[rebuildRegistry] Registry rebuilt: total=${s.total}, running=${s.running}, unknown=${s.unknown}`)}getStats(){return this.registry.getStats()}async cleanupStaleRegistry(){const e=this.registry.getAll();let s=0;for(const t of e)(t.state==="terminated"||t.state==="unknown")&&!p(t.pid)&&(await this.registry.remove(t.agentId),s++,r.debug(`[cleanupStaleRegistry] Removed stale entry: agentId=${t.agentId}, pid=${t.pid}, state=${t.state}`));return s>0&&r.info(`[cleanupStaleRegistry] Cleaned up ${s} stale registry entries`),s}async removeProcess(e){return r.info(`[removeProcess] Removing process from registry: agentId=${e}`),await this.registry.remove(e)}getProcess(e){return this.registry.get(e)}getProcessByPid(e){return this.registry.getByPid(e)}}g.instance=null;function L(){return g.getInstance()}export{g as AgentProcessManager,L as getAgentProcessManager};
|
|
1
|
+
import{execSync as R}from"node:child_process";import v from"node:os";import{createLogger as A}from"../utils/logger.js";import{isProcessRunning as p,isProcessRunningAsync as b,findClaudeCodeProcesses as w,findOrphanProcessByAgentId as I,terminateProcessTree as u,waitForProcessExit as f,checkProcessHealth as O}from"./process-detector.js";import{getProcessRegistry as M}from"./process-registry.js";import{loadPersistedSessions as $}from"./terminal-persistence.js";const r=A("agent-process-manager");async function x(h,e,s){const t=new Array(h.length);let i=0;const o=Math.min(Math.max(e,1),h.length),a=Array.from({length:o},async()=>{for(;i<h.length;){const d=i++;t[d]=await s(h[d])}});return await Promise.all(a),t}class g{constructor(){this.registry=M()}static getInstance(){return g.instance===null&&(g.instance=new g),g.instance}async startProcess(e){const{agentId:s,sessionId:t,pid:i,mode:o,workspacePath:a,command:d}=e;if(r.info(`[startProcess] Starting process: agentId=${s}, pid=${i}, mode=${o}`),await this.registry.register({agentId:s,sessionId:t,pid:i,mode:o,state:"creating",workspacePath:a,command:d}),r.debug(`[startProcess] Verifying process is running: pid=${i}`),!await p(i))throw r.error(`[startProcess] Process not running after registration: agentId=${s}, pid=${i}`),await this.registry.markTerminated(s),new Error(`Process ${i} is not running`);await this.registry.update(s,{state:"running"}),await this.registry.updateHeartbeat(s),r.info(`[startProcess] Process started successfully: agentId=${s}, pid=${i}`)}async discoverAllProcesses(){r.debug("[discoverAllProcesses] Scanning for all agent processes");const e=await w(),s=this.registry.getAll(),t=[],i=new Set(s.map(n=>n.pid)),o=new Set(s.map(n=>n.agentId)),a=new Map(s.map(n=>[n.pid,n]));for(const n of e){const l=i.has(n.pid),P=n.agentId&&o.has(n.agentId),k=a.get(n.pid),m=n.agentId||k?.agentId;if(l||P){const S=s.find(y=>y.pid===n.pid||y.agentId===n.agentId||y.agentId===m);t.push({...n,agentId:m,managementStatus:"managed",sessionId:S?.sessionId})}else m?t.push({...n,agentId:m,managementStatus:"orphan"}):t.push({...n,agentId:m,managementStatus:"unknown"})}const d=s.filter(n=>!t.some(l=>l.pid===n.pid)),c=await x(d,4,async n=>{const l=await b(n.pid);return{pid:n.pid,command:n.command,agentId:n.agentId,managementStatus:l?"managed":"orphan",sessionId:n.sessionId}});return t.push(...c),r.debug(`[discoverAllProcesses] Discovered ${t.length} processes: ${t.filter(n=>n.managementStatus==="managed").length} managed, ${t.filter(n=>n.managementStatus==="orphan").length} orphans, ${t.filter(n=>n.managementStatus==="unknown").length} unknown`),t}async healthCheckAll(){r.debug("[healthCheckAll] Starting health check for all processes");const e=new Map,s=this.registry.getAll(),t=s.map(async i=>{const o=await this.healthCheck(i.agentId);return e.set(i.agentId,o),o});return await Promise.all(t),r.debug(`[healthCheckAll] Completed health check for ${s.length} processes`),e}async healthCheck(e){const s=this.registry.get(e);if(!s)return r.warn(`[healthCheck] Process not found in registry: agentId=${e}`),{pid:-1,agentId:e,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};const t=await O(s.pid,e),i={cpu:t.cpu,memoryMB:t.memoryMB,status:t.status};return await this.registry.updateHealth(e,i),t.alive?await this.registry.updateHeartbeat(e):s.state!=="terminated"&&s.state!=="orphaned"&&(r.warn(`[healthCheck] Process died unexpectedly: agentId=${e}, pid=${s.pid}`),await this.registry.markOrphaned(e)),t}async stopProcess(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;if(r.info(`[stopProcess] Stopping process: agentId=${e}, pid=${t}`),!await p(t))return r.info(`[stopProcess] Process already stopped: agentId=${e}, pid=${t}`),await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:0,terminated:1,failed:0,message:"Process was already stopped"};if(await this.registry.update(e,{state:"stopping"}),r.debug(`[stopProcess] Level 1: Sending SIGTERM to pid=${t}`),this.sendSigterm(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 1: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:1,terminated:1,failed:0,message:"Process terminated with SIGTERM"};if(r.debug(`[stopProcess] Level 2: Force killing pid=${t}`),this.sendForceKill(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 2: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:2,terminated:1,failed:0,message:"Process terminated with force kill"};r.debug(`[stopProcess] Level 3: Terminating process tree for pid=${t}`);const a=await u(t);return await f(t,5e3)?(await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 3: agentId=${e}, pid=${t}, terminated=${a.terminated}, failed=${a.failed}`),{success:!0,agentId:e,pid:t,level:3,terminated:a.terminated,failed:a.failed,message:`Process tree terminated (${a.terminated} processes)`}):(r.error(`[stopProcess] Level 4: Process is unstoppable: agentId=${e}, pid=${t}`),(await p(t)?"still running":"terminated")==="terminated"?(await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:4,terminated:1,failed:0,message:"Process eventually terminated after all escalation levels"}):{success:!1,agentId:e,pid:t,level:4,terminated:a.terminated,failed:a.failed+1,message:"Process could not be terminated - marked as unstoppable"})}sendSigterm(e){try{return process.kill(e,"SIGTERM"),!0}catch(s){return r.debug(`[sendSigterm] Failed to send SIGTERM to ${e}:`,s),!1}}sendForceKill(e){try{return v.platform()==="win32"?R(`taskkill /PID ${e} /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}):process.kill(e,"SIGKILL"),!0}catch(s){return r.debug(`[sendForceKill] Failed to force kill ${e}:`,s),!1}}async forceKill(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;r.info(`[forceKill] Force killing process: agentId=${e}, pid=${t}`),await this.registry.update(e,{state:"stopping"});const i=await u(t);return await f(t,2e3)?(await this.registry.markTerminated(e),r.info(`[forceKill] Process terminated: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed,message:`Process force killed (${i.terminated} processes terminated)`}):(r.error(`[forceKill] Process could not be force killed: agentId=${e}, pid=${t}`),{success:!1,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed+1,message:"Force kill failed - process may require manual intervention"})}async reclaimOrphan(e){if(r.info(`[reclaimOrphan] Attempting to reclaim orphan: agentId=${e}`),this.registry.isManaged(e)){const o=this.registry.get(e);return o?(r.info(`[reclaimOrphan] Process already managed: agentId=${e}, pid=${o.pid}`),{success:!0,pid:o.pid,action:"adopted"}):{success:!1,pid:-1,action:"failed"}}const s=await I(e);if(!s)return r.warn(`[reclaimOrphan] No orphan process found: agentId=${e}`),{success:!1,pid:-1,action:"failed"};if(!await p(s.pid))return r.warn(`[reclaimOrphan] Orphan process not running: agentId=${e}, pid=${s.pid}`),{success:!1,pid:s.pid,action:"failed"};if(this.registry.isManagedByPid(s.pid)){const o=this.registry.getByPid(s.pid);if(!o)try{const d=(await $()).find(c=>c.agentId===e);return await this.registry.register({agentId:e,sessionId:d?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:d?.workspacePath||s.cwd||"",command:s.command||d?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),{success:!0,pid:s.pid,action:"adopted"}}catch{return await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}return r.warn(`[reclaimOrphan] PID already managed by different agent: pid=${s.pid}, existingAgentId=${o.agentId}`),o.agentId===e?{success:!0,pid:s.pid,action:"adopted"}:(r.warn(`[reclaimOrphan] Terminating conflicting orphan: agentId=${e}, pid=${s.pid}`),await u(s.pid),{success:!0,pid:s.pid,action:"terminated"})}const i=(await $()).find(o=>o.agentId===e);try{return await this.registry.register({agentId:e,sessionId:i?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:i?.workspacePath||s.cwd||"",command:s.command||i?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),r.info(`[reclaimOrphan] Successfully adopted orphan: agentId=${e}, pid=${s.pid}`),{success:!0,pid:s.pid,action:"adopted"}}catch(o){return r.error(`[reclaimOrphan] Failed to adopt orphan: agentId=${e}, pid=${s.pid}`,o),await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}}async scanAndReclaimAll(){r.info("[scanAndReclaimAll] Scanning for all orphan processes");const e=[],s=await $(),t=await w(),i=new Set(this.registry.getAll().map(a=>a.pid)),o=t.filter(a=>i.has(a.pid)?!1:!!(a.agentId&&!this.registry.isManaged(a.agentId)));r.info(`[scanAndReclaimAll] Found ${o.length} orphan processes`);for(const a of o){if(!a.agentId){r.warn(`[scanAndReclaimAll] Orphan without agentId, terminating: pid=${a.pid}`),await u(a.pid),e.push({agentId:"unknown",pid:a.pid,action:"terminated"});continue}const d=await this.reclaimOrphan(a.agentId);e.push({agentId:a.agentId,pid:d.pid,action:d.action})}for(const a of s)if(a.agentId&&!this.registry.isManaged(a.agentId)&&await I(a.agentId)){const c=await this.reclaimOrphan(a.agentId);e.find(l=>l.agentId===a.agentId)||e.push({agentId:a.agentId,pid:c.pid,action:c.action})}return r.info(`[scanAndReclaimAll] Reclamation complete: ${e.length} processes processed`),e}async markOrphaned(e){return r.info(`[markOrphaned] Marking process as orphaned: agentId=${e}`),await this.registry.markOrphaned(e)}isManaged(e){return this.registry.isManaged(e)}getAllManagedProcesses(){return this.registry.getAll()}getManagedProcessesByState(e){return this.registry.getByState(e)}async getUnmanagedProcesses(){const e=await w(),s=new Set(this.registry.getAll().map(i=>i.pid)),t=new Set(this.registry.getAll().map(i=>i.agentId));return e.filter(i=>!(s.has(i.pid)||i.agentId&&t.has(i.agentId)))}async rebuildRegistry(e){r.info(`[rebuildRegistry] Rebuilding registry from ${e.length} persisted sessions`),await this.registry.clear();for(const t of e){if(!t.pid){r.debug(`[rebuildRegistry] Skipping session without PID: agentId=${t.agentId}`);continue}const i=await p(t.pid),o=i?"running":"unknown";try{await this.registry.register({agentId:t.agentId,sessionId:t.sessionId,pid:t.pid,mode:"sdk",state:o,workspacePath:t.workspacePath||"",command:t.command||"",metadata:{rebuiltAt:new Date().toISOString(),wasRunningOnStartup:i}}),r.debug(`[rebuildRegistry] Registered: agentId=${t.agentId}, pid=${t.pid}, state=${o}`)}catch(a){r.warn(`[rebuildRegistry] Failed to register: agentId=${t.agentId}`,a)}}const s=this.registry.getStats();r.info(`[rebuildRegistry] Registry rebuilt: total=${s.total}, running=${s.running}, unknown=${s.unknown}`)}getStats(){return this.registry.getStats()}async cleanupStaleRegistry(){const e=this.registry.getAll();let s=0;for(const t of e)(t.state==="terminated"||t.state==="unknown")&&!await p(t.pid)&&(await this.registry.remove(t.agentId),s++,r.debug(`[cleanupStaleRegistry] Removed stale entry: agentId=${t.agentId}, pid=${t.pid}, state=${t.state}`));return s>0&&r.info(`[cleanupStaleRegistry] Cleaned up ${s} stale registry entries`),s}async removeProcess(e){return r.info(`[removeProcess] Removing process from registry: agentId=${e}`),await this.registry.remove(e)}getProcess(e){return this.registry.get(e)}getProcessByPid(e){return this.registry.getByPid(e)}}g.instance=null;function L(){return g.getInstance()}export{g as AgentProcessManager,L as getAgentProcessManager};
|
|
2
2
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{ptySessions as c,createPtySession as p,closePtySession as l}from"../routes/pty.js";const
|
|
2
|
-
`).pop()??"";return!!(/[:?]\s*$/.test(t)||/\((?:yes\/no|Y\/N|y\/n)\)/i.test(t)||/\b[Yy]\/?[Nn]\b/.test(t)||/\(press RETURN\)/i.test(t)||/\(press ENTER\)/i.test(t)||/press ENTER[^]*continue/i.test(t))}class
|
|
3
|
-
`),m=Math.min(Math.max(1,t.lines??200),
|
|
4
|
-
`),needs_input:f,truncated:d}}kill(e){l(e,"agent-kill"),this.cursors.delete(e),this.clearIdle(e)}killByAgent(e){if(!e)return;const t=[];for(const[s,r]of c.entries())r.ownerUserId===e&&t.push(s);for(const s of t){try{l(s,`agent-stop:${e}`)}catch{}this.cursors.delete(s),this.clearIdle(s)}}resize(e,t,s){const r=c.get(e);if(!r)return;const i=typeof t=="number"&&t>0?Math.min(t,u):120,n=typeof s=="number"&&s>0?Math.min(s,u):30;r.ptyProcess.resize(i,n)}touch(e){const t=this.idleTimers.get(e);t&&clearTimeout(t);const s=setTimeout(()=>{l(e,"agent-idle-timeout"),this.cursors.delete(e),this.idleTimers.delete(e)},
|
|
1
|
+
import{ptySessions as c,createPtySession as p,closePtySession as l,readPtyOutputBuffer as y}from"../routes/pty.js";const g=30*60*1e3,T=2e3,u=500;function M(a){const e=a.trimEnd();if(!e)return!1;const t=e.split(`
|
|
2
|
+
`).pop()??"";return!!(/[:?]\s*$/.test(t)||/\((?:yes\/no|Y\/N|y\/n)\)/i.test(t)||/\b[Yy]\/?[Nn]\b/.test(t)||/\(press RETURN\)/i.test(t)||/\(press ENTER\)/i.test(t)||/press ENTER[^]*continue/i.test(t))}class w{constructor(){this.cursors=new Map,this.idleTimers=new Map}create(e){const t=e.shell&&e.shell.trim()?e.shell.trim():"auto",s=typeof e.cols=="number"&&e.cols>0?Math.min(e.cols,u):120,r=typeof e.rows=="number"&&e.rows>0?Math.min(e.rows,u):30,i=e.preCommand&&e.preCommand.trim()?e.preCommand:void 0,n=p({workspacePath:e.cwd,shell:t,cols:s,rows:r,preCommand:i,persistent:!0,ownerUserId:e.agentId}),o=c.get(n.id);return this.cursors.set(n.id,0),this.touch(n.id),{id:n.id,pid:o?.ptyProcess.pid}}write(e,t){const s=c.get(e);!s||s.status==="exited"||(s.ptyProcess.write(t.replace(/\n/g,"\r")),this.touch(e))}read(e,t){const s=c.get(e);if(!s)return{status:"closed",exit_code:null,output:"",needs_input:!1,truncated:!1};this.touch(e);const r=y(s),i=this.cursors.get(e)??0,n=i>=r.length?"":r.slice(i);this.cursors.set(e,r.length);const o=n.split(`
|
|
3
|
+
`),m=Math.min(Math.max(1,t.lines??200),T);let h=o,d=!1;o.length>m&&(h=o.slice(o.length-m),d=!0);const f=s.status==="running"&&M(n);return{status:s.status,exit_code:s.exitCode??null,output:h.join(`
|
|
4
|
+
`),needs_input:f,truncated:d}}kill(e){l(e,"agent-kill"),this.cursors.delete(e),this.clearIdle(e)}killByAgent(e){if(!e)return;const t=[];for(const[s,r]of c.entries())r.ownerUserId===e&&t.push(s);for(const s of t){try{l(s,`agent-stop:${e}`)}catch{}this.cursors.delete(s),this.clearIdle(s)}}resize(e,t,s){const r=c.get(e);if(!r)return;const i=typeof t=="number"&&t>0?Math.min(t,u):120,n=typeof s=="number"&&s>0?Math.min(s,u):30;r.ptyProcess.resize(i,n)}touch(e){const t=this.idleTimers.get(e);t&&clearTimeout(t);const s=setTimeout(()=>{l(e,"agent-idle-timeout"),this.cursors.delete(e),this.idleTimers.delete(e)},g);s.unref?.(),this.idleTimers.set(e,s)}clearIdle(e){const t=this.idleTimers.get(e);t&&clearTimeout(t),this.idleTimers.delete(e)}}const _=new w;export{w as AgentPtyManager,_ as agentPtyManager,M as detectNeedsInput};
|
|
5
5
|
|