aws-runtime-bridge 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter/AdapterRegistry.d.ts +1 -1
  3. package/dist/adapter/AdapterRegistry.d.ts.map +1 -1
  4. package/dist/adapter/AdapterRegistry.js +0 -2
  5. package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
  6. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
  7. package/dist/adapter/ClaudeSdkAdapter.js +11 -2
  8. package/dist/adapter/CodexSdkAdapter.js +1 -1
  9. package/dist/adapter/OpencodeSdkAdapter.js +2 -2
  10. package/dist/adapter/types.d.ts +10 -0
  11. package/dist/adapter/types.d.ts.map +1 -1
  12. package/dist/index.js +14 -43
  13. package/dist/middleware/auth.d.ts +5 -0
  14. package/dist/middleware/auth.d.ts.map +1 -1
  15. package/dist/middleware/auth.js +9 -1
  16. package/dist/routes/file-browser.d.ts.map +1 -1
  17. package/dist/routes/file-browser.js +21 -1
  18. package/dist/routes/file-browser.test.js +9 -0
  19. package/dist/routes/instance.d.ts +10 -0
  20. package/dist/routes/instance.d.ts.map +1 -1
  21. package/dist/routes/instance.js +93 -2
  22. package/dist/routes/instance.test.js +50 -0
  23. package/dist/routes/pty.d.ts +106 -0
  24. package/dist/routes/pty.d.ts.map +1 -0
  25. package/dist/routes/pty.js +526 -0
  26. package/dist/routes/pty.test.d.ts +2 -0
  27. package/dist/routes/pty.test.d.ts.map +1 -0
  28. package/dist/routes/pty.test.js +73 -0
  29. package/dist/routes/sessions.d.ts +1 -1
  30. package/dist/routes/sessions.d.ts.map +1 -1
  31. package/dist/routes/sessions.js +32 -213
  32. package/dist/routes/terminal.d.ts +32 -3
  33. package/dist/routes/terminal.d.ts.map +1 -1
  34. package/dist/routes/terminal.js +411 -243
  35. package/dist/routes/terminal.test.js +105 -29
  36. package/dist/services/agent-process-manager.d.ts +2 -2
  37. package/dist/services/agent-process-manager.d.ts.map +1 -1
  38. package/dist/services/agent-process-manager.js +3 -3
  39. package/dist/services/process-detector.d.ts +2 -4
  40. package/dist/services/process-detector.d.ts.map +1 -1
  41. package/dist/services/process-detector.js +9 -16
  42. package/dist/services/process-registry.d.ts +2 -2
  43. package/dist/services/process-registry.d.ts.map +1 -1
  44. package/dist/services/process-registry.js +1 -1
  45. package/dist/services/session-output.d.ts +15 -5
  46. package/dist/services/session-output.d.ts.map +1 -1
  47. package/dist/services/session-output.js +33 -3
  48. package/dist/services/session-output.test.js +43 -29
  49. package/dist/services/terminal-persistence.d.ts +9 -0
  50. package/dist/services/terminal-persistence.d.ts.map +1 -1
  51. package/dist/services/terminal-persistence.js +20 -0
  52. package/dist/services/tool-installer.d.ts +10 -0
  53. package/dist/services/tool-installer.d.ts.map +1 -1
  54. package/dist/services/tool-installer.js +126 -5
  55. package/dist/services/tool-installer.test.js +32 -1
  56. package/dist/services/workspace-files.d.ts +14 -0
  57. package/dist/services/workspace-files.d.ts.map +1 -1
  58. package/dist/services/workspace-files.js +52 -0
  59. package/dist/services/workspace-files.test.js +85 -1
  60. package/dist/types.d.ts +8 -4
  61. package/dist/types.d.ts.map +1 -1
  62. package/package.json +2 -1
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { SDK_PROVIDER_DEFINITIONS } from '../adapter/SdkProviderSpi.js';
3
- import { resolveSdkProviderId } from './terminal.js';
3
+ import { buildRuntimeEnv, createTerminalOutputDecoder, decodeTerminalOutputChunk, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveTerminalOutputEncoding, resolveSdkProviderId, } from './terminal.js';
4
4
  describe('terminal route validation', () => {
5
5
  it('requires agentId and workspacePath for start', () => {
6
6
  const validateStartRequest = (body) => {
@@ -11,12 +11,32 @@ describe('terminal route validation', () => {
11
11
  expect(validateStartRequest({}).valid).toBe(false);
12
12
  expect(validateStartRequest({ agentId: 'agent-1', workspacePath: '/path' }).valid).toBe(true);
13
13
  });
14
- it('uses default command when not provided', () => {
14
+ it('uses SDK default command when not provided', () => {
15
15
  const resolveCommand = (command) => command || 'claude';
16
16
  expect(resolveCommand(undefined)).toBe('claude');
17
- expect(resolveCommand('custom-cli')).toBe('custom-cli');
17
+ expect(resolveCommand('codex')).toBe('codex');
18
18
  });
19
- it('requires sessionId and input for input', () => {
19
+ it('uses SDK launch mode for unsupported mode values', () => {
20
+ const resolveLaunchMode = (mode) => (mode === 'sdk' ? 'sdk' : 'sdk');
21
+ expect(resolveLaunchMode(undefined)).toBe('sdk');
22
+ expect(resolveLaunchMode('sdk')).toBe('sdk');
23
+ expect(resolveLaunchMode('unsupported')).toBe('sdk');
24
+ });
25
+ it('keeps shortcut mode available for manual key injection', () => {
26
+ const buildInputResponse = (mode) => mode === 'shortcut' ? { ok: true, mode: 'shortcut' } : { ok: true, mode: 'sdk' };
27
+ expect(buildInputResponse('shortcut')).toEqual({ ok: true, mode: 'shortcut' });
28
+ expect(buildInputResponse(undefined)).toEqual({ ok: true, mode: 'sdk' });
29
+ });
30
+ it('does not downgrade unsupported shortcut input to normal SDK messages', () => {
31
+ const buildShortcutFallbackResponse = (hasShortcutSupport) => (hasShortcutSupport
32
+ ? { status: 200, body: { ok: true, mode: 'shortcut' } }
33
+ : { status: 400, body: { error: 'shortcut input is not supported by this SDK provider' } });
34
+ expect(buildShortcutFallbackResponse(false)).toEqual({
35
+ status: 400,
36
+ body: { error: 'shortcut input is not supported by this SDK provider' },
37
+ });
38
+ });
39
+ it('requires sessionId and input for SDK terminal input', () => {
20
40
  const validateInputRequest = (body) => {
21
41
  if (!body.sessionId || body.input === undefined || body.input === null) {
22
42
  return { valid: false, error: 'sessionId and input are required' };
@@ -24,16 +44,11 @@ describe('terminal route validation', () => {
24
44
  return { valid: true };
25
45
  };
26
46
  expect(validateInputRequest({}).valid).toBe(false);
27
- expect(validateInputRequest({ sessionId: 'session-1', input: 'ls' }).valid).toBe(true);
47
+ expect(validateInputRequest({ sessionId: 'session-1', input: 'continue' }).valid).toBe(true);
28
48
  });
29
- it('requires sessionId, cols, and rows for resize', () => {
30
- const validateResizeRequest = (body) => {
31
- if (!body.sessionId || !body.cols || !body.rows)
32
- return { valid: false, error: 'sessionId, cols, rows are required' };
33
- return { valid: true };
34
- };
35
- expect(validateResizeRequest({}).valid).toBe(false);
36
- expect(validateResizeRequest({ sessionId: 'session-1', cols: 120, rows: 30 }).valid).toBe(true);
49
+ it('keeps resize contract as SDK no-op compatibility endpoint', () => {
50
+ const buildResizeResponse = (cols, rows) => ({ ok: true, mode: 'sdk', noop: true, cols, rows });
51
+ expect(buildResizeResponse(120, 30)).toEqual({ ok: true, mode: 'sdk', noop: true, cols: 120, rows: 30 });
37
52
  });
38
53
  it('requires sessionId for stop', () => {
39
54
  const validateStopRequest = (body) => {
@@ -46,26 +61,53 @@ describe('terminal route validation', () => {
46
61
  });
47
62
  });
48
63
  describe('terminal configuration', () => {
49
- it('selects correct shell for platform', () => {
50
- const getShellConfig = (platform) => {
51
- if (platform === 'win32')
52
- return { shell: 'powershell.exe', args: ['-NoLogo'] };
53
- return { shell: 'bash', args: [] };
54
- };
55
- expect(getShellConfig('win32').shell).toBe('powershell.exe');
56
- expect(getShellConfig('linux').shell).toBe('bash');
57
- });
58
- it('builds correct terminal environment', () => {
59
- const buildTerminalEnv = (agentId, baseEnv) => ({
60
- ...baseEnv,
61
- AWS_AGENT_ID: agentId,
62
- AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
63
- });
64
- const env = buildTerminalEnv('agent-123', { PATH: '/usr/bin' });
64
+ it('builds correct SDK runtime environment', () => {
65
+ const env = buildRuntimeEnv('agent-123', undefined, { PATH: '/usr/bin' });
65
66
  expect(env.AWS_AGENT_ID).toBe('agent-123');
66
67
  expect(env.AWS_MCP_LAUNCH_BINDING_ID).toBeUndefined();
67
68
  expect(env.AWS_MCP_CLAIM_LAUNCH_BINDING).toBe('true');
68
69
  });
70
+ it('merges launch env overrides without allowing agent identity override', () => {
71
+ const env = buildRuntimeEnv('agent-123', '/workspace', { PATH: '/usr/bin' }, {
72
+ ANTHROPIC_BASE_URL: ' https://api.example.com ',
73
+ ANTHROPIC_AUTH_TOKEN: 'secret-token',
74
+ ANTHROPIC_MODEL: 'claude-sonnet-4-5',
75
+ AWS_AGENT_ID: 'malicious-agent',
76
+ EMPTY_VALUE: ' ',
77
+ });
78
+ expect(env.ANTHROPIC_BASE_URL).toBe('https://api.example.com');
79
+ expect(env.ANTHROPIC_AUTH_TOKEN).toBe('secret-token');
80
+ expect(env.ANTHROPIC_MODEL).toBe('claude-sonnet-4-5');
81
+ expect(env.EMPTY_VALUE).toBeUndefined();
82
+ expect(env.AWS_AGENT_ID).toBe('agent-123');
83
+ expect(env.AWS_WORKSPACE_PATH).toBe('/workspace');
84
+ });
85
+ });
86
+ describe('terminal command helpers', () => {
87
+ it('normalizes carriage-return terminal input into executable command text', () => {
88
+ expect(normalizeTerminalCommandInput('npm test\r')).toBe('npm test');
89
+ expect(normalizeTerminalCommandInput(' pwd \n')).toBe('pwd');
90
+ });
91
+ it('parses cd commands without treating other shell commands as directory changes', () => {
92
+ expect(parseTerminalDirectoryChangeTarget('cd')).toBeNull();
93
+ expect(parseTerminalDirectoryChangeTarget('cd /d "D:\\code\\repo"')).toBe('D:\\code\\repo');
94
+ expect(parseTerminalDirectoryChangeTarget('npm run build')).toBeUndefined();
95
+ });
96
+ it('formats the working directory prompt as terminal output text', () => {
97
+ expect(formatTerminalPrompt('D:\\code\\repo')).toBe('\x1b[36mD:\\code\\repo>\x1b[0m ');
98
+ });
99
+ it('defaults Windows terminal command output to GB18030 decoding', () => {
100
+ expect(resolveTerminalOutputEncoding('win32', {})).toBe('gb18030');
101
+ expect(resolveTerminalOutputEncoding('linux', {})).toBe('utf-8');
102
+ expect(resolveTerminalOutputEncoding('win32', { AWS_TERMINAL_OUTPUT_ENCODING: 'utf-8' })).toBe('utf-8');
103
+ });
104
+ it('decodes GB18030 Chinese output across chunk boundaries', () => {
105
+ const decoder = createTerminalOutputDecoder('gb18030');
106
+ const first = decodeTerminalOutputChunk(decoder, Buffer.from([0xd6]));
107
+ const second = decodeTerminalOutputChunk(decoder, Buffer.from([0xd0, 0xce, 0xc4]));
108
+ const flushed = decodeTerminalOutputChunk(decoder, undefined, true);
109
+ expect(`${first}${second}${flushed}`).toBe('中文');
110
+ });
69
111
  });
70
112
  describe('resolveSdkProviderId', () => {
71
113
  it('exposes codex through the SDK provider SPI', () => {
@@ -88,3 +130,37 @@ describe('resolveSdkProviderId', () => {
88
130
  expect(resolveSdkProviderId(undefined)).toBe('claude-code');
89
131
  });
90
132
  });
133
+ describe('SDK output forwarding', () => {
134
+ it('formats text and thinking provider events for the terminal output callback path', () => {
135
+ const textEvent = {
136
+ type: 'text_delta',
137
+ sessionId: 'session-1',
138
+ timestamp: new Date(0).toISOString(),
139
+ data: { text: 'hello' },
140
+ };
141
+ const thinkingEvent = {
142
+ type: 'thinking',
143
+ sessionId: 'session-1',
144
+ timestamp: new Date(0).toISOString(),
145
+ data: { text: 'thinking...' },
146
+ };
147
+ expect(formatSdkOutputEvent(textEvent)).toBe('hello');
148
+ expect(formatSdkOutputEvent(thinkingEvent)).toBe('thinking...');
149
+ });
150
+ it('formats SDK errors as terminal output and ignores non-output events', () => {
151
+ const errorEvent = {
152
+ type: 'error',
153
+ sessionId: 'session-1',
154
+ timestamp: new Date(0).toISOString(),
155
+ data: { text: 'boom' },
156
+ };
157
+ const toolEvent = {
158
+ type: 'tool_use_start',
159
+ sessionId: 'session-1',
160
+ timestamp: new Date(0).toISOString(),
161
+ data: { toolName: 'read_file' },
162
+ };
163
+ expect(formatSdkOutputEvent(errorEvent)).toBe('\r\n[SDK Error] boom\r\n');
164
+ expect(formatSdkOutputEvent(toolEvent)).toBeUndefined();
165
+ });
166
+ });
@@ -14,7 +14,7 @@ export interface ProcessConfig {
14
14
  agentId: string;
15
15
  sessionId: string;
16
16
  pid: number;
17
- mode: 'pty' | 'sdk';
17
+ mode: 'sdk';
18
18
  workspacePath: string;
19
19
  command: string;
20
20
  }
@@ -201,7 +201,7 @@ export declare class AgentProcessManager {
201
201
  pid?: number;
202
202
  workspacePath?: string;
203
203
  command?: string;
204
- mode?: 'pty' | 'sdk';
204
+ mode?: 'sdk';
205
205
  }>): Promise<void>;
206
206
  /**
207
207
  * Get process statistics
@@ -1 +1 @@
1
- {"version":3,"file":"agent-process-manager.d.ts","sourceRoot":"","sources":["../../src/services/agent-process-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-process-manager.d.ts","sourceRoot":"","sources":["../../src/services/agent-process-manager.ts"],"names":[],"mappings":"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"}
@@ -482,7 +482,7 @@ export class AgentProcessManager {
482
482
  agentId,
483
483
  sessionId: session?.sessionId || `reclaimed-${Date.now()}`,
484
484
  pid: orphan.pid,
485
- mode: session?.mode || 'sdk',
485
+ mode: 'sdk',
486
486
  state: 'running',
487
487
  workspacePath: session?.workspacePath || orphan.cwd || '',
488
488
  command: orphan.command || session?.command || '',
@@ -521,7 +521,7 @@ export class AgentProcessManager {
521
521
  agentId,
522
522
  sessionId: session?.sessionId || `reclaimed-${Date.now()}`,
523
523
  pid: orphan.pid,
524
- mode: session?.mode || 'sdk',
524
+ mode: 'sdk',
525
525
  state: 'running',
526
526
  workspacePath: session?.workspacePath || orphan.cwd || '',
527
527
  command: orphan.command || session?.command || '',
@@ -696,7 +696,7 @@ export class AgentProcessManager {
696
696
  agentId: session.agentId,
697
697
  sessionId: session.sessionId,
698
698
  pid: session.pid,
699
- mode: session.mode || 'pty',
699
+ mode: 'sdk',
700
700
  state,
701
701
  workspacePath: session.workspacePath || '',
702
702
  command: session.command || '',
@@ -32,9 +32,7 @@ export declare function findClaudeCodeProcesses(): ProcessInfo[];
32
32
  * 检测策略(按优先级):
33
33
  * 1. 通过命令行中的 agentId 直接匹配
34
34
  * 2. Windows: 通过 PowerShell 在命令行中模糊搜索 agentId
35
- * 3. Windows: 通过进程树搜索(解决 PTY 场景下 agentId 仅存在于环境变量的问题)
36
- * PTY 启动链: pty.spawn('powershell.exe', {env: {AWS_AGENT_ID}}) → 用户运行 'claude'
37
- * 此时 claude 是 powershell 子进程,agentId 仅存在于父进程的环境变量中
35
+ * 3. Windows: 通过进程树搜索,覆盖 agentId 仅存在于祖先进程环境变量中的场景
38
36
  *
39
37
  * @param agentId Agent ID
40
38
  * @returns 进程信息或 undefined
@@ -46,7 +44,7 @@ export declare function findOrphanProcessByAgentId(agentId: string): ProcessInfo
46
44
  * 当 agentId 无法匹配到进程时,通过工作目录路径做宽泛搜索。
47
45
  * 适用于以下场景:
48
46
  * - runtime-bridge 重启后持久化会话丢失
49
- * - PTY 模式下 agentId 仅在环境变量中,命令行搜索不到
47
+ * - agentId 可能仅在祖先进程环境变量中,命令行搜索不到
50
48
  * - 进程树断链,无法通过祖先链匹配
51
49
  *
52
50
  * @param workspacePath 工作目录路径
@@ -1 +1 @@
1
- {"version":3,"file":"process-detector.d.ts","sourceRoot":"","sources":["../../src/services/process-detector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process-detector.d.ts","sourceRoot":"","sources":["../../src/services/process-detector.ts"],"names":[],"mappings":"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"}
@@ -241,9 +241,7 @@ function extractAgentId(cmd) {
241
241
  * 检测策略(按优先级):
242
242
  * 1. 通过命令行中的 agentId 直接匹配
243
243
  * 2. Windows: 通过 PowerShell 在命令行中模糊搜索 agentId
244
- * 3. Windows: 通过进程树搜索(解决 PTY 场景下 agentId 仅存在于环境变量的问题)
245
- * PTY 启动链: pty.spawn('powershell.exe', {env: {AWS_AGENT_ID}}) → 用户运行 'claude'
246
- * 此时 claude 是 powershell 子进程,agentId 仅存在于父进程的环境变量中
244
+ * 3. Windows: 通过进程树搜索,覆盖 agentId 仅存在于祖先进程环境变量中的场景
247
245
  *
248
246
  * @param agentId Agent ID
249
247
  * @returns 进程信息或 undefined
@@ -301,18 +299,14 @@ function findProcessByEnvVarWindows(agentId) {
301
299
  return undefined;
302
300
  }
303
301
  /**
304
- * Windows: 通过祖先环境变量搜索孤儿进程(解决 PTY 模式检测问题)
302
+ * Windows: 通过祖先环境变量搜索孤儿进程。
305
303
  *
306
304
  * 场景说明:
307
- * PTY 模式启动 Agent 时,runtime-bridge 执行:
308
- * pty.spawn('powershell.exe', [], { env: { AWS_AGENT_ID: 'agent-xxx' } })
309
- * 然后用户在 shell 中执行 'claude' 命令,产生如下进程树:
310
- * node.exe (runtime-bridge, PID=R)
311
- * └── powershell.exe (PID=A, 有 AWS_AGENT_ID 环境变量)
312
- * └── claude.exe (PID=B, 无 AWS_AGENT_ID, 命令行含 'claude')
305
+ * runtime-bridge 或其子进程可能把 AWS_AGENT_ID 传给 shell/agent 祖先进程,
306
+ * 最终运行的 claude/opencode/codex 进程命令行里不一定包含 agentId。
313
307
  *
314
308
  * 此时:
315
- * - findProcessesWindows() 能找到 claude.exe,但 extractAgentId() 提取不到 agentId
309
+ * - findProcessesWindows() 能找到 agent CLI 进程,但 extractAgentId() 提取不到 agentId
316
310
  * - findProcessByEnvVarWindows() 在命令行中搜不到 agentId(环境变量不在命令行中)
317
311
  *
318
312
  * 策略:用极简 PowerShell 获取全量进程树数据 → 在 Node.js 层做祖先链匹配
@@ -429,8 +423,7 @@ function searchOrphanInProcessTree(rawJson, agentId) {
429
423
  const shellInfo = findAncestorShell(proc.processId);
430
424
  if (shellInfo) {
431
425
  // ★ 验证 agentId:检查 shell 命令行中是否包含目标 agentId
432
- // PTY 模式下,shell 的命令行中不直接包含 agentId,但可以尝试匹配
433
- // 如果无法验证,仍然返回(保持向后兼容)
426
+ // shell 的命令行中不一定直接包含 agentId,但可以尝试匹配。
434
427
  const shellCmdLower = shellInfo.shellCmd.toLowerCase();
435
428
  const cmdLineIncludesAgentId = shellCmdLower.includes(agentId.toLowerCase());
436
429
  if (cmdLineIncludesAgentId) {
@@ -501,7 +494,7 @@ function extractJsonFromOutput(output) {
501
494
  *
502
495
  * Windows 下无法直接读取其他进程的环境变量,但可以通过以下方式间接验证:
503
496
  * 1. 检查进程命令行中是否包含 agentId
504
- * 2. 检查父进程命令行中是否包含 agentId(PTY 模式下环境变量在父进程)
497
+ * 2. 检查父进程命令行中是否包含 agentId
505
498
  * 3. 检查进程的整个祖先链中是否有匹配的 runtime-bridge 启动的 shell
506
499
  *
507
500
  * @param pid 进程 PID
@@ -520,7 +513,7 @@ function verifyProcessAgentId(pid, targetAgentId) {
520
513
  const result = execPowerShell(psScript, 5000).trim();
521
514
  if (result === 'MATCH')
522
515
  return true;
523
- // 策略2:检查父进程命令行是否包含 agentId(PTY 场景)
516
+ // 策略2:检查父进程命令行是否包含 agentId
524
517
  const parentPsScript = `
525
518
  try {
526
519
  $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" -ErrorAction SilentlyContinue
@@ -563,7 +556,7 @@ function verifyProcessAgentId(pid, targetAgentId) {
563
556
  * 当 agentId 无法匹配到进程时,通过工作目录路径做宽泛搜索。
564
557
  * 适用于以下场景:
565
558
  * - runtime-bridge 重启后持久化会话丢失
566
- * - PTY 模式下 agentId 仅在环境变量中,命令行搜索不到
559
+ * - agentId 可能仅在祖先进程环境变量中,命令行搜索不到
567
560
  * - 进程树断链,无法通过祖先链匹配
568
561
  *
569
562
  * @param workspacePath 工作目录路径
@@ -22,7 +22,7 @@ export interface ProcessRecord {
22
22
  agentId: string;
23
23
  sessionId: string;
24
24
  pid: number;
25
- mode: 'pty' | 'sdk';
25
+ mode: 'sdk';
26
26
  state: ProcessState;
27
27
  workspacePath: string;
28
28
  command: string;
@@ -41,7 +41,7 @@ export interface PersistedSessionInput {
41
41
  pid?: number;
42
42
  workspacePath?: string;
43
43
  command?: string;
44
- mode?: 'pty' | 'sdk';
44
+ mode?: 'sdk';
45
45
  }
46
46
  /**
47
47
  * 获取持久化注册表文件路径
@@ -1 +1 @@
1
- {"version":3,"file":"process-registry.d.ts","sourceRoot":"","sources":["../../src/services/process-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;AAEvG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAE/D;;OAEG;IACH,OAAO;IAEP;;;;OAIG;WACW,WAAW,IAAI,eAAe;IAO5C;;OAEG;YACW,OAAO;YAWP,MAAM;IAIpB;;;;;OAKG;IACU,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9E;;;;;;OAMG;IACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBvF;;;;;OAKG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAItD;;;;;OAKG;IACI,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAQvD;;;;OAIG;IACI,MAAM,IAAI,aAAa,EAAE;IAIhC;;;;;OAKG;IACI,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,EAAE;IAIvD;;;;;OAKG;IACI,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI1C;;;;;OAKG;IACI,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI3C;;;;;OAKG;IACU,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB5D;;;;;OAKG;IACU,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe9D;;;;;OAKG;IACU,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBtD;;;;;OAKG;IACU,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe/D;;;;;;OAMG;IACU,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAelF;;;;OAIG;IACU,oBAAoB,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCnF;;;;OAIG;IACI,WAAW,IAAI,aAAa,EAAE;IAIrC;;;;OAIG;IACI,QAAQ,IAAI,MAAM,CAAC,YAAY,GAAG,OAAO,EAAE,MAAM,CAAC;IAkBzD;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CASpC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAU7E;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1F"}
1
+ {"version":3,"file":"process-registry.d.ts","sourceRoot":"","sources":["../../src/services/process-registry.ts"],"names":[],"mappings":"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"}
@@ -280,7 +280,7 @@ export class ProcessRegistry {
280
280
  agentId: session.agentId,
281
281
  sessionId: session.sessionId,
282
282
  pid: session.pid,
283
- mode: session.mode || 'sdk',
283
+ mode: 'sdk',
284
284
  state: 'unknown', // 重建时状态未知,需要外部检测
285
285
  workspacePath: session.workspacePath || '',
286
286
  command: session.command || '',
@@ -4,6 +4,13 @@
4
4
  * 管理终端会话的输出缓冲和刷新机制
5
5
  */
6
6
  import type { Session } from '../types.js';
7
+ interface RuntimeStatusActionInfo {
8
+ actionType?: string;
9
+ actionLabel?: string;
10
+ actionDetail?: string;
11
+ actionResult?: string;
12
+ actionId?: string;
13
+ }
7
14
  /** 活跃会话存储 */
8
15
  export declare const sessions: Map<string, Session>;
9
16
  /**
@@ -14,11 +21,7 @@ export declare const sessions: Map<string, Session>;
14
21
  * @param status - 状态
15
22
  * @param actionInfo - 可选的动作详情
16
23
  */
17
- export declare function sendStatus(agentId: string, sessionId: string | null, status: string, actionInfo?: {
18
- actionType?: string;
19
- actionLabel?: string;
20
- actionDetail?: string;
21
- }, usage?: {
24
+ export declare function sendStatus(agentId: string, sessionId: string | null, status: string, actionInfo?: RuntimeStatusActionInfo, usage?: {
22
25
  inputTokens: number;
23
26
  outputTokens: number;
24
27
  }): Promise<void | {
@@ -53,6 +56,12 @@ export interface RuntimeFileChangedPayload {
53
56
  * 发送工作区文件变更事件到调度器,由调度器通过 WebSocket 通知前端刷新预览。
54
57
  */
55
58
  export declare function sendFileChanged(payload: RuntimeFileChangedPayload): Promise<void>;
59
+ /**
60
+ * 追加会话输出到有界缓冲区。
61
+ *
62
+ * 主流程:拼接新输出 -> 超过上限时丢弃最旧终端噪声并保留截断提示 -> 等待 flush pump 批量发送。
63
+ */
64
+ export declare function appendSessionOutput(sessionId: string, data: string): void;
56
65
  /**
57
66
  * 调度输出刷新
58
67
  *
@@ -65,4 +74,5 @@ export declare function scheduleOutputFlush(sessionId: string): void;
65
74
  * @param sessionId - 会话 ID
66
75
  */
67
76
  export declare function flushSessionOutput(sessionId: string): Promise<void>;
77
+ export {};
68
78
  //# sourceMappingURL=session-output.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAO3C,aAAa;AACb,eAAO,MAAM,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,EACjF,KAAK,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,IAAI,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAyBnC;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
1
+ {"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD,aAAa;AACb,eAAO,MAAM,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,uBAAuB,EACpC,KAAK,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,IAAI,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAuBnC;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/G;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUjH;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBzE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
@@ -10,6 +10,12 @@ function runtimeAuthHeaders() {
10
10
  const token = getRuntimeAccessToken(undefined, schedulerBaseUrl) || getRuntimeAccessToken();
11
11
  return token ? { 'X-Runtime-Token': token } : undefined;
12
12
  }
13
+ /** 输出刷新防抖时间:合并启动期高频小块输出,降低 HTTP/WebSocket 压力。 */
14
+ const OUTPUT_FLUSH_DEBOUNCE_MS = 100;
15
+ /** 单个会话待发送输出上限,避免调度器不可达时内存无限增长。 */
16
+ const MAX_PENDING_OUTPUT_CHARS = 64 * 1024;
17
+ /** 单次回调最大发送量,避免一次 POST 携带过大的终端噪声。 */
18
+ const MAX_OUTPUT_FLUSH_CHARS = 32 * 1024;
13
19
  /** 活跃会话存储 */
14
20
  export const sessions = new Map();
15
21
  /**
@@ -30,6 +36,10 @@ export async function sendStatus(agentId, sessionId, status, actionInfo, usage)
30
36
  payload.actionLabel = actionInfo.actionLabel;
31
37
  if (actionInfo.actionDetail)
32
38
  payload.actionDetail = actionInfo.actionDetail;
39
+ if (actionInfo.actionResult)
40
+ payload.actionResult = actionInfo.actionResult;
41
+ if (actionInfo.actionId)
42
+ payload.actionId = actionInfo.actionId;
33
43
  }
34
44
  // 添加 token 用量信息
35
45
  if (usage) {
@@ -96,6 +106,26 @@ export async function sendFileChanged(payload) {
96
106
  // ignore transient callback failures
97
107
  }
98
108
  }
109
+ /**
110
+ * 追加会话输出到有界缓冲区。
111
+ *
112
+ * 主流程:拼接新输出 -> 超过上限时丢弃最旧终端噪声并保留截断提示 -> 等待 flush pump 批量发送。
113
+ */
114
+ export function appendSessionOutput(sessionId, data) {
115
+ const session = sessions.get(sessionId);
116
+ if (!session || !data) {
117
+ return;
118
+ }
119
+ const combinedOutput = `${session.outputBuffer}${data}`;
120
+ if (combinedOutput.length <= MAX_PENDING_OUTPUT_CHARS) {
121
+ session.outputBuffer = combinedOutput;
122
+ return;
123
+ }
124
+ const omittedChars = combinedOutput.length - MAX_PENDING_OUTPUT_CHARS;
125
+ const marker = `\r\n[AgentsWorkStudio: omitted ${omittedChars} chars of old terminal output]\r\n`;
126
+ const retainedLength = Math.max(0, MAX_PENDING_OUTPUT_CHARS - marker.length);
127
+ session.outputBuffer = `${marker}${combinedOutput.slice(-retainedLength)}`;
128
+ }
99
129
  /**
100
130
  * 调度输出刷新
101
131
  *
@@ -112,7 +142,7 @@ export function scheduleOutputFlush(sessionId) {
112
142
  session.flushTimer = setTimeout(() => {
113
143
  session.flushTimer = null;
114
144
  flushSessionOutput(sessionId).catch(() => undefined);
115
- }, 30);
145
+ }, OUTPUT_FLUSH_DEBOUNCE_MS);
116
146
  }
117
147
  /**
118
148
  * 刷新会话输出
@@ -130,8 +160,8 @@ export async function flushSessionOutput(sessionId) {
130
160
  if (!session.outputBuffer) {
131
161
  return;
132
162
  }
133
- const output = session.outputBuffer;
134
- session.outputBuffer = '';
163
+ const output = session.outputBuffer.slice(0, MAX_OUTPUT_FLUSH_CHARS);
164
+ session.outputBuffer = session.outputBuffer.slice(MAX_OUTPUT_FLUSH_CHARS);
135
165
  const running = (async () => {
136
166
  const seq = session.seq + 1;
137
167
  session.seq = seq;
@@ -1,11 +1,23 @@
1
1
  /**
2
2
  * Session Output 服务单元测试
3
3
  */
4
- import { describe, it, expect } from 'vitest';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { appendSessionOutput, sessions } from './session-output.js';
6
+ const createSession = (overrides = {}) => ({
7
+ agentId: 'agent-1',
8
+ workspacePath: 'D:/workspace',
9
+ outputBuffer: '',
10
+ flushTimer: null,
11
+ flushInFlight: null,
12
+ seq: 0,
13
+ ...overrides,
14
+ });
15
+ afterEach(() => {
16
+ sessions.clear();
17
+ });
5
18
  describe('session-output service', () => {
6
19
  it('manages sessions map correctly', () => {
7
- const sessions = new Map();
8
- sessions.set('session-1', { agentId: 'agent-1', outputBuffer: '' });
20
+ sessions.set('session-1', createSession());
9
21
  expect(sessions.size).toBe(1);
10
22
  expect(sessions.has('session-1')).toBe(true);
11
23
  const session = sessions.get('session-1');
@@ -16,10 +28,8 @@ describe('session-output service', () => {
16
28
  expect(sessions.size).toBe(0);
17
29
  });
18
30
  it('finds session by agentId', () => {
19
- const sessions = new Map([
20
- ['session-1', { agentId: 'agent-1' }],
21
- ['session-2', { agentId: 'agent-2' }],
22
- ]);
31
+ sessions.set('session-1', createSession({ agentId: 'agent-1' }));
32
+ sessions.set('session-2', createSession({ agentId: 'agent-2' }));
23
33
  const findByAgentId = (agentId) => {
24
34
  for (const [id, session] of sessions) {
25
35
  if (session.agentId === agentId)
@@ -31,38 +41,42 @@ describe('session-output service', () => {
31
41
  expect(findByAgentId('agent-3')).toBe(null);
32
42
  });
33
43
  it('accumulates output correctly', () => {
34
- let outputBuffer = '';
35
- const appendOutput = (data) => { outputBuffer += data; };
36
- appendOutput('line1\n');
37
- appendOutput('line2\n');
38
- expect(outputBuffer).toBe('line1\nline2\n');
44
+ sessions.set('session-1', createSession());
45
+ appendSessionOutput('session-1', 'line1\n');
46
+ appendSessionOutput('session-1', 'line2\n');
47
+ expect(sessions.get('session-1')?.outputBuffer).toBe('line1\nline2\n');
39
48
  });
40
- it('clears buffer after flush', () => {
41
- let outputBuffer = 'pending output';
42
- const flushBuffer = () => {
43
- const output = outputBuffer;
44
- outputBuffer = '';
45
- return output;
46
- };
47
- const flushed = flushBuffer();
48
- expect(flushed).toBe('pending output');
49
- expect(outputBuffer).toBe('');
49
+ it('bounds pending SDK output so callback failures cannot grow memory without limit', () => {
50
+ sessions.set('session-bounded', createSession());
51
+ appendSessionOutput('session-bounded', 'a'.repeat(70 * 1024));
52
+ const output = sessions.get('session-bounded')?.outputBuffer ?? '';
53
+ expect(output.length).toBeLessThanOrEqual(64 * 1024);
54
+ expect(output).toContain('AgentsWorkStudio: omitted');
55
+ expect(output.endsWith('a')).toBe(true);
50
56
  });
51
57
  it('increments sequence correctly', () => {
52
- let seq = 0;
53
- const nextSeq = () => { seq += 1; return seq; };
54
- expect(nextSeq()).toBe(1);
55
- expect(nextSeq()).toBe(2);
58
+ const session = createSession();
59
+ sessions.set('session-1', session);
60
+ session.seq += 1;
61
+ expect(session.seq).toBe(1);
62
+ session.seq += 1;
63
+ expect(session.seq).toBe(2);
56
64
  });
57
65
  it('builds correct status payload', () => {
58
66
  const buildStatusPayload = (agentId, sessionId, status) => ({
59
- agentId, sessionId, status
67
+ agentId,
68
+ sessionId,
69
+ status,
60
70
  });
61
71
  expect(buildStatusPayload('agent-1', 'session-1', 'running')).toEqual({
62
- agentId: 'agent-1', sessionId: 'session-1', status: 'running'
72
+ agentId: 'agent-1',
73
+ sessionId: 'session-1',
74
+ status: 'running',
63
75
  });
64
76
  expect(buildStatusPayload('agent-1', null, 'stopped')).toEqual({
65
- agentId: 'agent-1', sessionId: null, status: 'stopped'
77
+ agentId: 'agent-1',
78
+ sessionId: null,
79
+ status: 'stopped',
66
80
  });
67
81
  });
68
82
  });
@@ -28,6 +28,15 @@ export declare function savePersistedSessions(sessions: PersistedSession[]): Pro
28
28
  * @param session - 会话数据
29
29
  */
30
30
  export declare function upsertPersistedSession(session: PersistedSession): Promise<void>;
31
+ /**
32
+ * 更新指定 Agent 的持久化自动命令配置。
33
+ *
34
+ * 主流程:加载 running 会话 -> 命中 agentId 时只替换自动命令字段,保留原 command/workspace/pid。
35
+ */
36
+ export declare function updatePersistedSessionAutoCommands(agentId: string, commands: {
37
+ idleInputAutoCommand: string;
38
+ nonInputAutoCommand: string;
39
+ }): Promise<boolean>;
31
40
  /**
32
41
  * 移除持久化会话(从完整文件中删除,包括 stopped 状态的)
33
42
  *
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-persistence.d.ts","sourceRoot":"","sources":["../../src/services/terminal-persistence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6BpD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAOzE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGvC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF"}
1
+ {"version":3,"file":"terminal-persistence.d.ts","sourceRoot":"","sources":["../../src/services/terminal-persistence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6BpD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAOzE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAED;;;;GAIG;AACH,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE;IAAE,oBAAoB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGvC;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF"}