aws-runtime-bridge 1.7.28 → 1.7.29
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/dist/adapter/ClaudeSdkAdapter.d.ts +5 -0
- package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/ClaudeSdkAdapter.js +20 -6
- package/dist/adapter/ClaudeSdkAdapter.test.js +43 -0
- package/dist/adapter/CodexSdkAdapter.js +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +2 -2
- package/dist/adapter/types.d.ts +13 -4
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/index.js +101 -77
- package/dist/routes/sessions.js +16 -0
- package/dist/routes/terminal.d.ts +19 -1
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +62 -16
- package/dist/routes/terminal.test.js +25 -1
- package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
- package/dist/services/aws-client-agent-mcp.js +22 -3
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +8 -1
- package/dist/services/mcp-launch-binding-queue.test.js +11 -0
- package/dist/services/orphan-monitor.d.ts.map +1 -1
- package/dist/services/orphan-monitor.js +16 -5
- package/dist/services/runtime-binding.d.ts.map +1 -1
- package/dist/services/runtime-binding.js +8 -1
- package/dist/services/runtime-binding.test.js +15 -0
- package/dist/services/runtime-lifecycle-policy.d.ts +26 -0
- package/dist/services/runtime-lifecycle-policy.d.ts.map +1 -0
- package/dist/services/runtime-lifecycle-policy.js +34 -0
- package/dist/services/runtime-lifecycle-policy.test.d.ts +2 -0
- package/dist/services/runtime-lifecycle-policy.test.d.ts.map +1 -0
- package/dist/services/runtime-lifecycle-policy.test.js +41 -0
- package/dist/services/terminal-persistence.d.ts +12 -0
- package/dist/services/terminal-persistence.d.ts.map +1 -1
- package/dist/services/terminal-persistence.js +23 -0
- package/dist/services/terminal-persistence.test.js +18 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +30 -3
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +118 -0
- package/package/aws-client-agent-mcp/dist/agent-client.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.js +10 -1
- package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +10 -0
- package/package/aws-client-agent-mcp/dist/config.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +47 -3
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +344 -9
- package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +4 -3
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +28 -15
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +107 -11
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +26 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package.json +1 -1
|
@@ -120,6 +120,11 @@ export declare class ClaudeSdkAdapter extends EventEmitter implements BaseProvid
|
|
|
120
120
|
private buildQueryOptions;
|
|
121
121
|
private createPermissionHandler;
|
|
122
122
|
private consumeStream;
|
|
123
|
+
/**
|
|
124
|
+
* Apply Claude SDK usage snapshots to the adapter session.
|
|
125
|
+
* Main flow: accept assistant-step or final-result usage, then keep the largest observed totals.
|
|
126
|
+
*/
|
|
127
|
+
private applyUsage;
|
|
123
128
|
private handleSdkMessage;
|
|
124
129
|
private handleToolUse;
|
|
125
130
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/ClaudeSdkAdapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ClaudeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/ClaudeSdkAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -153,7 +153,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
153
153
|
else {
|
|
154
154
|
// 没有初始 prompt,等待用户输入
|
|
155
155
|
session.status = 'waiting_input';
|
|
156
|
-
this.emit('status-change', sessionId, 'waiting_input');
|
|
156
|
+
this.emit('status-change', sessionId, 'waiting_input', { usage: session.totalUsage });
|
|
157
157
|
// 如果有空闲命令配置,立即启动空闲检测
|
|
158
158
|
if (this.idleCommands.has(sessionId)) {
|
|
159
159
|
this.startIdleDetection(sessionId);
|
|
@@ -898,6 +898,20 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
898
898
|
});
|
|
899
899
|
}
|
|
900
900
|
}
|
|
901
|
+
/**
|
|
902
|
+
* Apply Claude SDK usage snapshots to the adapter session.
|
|
903
|
+
* Main flow: accept assistant-step or final-result usage, then keep the largest observed totals.
|
|
904
|
+
*/
|
|
905
|
+
applyUsage(session, usage) {
|
|
906
|
+
if (!usage)
|
|
907
|
+
return;
|
|
908
|
+
if (Number.isFinite(usage.input_tokens)) {
|
|
909
|
+
session.totalUsage.inputTokens = Math.max(session.totalUsage.inputTokens, usage.input_tokens ?? 0);
|
|
910
|
+
}
|
|
911
|
+
if (Number.isFinite(usage.output_tokens)) {
|
|
912
|
+
session.totalUsage.outputTokens = Math.max(session.totalUsage.outputTokens, usage.output_tokens ?? 0);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
901
915
|
handleSdkMessage(sessionId, session, msg) {
|
|
902
916
|
const timestamp = new Date().toISOString();
|
|
903
917
|
// ★ 调试日志:记录所有收到的消息类型
|
|
@@ -952,6 +966,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
952
966
|
actionLabel: actionInfo.actionLabel,
|
|
953
967
|
actionDetail: actionInfo.actionDetail,
|
|
954
968
|
actionId: actionInfo.actionId,
|
|
969
|
+
usage: session.totalUsage,
|
|
955
970
|
});
|
|
956
971
|
if (actionInfo.actionType !== 'idle') {
|
|
957
972
|
this.stopIdleDetection(sessionId);
|
|
@@ -977,10 +992,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
977
992
|
// ★ SDK 的 turn_complete 事件是 'result' 类型
|
|
978
993
|
{
|
|
979
994
|
const isSuccess = msg.subtype === 'success';
|
|
980
|
-
|
|
981
|
-
session.totalUsage.inputTokens = msg.usage.input_tokens || session.totalUsage.inputTokens;
|
|
982
|
-
session.totalUsage.outputTokens = msg.usage.output_tokens || session.totalUsage.outputTokens;
|
|
983
|
-
}
|
|
995
|
+
this.applyUsage(session, msg.usage);
|
|
984
996
|
// 发送 turn_complete 事件
|
|
985
997
|
this.emitEvent(sessionId, {
|
|
986
998
|
type: 'turn_complete',
|
|
@@ -993,7 +1005,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
993
1005
|
});
|
|
994
1006
|
// ★ 更新状态为等待输入
|
|
995
1007
|
session.status = 'waiting_input';
|
|
996
|
-
this.emit('status-change', sessionId, 'waiting_input');
|
|
1008
|
+
this.emit('status-change', sessionId, 'waiting_input', { usage: session.totalUsage });
|
|
997
1009
|
// 如果有空闲命令配置,启动空闲检测
|
|
998
1010
|
if (this.idleCommands.has(sessionId)) {
|
|
999
1011
|
this.startIdleDetection(sessionId);
|
|
@@ -1008,6 +1020,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
1008
1020
|
break;
|
|
1009
1021
|
case 'assistant':
|
|
1010
1022
|
// AI 响应完成,可能包含完整消息
|
|
1023
|
+
this.applyUsage(session, msg.message?.usage);
|
|
1011
1024
|
if (msg.message?.content) {
|
|
1012
1025
|
const textContent = msg.message.content
|
|
1013
1026
|
.filter((c) => c.type === 'text' && c.text)
|
|
@@ -1176,6 +1189,7 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
1176
1189
|
actionLabel: actionInfo.actionLabel,
|
|
1177
1190
|
actionDetail: actionInfo.actionDetail,
|
|
1178
1191
|
actionId: actionInfo.actionId,
|
|
1192
|
+
usage: session.totalUsage,
|
|
1179
1193
|
});
|
|
1180
1194
|
this.stopIdleDetection(sessionId);
|
|
1181
1195
|
// 发送工具调用开始事件(此时有完整参数)
|
|
@@ -242,4 +242,47 @@ describe('ClaudeSdkAdapter', () => {
|
|
|
242
242
|
await vi.advanceTimersByTimeAsync(600);
|
|
243
243
|
expect(sentPrompts).toEqual(['continue']);
|
|
244
244
|
});
|
|
245
|
+
it('applies assistant message usage before final result usage is available', () => {
|
|
246
|
+
const adapter = new ClaudeSdkAdapter();
|
|
247
|
+
const emittedEvents = [];
|
|
248
|
+
const statusChanges = [];
|
|
249
|
+
const session = {
|
|
250
|
+
sessionId: 'session-1',
|
|
251
|
+
status: 'thinking',
|
|
252
|
+
messages: [],
|
|
253
|
+
createdAt: new Date().toISOString(),
|
|
254
|
+
totalUsage: { inputTokens: 0, outputTokens: 0 },
|
|
255
|
+
};
|
|
256
|
+
vi.spyOn(adapter, 'emitEvent')
|
|
257
|
+
.mockImplementation((_sessionId, event) => {
|
|
258
|
+
emittedEvents.push(event);
|
|
259
|
+
});
|
|
260
|
+
vi.spyOn(adapter, 'emit')
|
|
261
|
+
.mockImplementation((_eventName, _sessionId, status, actionInfo) => {
|
|
262
|
+
statusChanges.push({ status, usage: actionInfo?.usage });
|
|
263
|
+
return true;
|
|
264
|
+
});
|
|
265
|
+
const handler = adapter;
|
|
266
|
+
handler.handleSdkMessage('session-1', session, {
|
|
267
|
+
type: 'assistant',
|
|
268
|
+
message: {
|
|
269
|
+
id: 'msg-1',
|
|
270
|
+
usage: { input_tokens: 123, output_tokens: 45 },
|
|
271
|
+
content: [],
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
handler.handleSdkMessage('session-1', session, {
|
|
275
|
+
type: 'result',
|
|
276
|
+
subtype: 'success',
|
|
277
|
+
result: 'done',
|
|
278
|
+
});
|
|
279
|
+
expect(emittedEvents.find((event) => event.type === 'turn_complete')?.data?.usage).toEqual({
|
|
280
|
+
inputTokens: 123,
|
|
281
|
+
outputTokens: 45,
|
|
282
|
+
});
|
|
283
|
+
expect(statusChanges.at(-1)).toEqual({
|
|
284
|
+
status: 'waiting_input',
|
|
285
|
+
usage: { inputTokens: 123, outputTokens: 45 },
|
|
286
|
+
});
|
|
287
|
+
});
|
|
245
288
|
});
|
|
@@ -671,7 +671,7 @@ export class CodexSdkAdapter extends EventEmitter {
|
|
|
671
671
|
timestamp: item.timestamp,
|
|
672
672
|
data: { toolName: item.toolName, toolInput: item.toolInput, toolUseId: item.id, ...actionInfo },
|
|
673
673
|
});
|
|
674
|
-
this.emit('status-change', sessionId, 'tool_using', actionInfo);
|
|
674
|
+
this.emit('status-change', sessionId, 'tool_using', { ...actionInfo, usage: session.adapterSession.totalUsage });
|
|
675
675
|
session.adapterSession.messages.push({
|
|
676
676
|
id: uuidv4(),
|
|
677
677
|
sessionId,
|
|
@@ -194,7 +194,7 @@ export class OpencodeSdkAdapter extends EventEmitter {
|
|
|
194
194
|
// 步骤 6:后台启动 SSE 事件订阅循环
|
|
195
195
|
this.startSseLoop(sessionId, session);
|
|
196
196
|
session.adapterSession.status = 'waiting_input';
|
|
197
|
-
this.emit('status-change', sessionId, 'waiting_input');
|
|
197
|
+
this.emit('status-change', sessionId, 'waiting_input', { usage: session.adapterSession.totalUsage });
|
|
198
198
|
// 步骤 7:发送初始 Prompt
|
|
199
199
|
if (config.initialPrompt) {
|
|
200
200
|
this.dispatchInitialPrompt(sessionId, config.initialPrompt);
|
|
@@ -653,7 +653,7 @@ export class OpencodeSdkAdapter extends EventEmitter {
|
|
|
653
653
|
if (state.status === 'running') {
|
|
654
654
|
emitToolStart();
|
|
655
655
|
const actionInfo = { ...getToolActionInfo(toolName, toolInput, metadata), actionId: toolUseId };
|
|
656
|
-
this.emit('status-change', sessionId, 'tool_using', actionInfo);
|
|
656
|
+
this.emit('status-change', sessionId, 'tool_using', { ...actionInfo, usage: session.adapterSession.totalUsage });
|
|
657
657
|
}
|
|
658
658
|
else if (state.status === 'completed') {
|
|
659
659
|
emitToolStart();
|
package/dist/adapter/types.d.ts
CHANGED
|
@@ -39,6 +39,18 @@ export interface ToolMetadata {
|
|
|
39
39
|
* @param metadata SDK 提供的元数据(可能包含 MCP server 信息)
|
|
40
40
|
*/
|
|
41
41
|
export declare function getToolActionInfo(toolName: string | undefined, toolInput?: Record<string, unknown>, metadata?: ToolMetadata): ToolActionInfo;
|
|
42
|
+
export interface RuntimeTokenUsage {
|
|
43
|
+
inputTokens: number;
|
|
44
|
+
outputTokens: number;
|
|
45
|
+
}
|
|
46
|
+
export interface RuntimeStatusActionInfo {
|
|
47
|
+
actionType?: ToolActionType;
|
|
48
|
+
actionLabel?: string;
|
|
49
|
+
actionDetail?: string;
|
|
50
|
+
actionResult?: string;
|
|
51
|
+
actionId?: string;
|
|
52
|
+
usage?: RuntimeTokenUsage;
|
|
53
|
+
}
|
|
42
54
|
export interface ProviderEvent {
|
|
43
55
|
type: ProviderEventType;
|
|
44
56
|
sessionId: string;
|
|
@@ -55,10 +67,7 @@ export interface ProviderEvent {
|
|
|
55
67
|
/** 工具调用是否出错(tool_use_end) */
|
|
56
68
|
isError?: boolean;
|
|
57
69
|
/** Token 用量(turn_complete) */
|
|
58
|
-
usage?:
|
|
59
|
-
inputTokens: number;
|
|
60
|
-
outputTokens: number;
|
|
61
|
-
};
|
|
70
|
+
usage?: RuntimeTokenUsage;
|
|
62
71
|
/** 退出码(session_complete) */
|
|
63
72
|
exitCode?: number;
|
|
64
73
|
/** 权限请求描述(permission_request) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapter/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,YAAY,GACZ,eAAe,GACf,WAAW,GACX,YAAY,GACZ,OAAO,CAAC;AAIZ,MAAM,MAAM,iBAAiB,GACzB,YAAY,GACZ,UAAU,GACV,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,OAAO,CAAC;AAIZ;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,OAAO,GACP,KAAK,GACL,MAAM,GACN,WAAW,GACX,YAAY,GACZ,WAAW,GACX,MAAM,GACN,QAAQ,GACR,KAAK,GACL,KAAK,GACL,UAAU,GACV,OAAO,CAAC;AAEZ;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,aAAa;IACb,UAAU,EAAE,cAAc,CAAC;IAC3B,iBAAiB;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA6BD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,QAAQ,CAAC,EAAE,YAAY,GACtB,cAAc,CAuPhB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE;QACJ,0CAA0C;QAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,0CAA0C;QAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,kEAAkE;QAClE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,2BAA2B;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,6BAA6B;QAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,8BAA8B;QAC9B,KAAK,CAAC,EAAE
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapter/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import { autoRegister, unregister, bridgeRestartCleanup, } from "./services/auto
|
|
|
34
34
|
import { ensureAwsClientAgentMcpReleased } from "./services/aws-client-agent-mcp.js";
|
|
35
35
|
import { ensureStartupConfig } from "./services/startup-config-wizard.js";
|
|
36
36
|
import { handleCliCommand } from "./services/cli-commands.js";
|
|
37
|
+
import { buildGracefulShutdownPlan, shouldCleanupPersistedSessionsOnStartup, } from "./services/runtime-lifecycle-policy.js";
|
|
37
38
|
const cliCommandResult = await handleCliCommand();
|
|
38
39
|
if (cliCommandResult.handled) {
|
|
39
40
|
process.exit(cliCommandResult.exitCode);
|
|
@@ -76,19 +77,22 @@ async function performAutoRegister() {
|
|
|
76
77
|
}
|
|
77
78
|
performAutoRegister()
|
|
78
79
|
.then(() => {
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
80
|
+
// Bridge 启动后只做非破坏性同步:调度中心会通过 /runtime/sessions 恢复运行态。
|
|
81
|
+
// 不再默认把该 bridge 下的 Agent 标记为 offline/stopped,避免 server/bridge
|
|
82
|
+
// 短暂重启导致正在运行的 Agent 被误停。
|
|
82
83
|
return performBridgeRestartCleanup();
|
|
83
84
|
})
|
|
84
85
|
.catch((err) => {
|
|
85
86
|
logger.warn("[runtime-bridge] 自动注册或清理出错:", err);
|
|
86
87
|
});
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
// 这样可以确保 bridge 重启后,之前启动的 Agent 显示为"离线+停止"状态
|
|
88
|
+
// Bridge 启动状态同步。
|
|
89
|
+
// 默认不清理 Agent 状态;只有显式设置 AWS_BRIDGE_RESTART_CLEANUP=true 时才保留旧行为。
|
|
90
90
|
async function performBridgeRestartCleanup() {
|
|
91
91
|
try {
|
|
92
|
+
if (process.env.AWS_BRIDGE_RESTART_CLEANUP !== "true") {
|
|
93
|
+
logger.info("[runtime-bridge] 跳过 Bridge 重启清理,保留 Agent 状态供调度中心恢复");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
// 只有在已注册的情况下才执行清理
|
|
93
97
|
const { getRegistrationState } = await import("./services/auto-register.js");
|
|
94
98
|
const state = getRegistrationState();
|
|
@@ -96,7 +100,7 @@ async function performBridgeRestartCleanup() {
|
|
|
96
100
|
logger.info("[runtime-bridge] 实例未注册,跳过 Bridge 重启清理");
|
|
97
101
|
return;
|
|
98
102
|
}
|
|
99
|
-
logger.info("[runtime-bridge] ★ Bridge
|
|
103
|
+
logger.info("[runtime-bridge] ★ Bridge 重启清理已显式启用,正在通知调度中心清理 Agent 状态...");
|
|
100
104
|
const result = await bridgeRestartCleanup();
|
|
101
105
|
if (result.success) {
|
|
102
106
|
logger.info(`[runtime-bridge] ★ Bridge 重启清理成功,清理了 ${result.agentCount || 0} 个 Agent`);
|
|
@@ -137,16 +141,16 @@ async function rebuildProcessRegistry() {
|
|
|
137
141
|
rebuildProcessRegistry().catch((err) => {
|
|
138
142
|
logger.warn("[runtime-bridge] 进程注册表重建出错:", err);
|
|
139
143
|
});
|
|
140
|
-
// ★
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
+
// ★ 启动时检测孤儿进程。
|
|
145
|
+
// 默认保留持久化 running 会话并重建进程注册表,避免 runtime-bridge/server
|
|
146
|
+
// 重启误杀仍在运行的 SDK 进程。只有显式设置
|
|
147
|
+
// AWS_BRIDGE_CLEAN_ORPHANS_ON_STARTUP=true 时才执行历史清理逻辑。
|
|
144
148
|
async function detectOrphansOnStartup() {
|
|
145
149
|
try {
|
|
146
150
|
// ★★★ 检查是否存在保留会话标记文件
|
|
147
|
-
const fs = await import("fs/promises");
|
|
148
|
-
const path = await import("path");
|
|
149
|
-
const os = await import("os");
|
|
151
|
+
const fs = await import("node:fs/promises");
|
|
152
|
+
const path = await import("node:path");
|
|
153
|
+
const os = await import("node:os");
|
|
150
154
|
const restartFlagFile = path.join(os.tmpdir(), "agentswork-runtime-bridge", ".preserve-sessions");
|
|
151
155
|
let preserveSessions = false;
|
|
152
156
|
try {
|
|
@@ -165,9 +169,9 @@ async function detectOrphansOnStartup() {
|
|
|
165
169
|
logger.info("[runtime-bridge] 启动时无持久化会话,无需检测孤儿进程");
|
|
166
170
|
return;
|
|
167
171
|
}
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
logger.info(`[runtime-bridge] ★
|
|
172
|
+
const shouldCleanup = shouldCleanupPersistedSessionsOnStartup(preserveSessions);
|
|
173
|
+
if (!shouldCleanup) {
|
|
174
|
+
logger.info(`[runtime-bridge] ★ 保留 ${persistedSessions.length} 个持久化会话并重建进程注册表`);
|
|
171
175
|
// 重建进程注册表
|
|
172
176
|
const manager = getAgentProcessManager();
|
|
173
177
|
await manager.rebuildRegistry(persistedSessions.map((s) => ({
|
|
@@ -180,8 +184,7 @@ async function detectOrphansOnStartup() {
|
|
|
180
184
|
})));
|
|
181
185
|
return;
|
|
182
186
|
}
|
|
183
|
-
logger.info(`[runtime-bridge] ★
|
|
184
|
-
// bridge 重启 = 整个运行环境重启,所有 agent 都应该被终止
|
|
187
|
+
logger.info(`[runtime-bridge] ★ 已显式启用启动清理,检测 ${persistedSessions.length} 个持久化会话的孤儿进程...`);
|
|
185
188
|
const orphans = detectOrphanProcesses(persistedSessions.map((s) => ({
|
|
186
189
|
agentId: s.agentId,
|
|
187
190
|
pid: s.pid,
|
|
@@ -200,7 +203,7 @@ async function detectOrphansOnStartup() {
|
|
|
200
203
|
if (orphan.process.pid) {
|
|
201
204
|
// 使用跨平台方式终止进程
|
|
202
205
|
if (process.platform === "win32") {
|
|
203
|
-
const { execSync } = await import("child_process");
|
|
206
|
+
const { execSync } = await import("node:child_process");
|
|
204
207
|
execSync(`taskkill /PID ${orphan.process.pid} /T /F`, {
|
|
205
208
|
encoding: "utf8",
|
|
206
209
|
timeout: 3000,
|
|
@@ -221,10 +224,8 @@ async function detectOrphansOnStartup() {
|
|
|
221
224
|
// 等待进程完全终止
|
|
222
225
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
223
226
|
}
|
|
224
|
-
// ★★★ 修复:bridge 重启后清空所有持久化会话
|
|
225
|
-
// 不再保留任何会话,因为所有 agent 都应该被清理
|
|
226
227
|
await savePersistedSessions([]);
|
|
227
|
-
logger.info(`[runtime-bridge] ★
|
|
228
|
+
logger.info(`[runtime-bridge] ★ 启动清理完成,已清空所有持久化会话(清理了 ${orphans.length} 个孤儿进程)`);
|
|
228
229
|
}
|
|
229
230
|
catch (error) {
|
|
230
231
|
const err = error;
|
|
@@ -319,86 +320,109 @@ async function gracefulShutdown(signal, server, preserveSessions = false) {
|
|
|
319
320
|
}
|
|
320
321
|
logger.info(`[runtime-bridge] 收到 ${signal} 信号,开始优雅关闭... (preserveSessions=${preserveSessions})`);
|
|
321
322
|
const startTime = Date.now();
|
|
323
|
+
const shutdownPlan = buildGracefulShutdownPlan(preserveSessions);
|
|
322
324
|
try {
|
|
323
325
|
// 1. 停止所有 SDK 会话
|
|
324
326
|
const sdkCount = sdkSessions.size;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const providerId = entry.providerId || "claude-code";
|
|
329
|
-
const adapter = adapterRegistry.get(providerId);
|
|
330
|
-
// 尝试获取 PID 用于日志
|
|
331
|
-
let pidInfo = "";
|
|
327
|
+
if (shutdownPlan.terminateSdkSessions) {
|
|
328
|
+
logger.info(`[runtime-bridge] 正在停止 ${sdkCount} 个 SDK 会话...`);
|
|
329
|
+
for (const [sessionId, entry] of sdkSessions.entries()) {
|
|
332
330
|
try {
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
331
|
+
const providerId = entry.providerId || "claude-code";
|
|
332
|
+
const adapter = adapterRegistry.get(providerId);
|
|
333
|
+
// 尝试获取 PID 用于日志
|
|
334
|
+
let pidInfo = "";
|
|
335
|
+
try {
|
|
336
|
+
const pid = adapter.getSessionPid?.(sessionId);
|
|
337
|
+
if (pid) {
|
|
338
|
+
pidInfo = ` (PID: ${pid})`;
|
|
339
|
+
}
|
|
336
340
|
}
|
|
341
|
+
catch {
|
|
342
|
+
// 忽略 PID 获取错误
|
|
343
|
+
}
|
|
344
|
+
await adapter.terminateSession(sessionId);
|
|
345
|
+
logger.info(`[runtime-bridge] SDK 会话 ${sessionId} 已终止${pidInfo}`);
|
|
346
|
+
sdkSessions.delete(sessionId);
|
|
337
347
|
}
|
|
338
|
-
catch {
|
|
339
|
-
|
|
348
|
+
catch (e) {
|
|
349
|
+
const err = e;
|
|
350
|
+
logger.error(`[runtime-bridge] SDK 会话 ${sessionId} 终止失败:`, err.message);
|
|
351
|
+
// 即使失败也从内存中移除
|
|
352
|
+
sdkSessions.delete(sessionId);
|
|
340
353
|
}
|
|
341
|
-
await adapter.terminateSession(sessionId);
|
|
342
|
-
logger.info(`[runtime-bridge] SDK 会话 ${sessionId} 已终止${pidInfo}`);
|
|
343
|
-
sdkSessions.delete(sessionId);
|
|
344
|
-
}
|
|
345
|
-
catch (e) {
|
|
346
|
-
const err = e;
|
|
347
|
-
logger.error(`[runtime-bridge] SDK 会话 ${sessionId} 终止失败:`, err.message);
|
|
348
|
-
// 即使失败也从内存中移除
|
|
349
|
-
sdkSessions.delete(sessionId);
|
|
350
354
|
}
|
|
351
355
|
}
|
|
356
|
+
else {
|
|
357
|
+
logger.info(`[runtime-bridge] ★ 保留 ${sdkCount} 个 SDK 会话,不在重启恢复场景中终止 Agent 进程`);
|
|
358
|
+
}
|
|
352
359
|
const ptyCount = ptySessions.size;
|
|
353
|
-
|
|
354
|
-
|
|
360
|
+
if (shutdownPlan.closePtySessions) {
|
|
361
|
+
logger.info(`[runtime-bridge] 正在停止 ${ptyCount} 个 PTY 会话...`);
|
|
362
|
+
closeAllPtySessions("shutdown");
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
logger.info(`[runtime-bridge] ★ 保留 ${ptyCount} 个 PTY 会话,不在重启恢复场景中关闭终端进程`);
|
|
366
|
+
}
|
|
355
367
|
// 3. 停止孤儿进程监控
|
|
356
368
|
logger.info("[runtime-bridge] 正在停止孤儿进程监控...");
|
|
357
369
|
stopOrphanMonitor();
|
|
358
370
|
// 4. ★ 验证所有进程已终止(等待一小段时间让进程完全退出)
|
|
359
|
-
|
|
360
|
-
|
|
371
|
+
if (shutdownPlan.terminateResidualProcesses) {
|
|
372
|
+
logger.info("[runtime-bridge] 等待进程完全终止...");
|
|
373
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
374
|
+
}
|
|
361
375
|
// 5. 检查是否还有残留进程,如果有则强制终止
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
if (shutdownPlan.terminateResidualProcesses) {
|
|
377
|
+
try {
|
|
378
|
+
const { detectOrphanProcesses, terminateProcessTree } = await import("./services/process-detector.js");
|
|
379
|
+
const { loadPersistedSessions } = await import("./services/terminal-persistence.js");
|
|
380
|
+
const persistedSessions = await loadPersistedSessions();
|
|
381
|
+
if (persistedSessions.length > 0) {
|
|
382
|
+
const orphans = detectOrphanProcesses(persistedSessions.map((s) => ({
|
|
383
|
+
agentId: s.agentId,
|
|
384
|
+
pid: s.pid,
|
|
385
|
+
workspacePath: s.workspacePath,
|
|
386
|
+
command: s.command,
|
|
387
|
+
})));
|
|
388
|
+
if (orphans.length > 0) {
|
|
389
|
+
logger.warn(`[runtime-bridge] 检测到 ${orphans.length} 个残留进程,正在强制终止...`);
|
|
390
|
+
for (const orphan of orphans) {
|
|
391
|
+
if (orphan.process.pid) {
|
|
392
|
+
// 使用进程树终止(跨平台)
|
|
393
|
+
const result = terminateProcessTree(orphan.process.pid);
|
|
394
|
+
logger.info(`[runtime-bridge] 已强制终止残留进程树:agentId=${orphan.agentId}, PID=${orphan.process.pid}, 终止了 ${result.terminated} 个进程`);
|
|
395
|
+
}
|
|
380
396
|
}
|
|
381
397
|
}
|
|
382
398
|
}
|
|
383
399
|
}
|
|
400
|
+
catch (checkError) {
|
|
401
|
+
const err = checkError;
|
|
402
|
+
logger.warn("[runtime-bridge] 残留进程检查失败:", err.message);
|
|
403
|
+
}
|
|
384
404
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
logger.warn("[runtime-bridge] 残留进程检查失败:", err.message);
|
|
405
|
+
else {
|
|
406
|
+
logger.info("[runtime-bridge] ★ 保留模式跳过残留进程强制终止,等待调度中心恢复会话");
|
|
388
407
|
}
|
|
389
408
|
// 6. 注销实例
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
409
|
+
if (shutdownPlan.unregisterInstance) {
|
|
410
|
+
logger.info("[runtime-bridge] 正在注销实例...");
|
|
411
|
+
try {
|
|
412
|
+
await unregister();
|
|
413
|
+
}
|
|
414
|
+
catch (e) {
|
|
415
|
+
const err = e;
|
|
416
|
+
logger.error("[runtime-bridge] 注销实例失败:", err.message);
|
|
417
|
+
}
|
|
393
418
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
logger.error("[runtime-bridge] 注销实例失败:", err.message);
|
|
419
|
+
else {
|
|
420
|
+
logger.info("[runtime-bridge] ★ 保留模式跳过实例注销,避免调度中心将 Agent 标记为 stopped");
|
|
397
421
|
}
|
|
398
422
|
// 7. ★★★ 修复:根据 preserveSessions 决定是否清空持久化状态
|
|
399
423
|
// - preserveSessions=true (aws-mcp-server 触发): 保留会话状态,aws-mcp-server 重启后可恢复
|
|
400
424
|
// - preserveSessions=false (bridge 自己关闭): 清空所有会话,agent 应被清理
|
|
401
|
-
if (
|
|
425
|
+
if (shutdownPlan.clearPersistedSessions) {
|
|
402
426
|
logger.info("[runtime-bridge] 正在清空持久化会话状态...");
|
|
403
427
|
try {
|
|
404
428
|
await savePersistedSessions([]);
|
|
@@ -483,7 +507,7 @@ process.on("uncaughtException", (error) => {
|
|
|
483
507
|
// ★ 未捕获异常时不检查标记文件 — 异常重启需要完整清理
|
|
484
508
|
gracefulShutdown("uncaughtException", server);
|
|
485
509
|
});
|
|
486
|
-
process.on("unhandledRejection", (reason
|
|
510
|
+
process.on("unhandledRejection", (reason) => {
|
|
487
511
|
logger.error("[runtime-bridge] 未处理的 Promise 拒绝:", reason);
|
|
488
512
|
// 不立即退出,只记录错误
|
|
489
513
|
});
|
package/dist/routes/sessions.js
CHANGED
|
@@ -25,6 +25,10 @@ sessionsRouter.get('/sessions', validateToken, async (_req, res) => {
|
|
|
25
25
|
agentId: entry.agentId,
|
|
26
26
|
workspacePath: entry.workspacePath,
|
|
27
27
|
status: 'running',
|
|
28
|
+
runtimeStatus: entry.currentRuntimeStatus,
|
|
29
|
+
runtimeActionType: entry.currentRuntimeActionType,
|
|
30
|
+
runtimeActionLabel: entry.currentRuntimeActionLabel,
|
|
31
|
+
runtimeActionDetail: entry.currentRuntimeActionDetail,
|
|
28
32
|
mode: 'sdk',
|
|
29
33
|
startedAt: null,
|
|
30
34
|
}));
|
|
@@ -69,6 +73,10 @@ sessionsRouter.post('/sessions/recover', validateToken, async (req, res) => {
|
|
|
69
73
|
workspacePath: existingSdkSession[1].workspacePath,
|
|
70
74
|
command: existingSdkSession[1].config.command,
|
|
71
75
|
status: 'running',
|
|
76
|
+
runtimeStatus: existingSdkSession[1].currentRuntimeStatus,
|
|
77
|
+
runtimeActionType: existingSdkSession[1].currentRuntimeActionType,
|
|
78
|
+
runtimeActionLabel: existingSdkSession[1].currentRuntimeActionLabel,
|
|
79
|
+
runtimeActionDetail: existingSdkSession[1].currentRuntimeActionDetail,
|
|
72
80
|
mode: 'sdk',
|
|
73
81
|
recovered: false,
|
|
74
82
|
message: 'SDK session already active',
|
|
@@ -112,6 +120,10 @@ sessionsRouter.post('/sessions/recover', validateToken, async (req, res) => {
|
|
|
112
120
|
workspacePath: resolvedWorkspacePath,
|
|
113
121
|
command: resolvedCommand,
|
|
114
122
|
status: 'orphan_detected',
|
|
123
|
+
runtimeStatus: persistedSession?.runtimeStatus,
|
|
124
|
+
runtimeActionType: persistedSession?.runtimeActionType,
|
|
125
|
+
runtimeActionLabel: persistedSession?.runtimeActionLabel,
|
|
126
|
+
runtimeActionDetail: persistedSession?.runtimeActionDetail,
|
|
115
127
|
recovered: false,
|
|
116
128
|
orphan: {
|
|
117
129
|
pid: orphanPid,
|
|
@@ -358,6 +370,10 @@ sessionsRouter.get('/sessions/by-agent/:agentId', validateToken, async (req, res
|
|
|
358
370
|
workspacePath: persistedSession.workspacePath,
|
|
359
371
|
command: persistedSession.command,
|
|
360
372
|
status: isProcessAlive ? 'orphan' : 'stopped',
|
|
373
|
+
runtimeStatus: persistedSession.runtimeStatus,
|
|
374
|
+
runtimeActionType: persistedSession.runtimeActionType,
|
|
375
|
+
runtimeActionLabel: persistedSession.runtimeActionLabel,
|
|
376
|
+
runtimeActionDetail: persistedSession.runtimeActionDetail,
|
|
361
377
|
startedAt: persistedSession.startedAt,
|
|
362
378
|
isActive: false,
|
|
363
379
|
mode: persistedSession.mode,
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* 终端 UI 仅作为 SDK Agent 的消息输入/状态输出载体
|
|
6
6
|
*/
|
|
7
7
|
import { TextDecoder } from 'node:util';
|
|
8
|
-
import { type AdapterSessionConfig, type ProviderEvent } from '../adapter/index.js';
|
|
8
|
+
import { type AdapterSessionConfig, type ProviderEvent, type RuntimeStatusActionInfo } from '../adapter/index.js';
|
|
9
|
+
import type { PersistedSession } from '../types.js';
|
|
9
10
|
export declare const terminalRouter: import("express-serve-static-core").Router;
|
|
10
11
|
export interface SdkSessionEntry {
|
|
11
12
|
agentId: string;
|
|
@@ -14,8 +15,16 @@ export interface SdkSessionEntry {
|
|
|
14
15
|
config: AdapterSessionConfig;
|
|
15
16
|
providerId: string;
|
|
16
17
|
seq: number;
|
|
18
|
+
currentRuntimeStatus?: string;
|
|
19
|
+
currentRuntimeActionType?: string;
|
|
20
|
+
currentRuntimeActionLabel?: string;
|
|
21
|
+
currentRuntimeActionDetail?: string;
|
|
17
22
|
}
|
|
18
23
|
export declare const sdkSessions: Map<string, SdkSessionEntry>;
|
|
24
|
+
export declare function resolveStatusChangeUsage(actionInfo?: RuntimeStatusActionInfo): {
|
|
25
|
+
inputTokens: number;
|
|
26
|
+
outputTokens: number;
|
|
27
|
+
} | undefined;
|
|
19
28
|
/**
|
|
20
29
|
* 标准化终端输入:将前端回车符还原为 shell 可执行命令文本。
|
|
21
30
|
*/
|
|
@@ -37,6 +46,15 @@ export declare function decodeTerminalOutputChunk(decoder: TextDecoder, chunk?:
|
|
|
37
46
|
* 解析 cd 命令目标;返回 undefined 表示不是目录切换命令,null 表示仅查看当前目录。
|
|
38
47
|
*/
|
|
39
48
|
export declare function parseTerminalDirectoryChangeTarget(command: string): string | null | undefined;
|
|
49
|
+
export interface PersistedSessionReuseDecision {
|
|
50
|
+
reusable: boolean;
|
|
51
|
+
reason: 'active-pid' | 'missing-pid' | 'dead-pid';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 判断持久化 SDK 会话能否在显式启动请求中复用。
|
|
55
|
+
* 主流程:必须存在 PID 且 OS 仍能确认该进程存活;否则视为重启后遗留的陈旧会话。
|
|
56
|
+
*/
|
|
57
|
+
export declare function evaluatePersistedSessionReuse(session: Pick<PersistedSession, 'pid'>, isPidRunning?: (pid: number) => boolean): PersistedSessionReuseDecision;
|
|
40
58
|
/**
|
|
41
59
|
* 生成显示在终端输出流中的工作目录提示符。
|
|
42
60
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/routes/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAKxC,OAAO,EAEL,KAAK,oBAAoB,EAEzB,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/routes/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAKxC,OAAO,EAEL,KAAK,oBAAoB,EAEzB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAI7B,MAAM,qBAAqB,CAAC;AAc7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,cAAc,4CAAW,CAAC;AAIvC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAGD,eAAO,MAAM,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAa,CAAC;AAKnE,wBAAgB,wBAAwB,CAAC,UAAU,CAAC,EAAE,uBAAuB;;;cAS5E;AAaD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpE;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,SAAkC,GAAG,WAAW,CAMnG;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,CAQnG;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAiB7F;AA2CD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,YAAY,GAAG,aAAa,GAAG,UAAU,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,EACtC,YAAY,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAA0B,GACxD,6BAA6B,CAU/B;AA4BD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAErE;AAyGD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,CAAC,UAAU,EAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+BxB;AA8BD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAU7E;AAYD,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|