aws-runtime-bridge 1.7.48 → 1.7.50

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 (166) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +77 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -0
  3. package/dist/adapter/AcodeSdkAdapter.js +322 -0
  4. package/dist/adapter/AcodeSdkAdapter.test.d.ts +2 -0
  5. package/dist/adapter/AcodeSdkAdapter.test.d.ts.map +1 -0
  6. package/dist/adapter/AcodeSdkAdapter.test.js +273 -0
  7. package/dist/adapter/AdapterRegistry.d.ts +1 -1
  8. package/dist/adapter/AdapterRegistry.d.ts.map +1 -1
  9. package/dist/adapter/AdapterRegistry.js +2 -0
  10. package/dist/adapter/AdapterRegistry.test.js +10 -1
  11. package/dist/adapter/SdkProviderSpi.d.ts.map +1 -1
  12. package/dist/adapter/SdkProviderSpi.js +10 -1
  13. package/dist/adapter/index.d.ts +1 -0
  14. package/dist/adapter/index.d.ts.map +1 -1
  15. package/dist/adapter/index.js +1 -0
  16. package/dist/adapters/cc-switch/index.d.ts +2 -0
  17. package/dist/adapters/cc-switch/index.d.ts.map +1 -1
  18. package/dist/adapters/cc-switch/index.js +6 -0
  19. package/dist/adapters/cc-switch/mcp-acode.d.ts +17 -0
  20. package/dist/adapters/cc-switch/mcp-acode.d.ts.map +1 -0
  21. package/dist/adapters/cc-switch/mcp-acode.js +71 -0
  22. package/dist/adapters/cc-switch/mcp-acode.test.d.ts +2 -0
  23. package/dist/adapters/cc-switch/mcp-acode.test.d.ts.map +1 -0
  24. package/dist/adapters/cc-switch/mcp-acode.test.js +80 -0
  25. package/dist/adapters/cc-switch/mcp-claude.d.ts.map +1 -1
  26. package/dist/adapters/cc-switch/mcp-claude.js +1 -0
  27. package/dist/adapters/cc-switch/mcp-claudecode.d.ts.map +1 -1
  28. package/dist/adapters/cc-switch/mcp-claudecode.js +1 -0
  29. package/dist/adapters/cc-switch/mcp-claudecode.test.js +1 -0
  30. package/dist/adapters/cc-switch/mcp-codex.d.ts.map +1 -1
  31. package/dist/adapters/cc-switch/mcp-codex.js +1 -0
  32. package/dist/adapters/cc-switch/mcp-codex.test.js +1 -0
  33. package/dist/adapters/cc-switch/mcp-opencode.d.ts.map +1 -1
  34. package/dist/adapters/cc-switch/mcp-opencode.js +1 -0
  35. package/dist/adapters/cc-switch/mcp-opencode.test.js +1 -0
  36. package/dist/adapters/cc-switch/skill-acode.d.ts +11 -0
  37. package/dist/adapters/cc-switch/skill-acode.d.ts.map +1 -0
  38. package/dist/adapters/cc-switch/skill-acode.js +12 -0
  39. package/dist/adapters/cc-switch/skill-directory.test.js +1 -0
  40. package/dist/config.d.ts +4 -0
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +10 -0
  43. package/dist/index.js +2 -0
  44. package/dist/routes/ai-sources.js +3 -2
  45. package/dist/routes/instance.js +1 -1
  46. package/dist/routes/instance.test.js +2 -1
  47. package/dist/routes/mcp.js +2 -2
  48. package/dist/routes/mcp.test.js +2 -1
  49. package/dist/routes/runtime-binding.d.ts +3 -2
  50. package/dist/routes/runtime-binding.d.ts.map +1 -1
  51. package/dist/routes/runtime-binding.js +9 -56
  52. package/dist/routes/runtime-binding.test.js +4 -80
  53. package/dist/routes/sessions.d.ts +5 -0
  54. package/dist/routes/sessions.d.ts.map +1 -1
  55. package/dist/routes/sessions.js +36 -16
  56. package/dist/routes/sessions.test.js +13 -0
  57. package/dist/routes/skills.js +2 -2
  58. package/dist/routes/skills.test.js +2 -1
  59. package/dist/routes/terminal.d.ts +24 -4
  60. package/dist/routes/terminal.d.ts.map +1 -1
  61. package/dist/routes/terminal.js +99 -10
  62. package/dist/routes/terminal.test.js +74 -8
  63. package/dist/services/acode-package.d.ts +8 -0
  64. package/dist/services/acode-package.d.ts.map +1 -0
  65. package/dist/services/acode-package.js +82 -0
  66. package/dist/services/ai-source-apply.d.ts +4 -0
  67. package/dist/services/ai-source-apply.d.ts.map +1 -1
  68. package/dist/services/ai-source-apply.js +38 -9
  69. package/dist/services/ai-source-apply.test.js +58 -1
  70. package/dist/services/cc-switch-sdk.d.ts.map +1 -1
  71. package/dist/services/cc-switch-sdk.js +9 -1
  72. package/dist/services/instance-init-service.d.ts.map +1 -1
  73. package/dist/services/instance-init-service.js +3 -2
  74. package/dist/services/instance-init-service.test.js +6 -5
  75. package/dist/services/instance-service.d.ts.map +1 -1
  76. package/dist/services/instance-service.js +1 -0
  77. package/dist/services/instance-state.js +1 -1
  78. package/dist/services/instance-state.test.js +4 -4
  79. package/dist/services/tool-installer.d.ts.map +1 -1
  80. package/dist/services/tool-installer.js +10 -0
  81. package/dist/types.d.ts +5 -0
  82. package/dist/types.d.ts.map +1 -1
  83. package/dist/utils/file-utils.d.ts.map +1 -1
  84. package/dist/utils/file-utils.js +1 -0
  85. package/dist/utils/mcp-utils.d.ts.map +1 -1
  86. package/dist/utils/mcp-utils.js +4 -1
  87. package/dist/utils/validation.js +1 -1
  88. package/node_modules/@cc-switch/sdk/dist/constants.d.ts.map +1 -1
  89. package/node_modules/@cc-switch/sdk/dist/constants.js +7 -0
  90. package/node_modules/@cc-switch/sdk/dist/schemas.d.ts.map +1 -1
  91. package/node_modules/@cc-switch/sdk/dist/schemas.js +1 -0
  92. package/node_modules/@cc-switch/sdk/dist/sdk.d.ts.map +1 -1
  93. package/node_modules/@cc-switch/sdk/dist/sdk.js +7 -3
  94. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.d.ts +7 -0
  95. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.d.ts.map +1 -1
  96. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.js +29 -2
  97. package/node_modules/@cc-switch/sdk/dist/types.d.ts +4 -1
  98. package/node_modules/@cc-switch/sdk/dist/types.d.ts.map +1 -1
  99. package/package/acode/README.md +88 -0
  100. package/package/acode/dist/built-in-file-tools.d.ts +16 -0
  101. package/package/acode/dist/built-in-file-tools.d.ts.map +1 -0
  102. package/package/acode/dist/built-in-file-tools.js +231 -0
  103. package/package/acode/dist/cli.d.ts +3 -0
  104. package/package/acode/dist/cli.d.ts.map +1 -0
  105. package/package/acode/dist/cli.js +37 -0
  106. package/package/acode/dist/commands/commandLoader.d.ts +7 -0
  107. package/package/acode/dist/commands/commandLoader.d.ts.map +1 -0
  108. package/package/acode/dist/commands/commandLoader.js +33 -0
  109. package/package/acode/dist/commands/commandParser.d.ts +7 -0
  110. package/package/acode/dist/commands/commandParser.d.ts.map +1 -0
  111. package/package/acode/dist/commands/commandParser.js +77 -0
  112. package/package/acode/dist/commands/commandRegistry.d.ts +13 -0
  113. package/package/acode/dist/commands/commandRegistry.d.ts.map +1 -0
  114. package/package/acode/dist/commands/commandRegistry.js +30 -0
  115. package/package/acode/dist/config.d.ts +4 -0
  116. package/package/acode/dist/config.d.ts.map +1 -0
  117. package/package/acode/dist/config.js +80 -0
  118. package/package/acode/dist/hooks/hookBus.d.ts +19 -0
  119. package/package/acode/dist/hooks/hookBus.d.ts.map +1 -0
  120. package/package/acode/dist/hooks/hookBus.js +40 -0
  121. package/package/acode/dist/index.d.ts +8 -0
  122. package/package/acode/dist/index.d.ts.map +1 -0
  123. package/package/acode/dist/index.js +7 -0
  124. package/package/acode/dist/runtime.d.ts +34 -0
  125. package/package/acode/dist/runtime.d.ts.map +1 -0
  126. package/package/acode/dist/runtime.js +571 -0
  127. package/package/acode/dist/types.d.ts +99 -0
  128. package/package/acode/dist/types.d.ts.map +1 -0
  129. package/package/acode/dist/types.js +1 -0
  130. package/package/acode/package.json +24 -0
  131. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +4 -4
  132. package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
  133. package/package/aws-client-agent-mcp/dist/agent-client.js +9 -6
  134. package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
  135. package/package/aws-client-agent-mcp/dist/agent-client.test.js +21 -0
  136. package/package/aws-client-agent-mcp/dist/agent-client.test.js.map +1 -1
  137. package/package/aws-client-agent-mcp/dist/http-client.d.ts +1 -17
  138. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
  139. package/package/aws-client-agent-mcp/dist/http-client.js +7 -113
  140. package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
  141. package/package/aws-client-agent-mcp/dist/http-client.test.js +22 -2
  142. package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
  143. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -5
  144. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
  145. package/package/aws-client-agent-mcp/dist/mcp-server.js +1 -23
  146. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
  147. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +89 -6
  148. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
  149. package/package/aws-client-agent-mcp/dist/types.d.ts +3 -0
  150. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
  151. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +0 -13
  152. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
  153. package/package/aws-client-agent-mcp/dist/websocket-client.js +3 -100
  154. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
  155. package/package/cc-switch-sdk/dist/constants.d.ts.map +1 -1
  156. package/package/cc-switch-sdk/dist/constants.js +7 -0
  157. package/package/cc-switch-sdk/dist/schemas.d.ts.map +1 -1
  158. package/package/cc-switch-sdk/dist/schemas.js +1 -0
  159. package/package/cc-switch-sdk/dist/sdk.d.ts.map +1 -1
  160. package/package/cc-switch-sdk/dist/sdk.js +7 -3
  161. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts +7 -0
  162. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts.map +1 -1
  163. package/package/cc-switch-sdk/dist/services/ai-config-service.js +29 -2
  164. package/package/cc-switch-sdk/dist/types.d.ts +4 -1
  165. package/package/cc-switch-sdk/dist/types.d.ts.map +1 -1
  166. package/package.json +8 -4
@@ -1,6 +1,9 @@
1
+ import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
1
4
  import { describe, expect, it } from 'vitest';
2
5
  import { SDK_PROVIDER_DEFINITIONS } from '../adapter/SdkProviderSpi.js';
3
- import { buildRuntimeEnv, buildToolResultTimelineActionInfo, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveStatusChangeUsage, } from './terminal.js';
6
+ import { buildClaudeCodeLaunchConfig, buildRuntimeEnv, buildToolResultTimelineActionInfo, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveSdkInputMessage, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveSdkSessionDisplayStatus, resolveStatusChangeUsage, } from './terminal.js';
4
7
  describe('terminal route validation', () => {
5
8
  it('requires agentId and workspacePath for start', () => {
6
9
  const validateStartRequest = (body) => {
@@ -12,8 +15,8 @@ describe('terminal route validation', () => {
12
15
  expect(validateStartRequest({ agentId: 'agent-1', workspacePath: '/path' }).valid).toBe(true);
13
16
  });
14
17
  it('uses SDK default command when not provided', () => {
15
- const resolveCommand = (command) => command || 'claude';
16
- expect(resolveCommand(undefined)).toBe('claude');
18
+ const resolveCommand = (command) => command || 'acode';
19
+ expect(resolveCommand(undefined)).toBe('acode');
17
20
  expect(resolveCommand('codex')).toBe('codex');
18
21
  });
19
22
  it('uses SDK launch mode for unsupported mode values', () => {
@@ -82,6 +85,41 @@ describe('terminal configuration', () => {
82
85
  expect(env.AWS_AGENT_ID).toBe('agent-123');
83
86
  expect(env.AWS_WORKSPACE_PATH).toBe('/workspace');
84
87
  });
88
+ it('merges saved ClaudeCode AI settings into SDK launch env with request overrides taking precedence', () => {
89
+ const launchConfig = buildClaudeCodeLaunchConfig({
90
+ env: {
91
+ ANTHROPIC_BASE_URL: 'https://saved.example.com',
92
+ ANTHROPIC_AUTH_TOKEN: 'sk-saved',
93
+ ANTHROPIC_MODEL: 'claude-saved',
94
+ EMPTY_SAVED: ' ',
95
+ },
96
+ }, {
97
+ ANTHROPIC_MODEL: ' claude-request ',
98
+ EXTRA_VALUE: 'enabled',
99
+ });
100
+ expect(launchConfig).toEqual({
101
+ envOverrides: {
102
+ ANTHROPIC_BASE_URL: 'https://saved.example.com',
103
+ ANTHROPIC_AUTH_TOKEN: 'sk-saved',
104
+ ANTHROPIC_MODEL: 'claude-request',
105
+ EXTRA_VALUE: 'enabled',
106
+ },
107
+ model: 'claude-request',
108
+ });
109
+ });
110
+ it('uses CODEX_MODEL from request env overrides as SDK launch model', () => {
111
+ const launchConfig = buildClaudeCodeLaunchConfig(null, {
112
+ OPENAI_API_KEY: 'sk-codex',
113
+ CODEX_MODEL: ' gpt-5.3-codex ',
114
+ });
115
+ expect(launchConfig).toEqual({
116
+ envOverrides: {
117
+ OPENAI_API_KEY: 'sk-codex',
118
+ CODEX_MODEL: 'gpt-5.3-codex',
119
+ },
120
+ model: 'gpt-5.3-codex',
121
+ });
122
+ });
85
123
  });
86
124
  describe('persisted SDK session reuse', () => {
87
125
  it('does not reuse a persisted session without a PID', () => {
@@ -92,12 +130,40 @@ describe('persisted SDK session reuse', () => {
92
130
  const decision = evaluatePersistedSessionReuse({ pid: 1234 }, () => false);
93
131
  expect(decision).toEqual({ reusable: false, reason: 'dead-pid' });
94
132
  });
95
- it('reuses a persisted session only when its PID is still running', () => {
96
- const decision = evaluatePersistedSessionReuse({ pid: 1234 }, () => true);
133
+ it('reuses a persisted session only when its PID is still running for externally controllable providers', () => {
134
+ const decision = evaluatePersistedSessionReuse({ pid: 1234, command: 'claude' }, () => true);
97
135
  expect(decision).toEqual({ reusable: true, reason: 'active-pid' });
98
136
  });
137
+ it('does not reuse ACode persisted sessions because their control channel is in-process only', () => {
138
+ const decision = evaluatePersistedSessionReuse({ pid: 1234, command: 'acode' }, () => true);
139
+ expect(decision).toEqual({ reusable: false, reason: 'in-process-provider' });
140
+ });
141
+ });
142
+ describe('SDK session display status', () => {
143
+ it('prefers adapter fine-grained status over coarse running fallback', () => {
144
+ expect(resolveSdkSessionDisplayStatus('waiting_input', 'running')).toBe('waiting_input');
145
+ expect(resolveSdkSessionDisplayStatus('thinking', 'running')).toBe('thinking');
146
+ });
147
+ it('uses in-memory runtime status when adapter status is temporarily unavailable', () => {
148
+ expect(resolveSdkSessionDisplayStatus(undefined, 'tool_using')).toBe('tool_using');
149
+ });
150
+ it('falls back to running only when no fine-grained state exists', () => {
151
+ expect(resolveSdkSessionDisplayStatus(undefined, undefined)).toBe('running');
152
+ });
99
153
  });
100
154
  describe('terminal command helpers', () => {
155
+ it('expands a whole mini-term clipboard paste file path into SDK input content', async () => {
156
+ const tempDir = await mkdtemp(path.join(os.tmpdir(), 'terminal-input-'));
157
+ const clipboardDir = path.join(tempDir, 'mini-term-clipboard');
158
+ await mkdir(clipboardDir, { recursive: true });
159
+ const pasteFile = path.join(clipboardDir, 'paste-1780491671137.txt');
160
+ await writeFile(pasteFile, 'real pasted prompt', 'utf-8');
161
+ await expect(resolveSdkInputMessage(`"${pasteFile}"`)).resolves.toBe('real pasted prompt');
162
+ });
163
+ it('keeps explicit commands that mention mini-term clipboard files unchanged', async () => {
164
+ const command = 'type "C:\\Users\\ZHUANG~1\\AppData\\Local\\Temp\\mini-term-clipboard\\paste-1780491671137.txt"';
165
+ await expect(resolveSdkInputMessage(command)).resolves.toBe(command);
166
+ });
101
167
  it('normalizes carriage-return terminal input into executable command text', () => {
102
168
  expect(normalizeTerminalCommandInput('npm test\r')).toBe('npm test');
103
169
  expect(normalizeTerminalCommandInput(' pwd \n')).toBe('pwd');
@@ -138,10 +204,10 @@ describe('resolveSdkProviderId', () => {
138
204
  it('resolves opencode commands to opencode provider', () => {
139
205
  expect(resolveSdkProviderId('opencode')).toBe('opencode');
140
206
  });
141
- it('falls back to claude-code for claude or unknown commands', () => {
207
+ it('falls back to acode for unknown or empty commands while keeping claude mapped to claude-code', () => {
142
208
  expect(resolveSdkProviderId('claude')).toBe('claude-code');
143
- expect(resolveSdkProviderId('custom-binary')).toBe('claude-code');
144
- expect(resolveSdkProviderId(undefined)).toBe('claude-code');
209
+ expect(resolveSdkProviderId('custom-binary')).toBe('acode');
210
+ expect(resolveSdkProviderId(undefined)).toBe('acode');
145
211
  });
146
212
  });
147
213
  describe('SDK status usage forwarding', () => {
@@ -0,0 +1,8 @@
1
+ export declare function getReleasedAcodeEntryPath(): string;
2
+ /**
3
+ * 释放随 bridge 打包的内置 ACode runtime。
4
+ * 主流程:检查 bundled dist -> 复制 dist 与 metadata -> 链接 bridge node_modules,
5
+ * 确保 ACode 无需安装即可被 Adapter 动态加载。
6
+ */
7
+ export declare function ensureAcodePackageReleased(): string | null;
8
+ //# sourceMappingURL=acode-package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acode-package.d.ts","sourceRoot":"","sources":["../../src/services/acode-package.ts"],"names":[],"mappings":"AAyDA,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,GAAG,IAAI,CAwB1D"}
@@ -0,0 +1,82 @@
1
+ import { existsSync, mkdirSync, rmSync, cpSync, symlinkSync, lstatSync, realpathSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getRuntimeHomeDir } from '../config.js';
5
+ import { logger } from '../utils/logger.js';
6
+ function getBridgePackageRoot() {
7
+ const currentFile = fileURLToPath(import.meta.url);
8
+ return path.resolve(path.dirname(currentFile), '..', '..');
9
+ }
10
+ function getBundledAcodeRoot(packageRoot = getBridgePackageRoot()) {
11
+ return path.join(packageRoot, 'package', 'acode');
12
+ }
13
+ function getReleasedAcodeRoot() {
14
+ return path.join(getRuntimeHomeDir(), '.agentswork', 'runtime-bridge', 'packages', 'acode');
15
+ }
16
+ function shouldReplaceNodeModulesLink(targetPath) {
17
+ if (!existsSync(targetPath)) {
18
+ return true;
19
+ }
20
+ const stat = lstatSync(targetPath);
21
+ return stat.isSymbolicLink() || stat.isDirectory();
22
+ }
23
+ function isExpectedNodeModulesLink(targetPath, sourcePath) {
24
+ if (!existsSync(targetPath)) {
25
+ return false;
26
+ }
27
+ try {
28
+ return realpathSync(targetPath) === realpathSync(sourcePath);
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ function ensureReleasedNodeModules(packageRoot, releasedRoot) {
35
+ const sourceNodeModules = path.join(packageRoot, 'node_modules');
36
+ const releasedNodeModules = path.join(releasedRoot, 'node_modules');
37
+ if (!existsSync(sourceNodeModules)) {
38
+ logger.warn(`[runtime-bridge] ACode 未找到 bridge node_modules,依赖解析可能失败: ${sourceNodeModules}`);
39
+ return;
40
+ }
41
+ if (isExpectedNodeModulesLink(releasedNodeModules, sourceNodeModules)) {
42
+ return;
43
+ }
44
+ if (!shouldReplaceNodeModulesLink(releasedNodeModules)) {
45
+ logger.warn(`[runtime-bridge] ACode node_modules 路径已存在但不是目录或链接,已保留: ${releasedNodeModules}`);
46
+ return;
47
+ }
48
+ rmSync(releasedNodeModules, { recursive: true, force: true });
49
+ symlinkSync(sourceNodeModules, releasedNodeModules, process.platform === 'win32' ? 'junction' : 'dir');
50
+ }
51
+ export function getReleasedAcodeEntryPath() {
52
+ return path.join(getReleasedAcodeRoot(), 'dist', 'index.js');
53
+ }
54
+ /**
55
+ * 释放随 bridge 打包的内置 ACode runtime。
56
+ * 主流程:检查 bundled dist -> 复制 dist 与 metadata -> 链接 bridge node_modules,
57
+ * 确保 ACode 无需安装即可被 Adapter 动态加载。
58
+ */
59
+ export function ensureAcodePackageReleased() {
60
+ const packageRoot = getBridgePackageRoot();
61
+ const bundledRoot = getBundledAcodeRoot(packageRoot);
62
+ const bundledDist = path.join(bundledRoot, 'dist');
63
+ const bundledEntry = path.join(bundledDist, 'index.js');
64
+ if (!existsSync(bundledEntry)) {
65
+ logger.warn(`[runtime-bridge] 未找到 bundled ACode dist,ACode 启动可能失败: ${bundledEntry}`);
66
+ return null;
67
+ }
68
+ const releasedRoot = getReleasedAcodeRoot();
69
+ const releasedDist = path.join(releasedRoot, 'dist');
70
+ mkdirSync(releasedRoot, { recursive: true });
71
+ rmSync(releasedDist, { recursive: true, force: true });
72
+ cpSync(bundledDist, releasedDist, { recursive: true, force: true, errorOnExist: false });
73
+ for (const fileName of ['package.json', 'README.md']) {
74
+ const source = path.join(bundledRoot, fileName);
75
+ if (existsSync(source)) {
76
+ cpSync(source, path.join(releasedRoot, fileName), { force: true, errorOnExist: false });
77
+ }
78
+ }
79
+ ensureReleasedNodeModules(packageRoot, releasedRoot);
80
+ logger.info(`[runtime-bridge] ACode 已准备: ${getReleasedAcodeEntryPath()}`);
81
+ return getReleasedAcodeEntryPath();
82
+ }
@@ -7,11 +7,13 @@ export interface AiSourceTemplateInput {
7
7
  models?: unknown;
8
8
  }
9
9
  export interface RequestedAiSources {
10
+ acode?: unknown;
10
11
  claudecode?: unknown;
11
12
  codex?: unknown;
12
13
  opencode?: unknown;
13
14
  }
14
15
  export interface AiConfigApplier {
16
+ applyAcodeConfig(config: OpenCodeConfig): Promise<OpenCodeConfig>;
15
17
  applyClaudeCodeConfig(config: ClaudeCodeConfig): Promise<ClaudeCodeConfig>;
16
18
  applyCodexConfig(config: CodexConfig): Promise<CodexConfig>;
17
19
  applyOpenCodeConfig(config: OpenCodeConfig): Promise<OpenCodeConfig>;
@@ -25,12 +27,14 @@ export interface ApplyCurrentAiConfigOptions {
25
27
  export interface AppliedAiConfigSummary {
26
28
  generatedFromUnifiedTemplate: boolean;
27
29
  applied: {
30
+ acode: string[];
28
31
  claudecode: string[];
29
32
  codex: string[];
30
33
  opencode: string[];
31
34
  };
32
35
  skippedTools: string[];
33
36
  merged: {
37
+ acode: OpenCodeConfig | null;
34
38
  claudecode: ClaudeCodeConfig | null;
35
39
  codex: CodexConfig | null;
36
40
  opencode: OpenCodeConfig | null;
@@ -1 +1 @@
1
- {"version":3,"file":"ai-source-apply.d.ts","sourceRoot":"","sources":["../../src/services/ai-source-apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3E,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5D,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IACnD,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC9C,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,4BAA4B,EAAE,OAAO,CAAC;IACtC,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE;QACN,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACpC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;KACjC,CAAC;CACH;AAqBD;;GAEG;AACH,wBAAsB,oCAAoC,CACxD,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,sBAAsB,CAAC,CAsCjC"}
1
+ {"version":3,"file":"ai-source-apply.d.ts","sourceRoot":"","sources":["../../src/services/ai-source-apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3E,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5D,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IACnD,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC9C,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,4BAA4B,EAAE,OAAO,CAAC;IACtC,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE;QACN,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;QAC7B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACpC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;KACjC,CAAC;CACH;AAuCD;;GAEG;AACH,wBAAsB,oCAAoC,CACxD,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,sBAAsB,CAAC,CA6DjC"}
@@ -15,6 +15,21 @@ function isInstalled(toolStatus, tool) {
15
15
  function isClaudeCodeInstalled(toolStatus) {
16
16
  return isInstalled(toolStatus, 'claude') || isInstalled(toolStatus, 'claudecode');
17
17
  }
18
+ function isRecord(value) {
19
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
20
+ }
21
+ function hasConfigContent(value) {
22
+ return Object.keys(value).length > 0;
23
+ }
24
+ /**
25
+ * 具体逻辑:将服务端已生成的 per-tool AI 配置规范化为可应用 patch,空对象视为未配置。
26
+ */
27
+ function normalizeRequestedConfig(value) {
28
+ if (!isRecord(value) || !hasConfigContent(value)) {
29
+ return null;
30
+ }
31
+ return value;
32
+ }
18
33
  /**
19
34
  * 主流程:用当前统一 AI 配置覆盖各 Agent CLI 配置,并跳过未安装 CLI。
20
35
  */
@@ -22,30 +37,44 @@ export async function applyCurrentAiConfigToInstalledTools(options) {
22
37
  const generatedConfig = options.template
23
38
  ? buildToolSpecificAiConfig(normalizeTemplate(options.template))
24
39
  : null;
40
+ const requestedAcodeConfig = normalizeRequestedConfig(options.requestedSources?.acode);
41
+ const requestedClaudeConfig = normalizeRequestedConfig(options.requestedSources?.claudecode);
42
+ const requestedCodexConfig = normalizeRequestedConfig(options.requestedSources?.codex);
43
+ const requestedOpenCodeConfig = normalizeRequestedConfig(options.requestedSources?.opencode);
44
+ const acodeConfig = generatedConfig?.acode || requestedAcodeConfig;
45
+ const claudeConfig = generatedConfig?.claudecode || requestedClaudeConfig;
46
+ const codexConfig = generatedConfig?.codex || requestedCodexConfig;
47
+ const openCodeConfig = generatedConfig?.opencode || requestedOpenCodeConfig;
25
48
  const skippedTools = Object.values(options.toolStatus)
26
49
  .filter((item) => !item.installed)
27
50
  .map((item) => item.tool);
51
+ let mergedAcode = null;
28
52
  let mergedClaude = null;
29
53
  let mergedCodex = null;
30
54
  let mergedOpencode = null;
31
- if (generatedConfig?.claudecode && isClaudeCodeInstalled(options.toolStatus)) {
32
- mergedClaude = await options.aiConfigService.applyClaudeCodeConfig(generatedConfig.claudecode);
55
+ if (acodeConfig && isInstalled(options.toolStatus, 'acode')) {
56
+ mergedAcode = await options.aiConfigService.applyAcodeConfig(acodeConfig);
57
+ }
58
+ if (claudeConfig && isClaudeCodeInstalled(options.toolStatus)) {
59
+ mergedClaude = await options.aiConfigService.applyClaudeCodeConfig(claudeConfig);
33
60
  }
34
- if (generatedConfig?.codex && isInstalled(options.toolStatus, 'codex')) {
35
- mergedCodex = await options.aiConfigService.applyCodexConfig(generatedConfig.codex);
61
+ if (codexConfig && isInstalled(options.toolStatus, 'codex')) {
62
+ mergedCodex = await options.aiConfigService.applyCodexConfig(codexConfig);
36
63
  }
37
- if (generatedConfig?.opencode && isInstalled(options.toolStatus, 'opencode')) {
38
- mergedOpencode = await options.aiConfigService.applyOpenCodeConfig(generatedConfig.opencode);
64
+ if (openCodeConfig && isInstalled(options.toolStatus, 'opencode')) {
65
+ mergedOpencode = await options.aiConfigService.applyOpenCodeConfig(openCodeConfig);
39
66
  }
40
67
  return {
41
68
  generatedFromUnifiedTemplate: Boolean(generatedConfig),
42
69
  applied: {
43
- claudecode: generatedConfig?.claudecode && mergedClaude ? Object.keys(generatedConfig.claudecode) : [],
44
- codex: generatedConfig?.codex && mergedCodex ? Object.keys(generatedConfig.codex) : [],
45
- opencode: generatedConfig?.opencode && mergedOpencode ? Object.keys(generatedConfig.opencode) : [],
70
+ acode: acodeConfig && mergedAcode ? Object.keys(acodeConfig) : [],
71
+ claudecode: claudeConfig && mergedClaude ? Object.keys(claudeConfig) : [],
72
+ codex: codexConfig && mergedCodex ? Object.keys(codexConfig) : [],
73
+ opencode: openCodeConfig && mergedOpencode ? Object.keys(openCodeConfig) : [],
46
74
  },
47
75
  skippedTools,
48
76
  merged: {
77
+ acode: mergedAcode,
49
78
  claudecode: mergedClaude,
50
79
  codex: mergedCodex,
51
80
  opencode: mergedOpencode,
@@ -14,6 +14,7 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
14
14
  const applyClaudeCodeConfig = vi.fn(async (config) => config);
15
15
  const applyCodexConfig = vi.fn(async (config) => config);
16
16
  const applyOpenCodeConfig = vi.fn(async (config) => config);
17
+ const applyAcodeConfig = vi.fn(async (config) => config);
17
18
  const { applyCurrentAiConfigToInstalledTools } = await import('./ai-source-apply.js');
18
19
  const result = await applyCurrentAiConfigToInstalledTools({
19
20
  template: {
@@ -27,11 +28,13 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
27
28
  opencode: { provider: { default: { options: { baseURL: 'https://stale.example.com/v1' } } } },
28
29
  },
29
30
  toolStatus: {
31
+ acode: status('acode', true),
30
32
  claude: status('claude', true),
31
33
  codex: status('codex', false),
32
34
  opencode: status('opencode', true),
33
35
  },
34
36
  aiConfigService: {
37
+ applyAcodeConfig,
35
38
  applyClaudeCodeConfig,
36
39
  applyCodexConfig,
37
40
  applyOpenCodeConfig,
@@ -48,6 +51,7 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
48
51
  expect(applyOpenCodeConfig).toHaveBeenCalledWith(expect.objectContaining({
49
52
  provider: expect.objectContaining({
50
53
  default: expect.objectContaining({
54
+ model: 'gpt-current',
51
55
  options: expect.objectContaining({
52
56
  baseURL: 'https://current.example.com/v1',
53
57
  apiKey: 'sk-current',
@@ -55,9 +59,10 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
55
59
  }),
56
60
  }),
57
61
  }));
62
+ expect(applyAcodeConfig).toHaveBeenCalledOnce();
58
63
  expect(result.applied.codex).toEqual([]);
59
64
  expect(result.skippedTools).toEqual(['codex']);
60
- });
65
+ }, 15_000);
61
66
  it('applies Claude Code config when the installed tool status uses the claudecode alias', async () => {
62
67
  const applyClaudeCodeConfig = vi.fn(async (config) => config);
63
68
  const { applyCurrentAiConfigToInstalledTools } = await import('./ai-source-apply.js');
@@ -71,6 +76,7 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
71
76
  claudecode: status('claudecode', true),
72
77
  },
73
78
  aiConfigService: {
79
+ applyAcodeConfig: vi.fn(async (config) => config),
74
80
  applyClaudeCodeConfig,
75
81
  applyCodexConfig: vi.fn(async (config) => config),
76
82
  applyOpenCodeConfig: vi.fn(async (config) => config),
@@ -78,4 +84,55 @@ describe('applyCurrentAiConfigToInstalledTools', () => {
78
84
  });
79
85
  expect(applyClaudeCodeConfig).toHaveBeenCalledOnce();
80
86
  });
87
+ it('applies explicit per-tool AI sources when no unified template is present', async () => {
88
+ const applyClaudeCodeConfig = vi.fn(async (config) => config);
89
+ const applyCodexConfig = vi.fn(async (config) => config);
90
+ const applyOpenCodeConfig = vi.fn(async (config) => config);
91
+ const applyAcodeConfig = vi.fn(async (config) => config);
92
+ const { applyCurrentAiConfigToInstalledTools } = await import('./ai-source-apply.js');
93
+ const result = await applyCurrentAiConfigToInstalledTools({
94
+ template: null,
95
+ requestedSources: {
96
+ claudecode: {
97
+ env: {
98
+ ANTHROPIC_BASE_URL: 'https://explicit.example.com',
99
+ ANTHROPIC_AUTH_TOKEN: 'sk-explicit',
100
+ ANTHROPIC_MODEL: 'claude-explicit',
101
+ },
102
+ },
103
+ codex: { model: 'gpt-explicit' },
104
+ opencode: {
105
+ provider: {
106
+ default: {
107
+ options: { baseURL: 'https://explicit.example.com/v1', apiKey: 'sk-explicit' },
108
+ },
109
+ },
110
+ },
111
+ },
112
+ toolStatus: {
113
+ claude: status('claude', true),
114
+ codex: status('codex', true),
115
+ opencode: status('opencode', true),
116
+ },
117
+ aiConfigService: {
118
+ applyAcodeConfig,
119
+ applyClaudeCodeConfig,
120
+ applyCodexConfig,
121
+ applyOpenCodeConfig,
122
+ },
123
+ });
124
+ expect(applyClaudeCodeConfig).toHaveBeenCalledWith({
125
+ env: {
126
+ ANTHROPIC_BASE_URL: 'https://explicit.example.com',
127
+ ANTHROPIC_AUTH_TOKEN: 'sk-explicit',
128
+ ANTHROPIC_MODEL: 'claude-explicit',
129
+ },
130
+ });
131
+ expect(applyCodexConfig).toHaveBeenCalledWith({ model: 'gpt-explicit' });
132
+ expect(applyOpenCodeConfig).toHaveBeenCalledOnce();
133
+ expect(result.generatedFromUnifiedTemplate).toBe(false);
134
+ expect(result.applied.claudecode).toEqual(['env']);
135
+ expect(result.applied.codex).toEqual(['model']);
136
+ expect(result.applied.opencode).toEqual(['provider']);
137
+ });
81
138
  });
@@ -1 +1 @@
1
- {"version":3,"file":"cc-switch-sdk.d.ts","sourceRoot":"","sources":["../../src/services/cc-switch-sdk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAc,MAAM,gBAAgB,CAAC;AAYzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAatD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA+B3D;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAI3E;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,+BAA+B,CACnD,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,uBAAuB,CAAC,CAOlC;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAOpD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,eAAe,CAI1F;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAgBxB;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,QAAQ,CAW1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAmB7D"}
1
+ {"version":3,"file":"cc-switch-sdk.d.ts","sourceRoot":"","sources":["../../src/services/cc-switch-sdk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAc,MAAM,gBAAgB,CAAC;AAczF,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAetD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAiC3D;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAI3E;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,+BAA+B,CACnD,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,uBAAuB,CAAC,CAOlC;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAQpD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,eAAe,CAI1F;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAgBxB;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,QAAQ,CAY1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAqB7D"}
@@ -7,13 +7,15 @@
7
7
  import path from 'node:path';
8
8
  import { AiConfigService, CcSwitchSdk } from '@cc-switch/sdk';
9
9
  import { createMcpAdapters, createSkillAdapters } from '../adapters/cc-switch/index.js';
10
- import { getClaudeConfigFile, getClaudeMcpConfigFile, getClaudeSkillsDir, getCodexConfigFile, getCodexSkillsDir, getRuntimeHomeDir, getOpencodeConfigFile, getOpencodeSkillsDir, } from '../config.js';
10
+ import { getAcodeConfigFile, getAcodeSkillsDir, getClaudeConfigFile, getClaudeMcpConfigFile, getClaudeSkillsDir, getCodexConfigFile, getCodexSkillsDir, getRuntimeHomeDir, getOpencodeConfigFile, getOpencodeSkillsDir, } from '../config.js';
11
11
  import { getAgentInitRoot } from './instance-state.js';
12
12
  import { InstanceService } from './instance-service.js';
13
13
  export function getCcSwitchAppPaths() {
14
14
  const runtimeHome = path.resolve(getRuntimeHomeDir());
15
15
  return {
16
16
  runtimeHome,
17
+ acodeConfigFile: path.resolve(getAcodeConfigFile(runtimeHome)),
18
+ acodeSkillsDir: path.resolve(getAcodeSkillsDir(runtimeHome)),
17
19
  claudeConfigFile: path.resolve(getClaudeConfigFile(runtimeHome)),
18
20
  claudeMcpConfigFile: path.resolve(getClaudeMcpConfigFile(runtimeHome)),
19
21
  claudeSkillsDir: path.resolve(getClaudeSkillsDir(runtimeHome)),
@@ -30,6 +32,8 @@ export function getCcSwitchSdk(agentId) {
30
32
  const paths = {
31
33
  stateFile: path.join(sdkRoot, 'state.json'),
32
34
  backupDir: path.join(sdkRoot, 'backups'),
35
+ acodeConfigFile: appPaths.acodeConfigFile,
36
+ acodeSkillsDir: appPaths.acodeSkillsDir,
33
37
  claudeConfigFile: appPaths.claudeConfigFile,
34
38
  claudeSkillsDir: appPaths.claudeSkillsDir,
35
39
  claudecodeConfigFile: appPaths.claudeMcpConfigFile,
@@ -67,6 +71,7 @@ export async function discoverCcSwitchConfiguredItems(sdk) {
67
71
  export function getAiConfigService() {
68
72
  const appPaths = getCcSwitchAppPaths();
69
73
  return new AiConfigService({
74
+ acodeConfigFile: appPaths.acodeConfigFile,
70
75
  claudecodeConfigFile: appPaths.claudeConfigFile,
71
76
  codexConfigFile: appPaths.codexConfigFile,
72
77
  opencodeConfigFile: appPaths.opencodeConfigFile,
@@ -97,6 +102,7 @@ export function toSdkAppsFromEnabledTools(enabledTools) {
97
102
  const tools = Array.isArray(enabledTools) ? enabledTools : [];
98
103
  const includes = (name) => tools.includes(name);
99
104
  return {
105
+ acode: includes('acode'),
100
106
  claude: false,
101
107
  claudecode: includes('claudecode') || includes('claude'),
102
108
  codex: includes('codex'),
@@ -108,6 +114,7 @@ export function toSdkAppsFromEnabledTools(enabledTools) {
108
114
  export function toSdkApps(apps) {
109
115
  if (!apps) {
110
116
  return {
117
+ acode: false,
111
118
  claude: false,
112
119
  claudecode: false,
113
120
  codex: false,
@@ -117,6 +124,7 @@ export function toSdkApps(apps) {
117
124
  };
118
125
  }
119
126
  return {
127
+ acode: Boolean(apps.acode),
120
128
  claude: false,
121
129
  claudecode: Boolean(apps.claudecode) || Boolean(apps.claude),
122
130
  codex: Boolean(apps.codex),
@@ -1 +1 @@
1
- {"version":3,"file":"instance-init-service.d.ts","sourceRoot":"","sources":["../../src/services/instance-init-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,UAAU,EAAS,YAAY,EAAE,eAAe,EAAqB,MAAM,aAAa,CAAC;AAsB9K,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,eAAe,CAAC,CAyB1B;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B,GACA,OAAO,CAAC;IACT,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,oBAAoB,EAAE,CAAC;KACpC,CAAC;IACF,GAAG,EAAE;QACH,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE;QACV,MAAM,EAAE,oBAAoB,EAAE,CAAC;QAC/B,UAAU,EAAE,kBAAkB,EAAE,CAAC;KAClC,CAAC;CACH,CAAC,CA4MD"}
1
+ {"version":3,"file":"instance-init-service.d.ts","sourceRoot":"","sources":["../../src/services/instance-init-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,UAAU,EAAS,YAAY,EAAE,eAAe,EAAqB,MAAM,aAAa,CAAC;AAsB9K,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,eAAe,CAAC,CAyB1B;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B,GACA,OAAO,CAAC;IACT,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,oBAAoB,EAAE,CAAC;KACpC,CAAC;IACF,GAAG,EAAE;QACH,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE;QACV,MAAM,EAAE,oBAAoB,EAAE,CAAC;QAC/B,UAAU,EAAE,kBAAkB,EAAE,CAAC;KAClC,CAAC;CACH,CAAC,CA6MD"}
@@ -64,7 +64,7 @@ export async function initInstance(agentId, workspacePath, options) {
64
64
  agentId: String(agentId),
65
65
  workspacePath: normalizedWorkspace,
66
66
  initRoot,
67
- enabledTools: installedTools,
67
+ enabledTools: tools,
68
68
  toolStatus: detectedToolStatus,
69
69
  logs,
70
70
  skill: {
@@ -83,6 +83,7 @@ export async function initInstance(agentId, workspacePath, options) {
83
83
  });
84
84
  }
85
85
  pushLog('select-installed-tools', 'success', '已选择可初始化工具', {
86
+ enabledTools: tools,
86
87
  installedTools,
87
88
  });
88
89
  pushLog('load-sdk', 'running', '开始加载 CC Switch SDK');
@@ -154,7 +155,7 @@ export async function initInstance(agentId, workspacePath, options) {
154
155
  }
155
156
  pushLog('persist-state', 'running', '开始保存实例状态');
156
157
  state.initialized = true;
157
- state.enabledTools = installedTools;
158
+ state.enabledTools = tools;
158
159
  state.toolStatus = detectedToolStatus;
159
160
  state.skillEnabled = initResult.skill.enabled;
160
161
  state.mcpEnabled = initResult.mcp.enabled;
@@ -17,6 +17,7 @@ vi.mock('./cc-switch-sdk.js', () => ({
17
17
  const tools = Array.isArray(enabledTools) ? enabledTools : [];
18
18
  return {
19
19
  claude: false,
20
+ acode: false,
20
21
  claudecode: tools.includes('claude') || tools.includes('claudecode'),
21
22
  codex: tools.includes('codex'),
22
23
  gemini: tools.includes('gemini'),
@@ -80,11 +81,11 @@ function status(tool, installed) {
80
81
  error: installed ? null : 'not installed',
81
82
  };
82
83
  }
83
- describe('initInstance installed-only tool initialization', () => {
84
+ describe('initInstance enabled tool initialization', () => {
84
85
  const originalRuntimeHomeDir = process.env.AWS_RUNTIME_HOME_DIR;
85
86
  let runtimeHomeDir;
86
87
  beforeEach(async () => {
87
- runtimeHomeDir = path.join(os.tmpdir(), `aws-init-installed-only-${Date.now()}`);
88
+ runtimeHomeDir = path.join(os.tmpdir(), `aws-init-enabled-tools-${Date.now()}`);
88
89
  process.env.AWS_RUNTIME_HOME_DIR = runtimeHomeDir;
89
90
  activeSdk = new MockSdk();
90
91
  vi.clearAllMocks();
@@ -110,7 +111,7 @@ describe('initInstance installed-only tool initialization', () => {
110
111
  }
111
112
  await fs.rm(runtimeHomeDir, { recursive: true, force: true });
112
113
  });
113
- it('skips uninstalled tools and configures MCP and skills only for installed tools', async () => {
114
+ it('persists requested tools but configures MCP and skills only for installed tools', async () => {
114
115
  detectToolStatusesMock.mockResolvedValue({
115
116
  claude: status('claude', true),
116
117
  opencode: status('opencode', false),
@@ -123,7 +124,7 @@ describe('initInstance installed-only tool initialization', () => {
123
124
  mcpServers: [{ name: 'aws-mcp', command: 'node', args: ['server.js'] }],
124
125
  });
125
126
  expect(ensureToolsInstalledMock).not.toHaveBeenCalled();
126
- expect(result.enabledTools).toEqual(['claude']);
127
+ expect(result.enabledTools).toEqual(['claude', 'opencode', 'codex']);
127
128
  expect(result.ok).toBe(true);
128
129
  expect(installSkillPackageToSdkMock).toHaveBeenCalledWith(activeSdk, expect.objectContaining({ skillName: 'demo-skill' }), expect.any(String), expect.objectContaining({ claudecode: true, opencode: false, codex: false }));
129
130
  expect(activeSdk.createdMcpInputs).toEqual([
@@ -134,6 +135,6 @@ describe('initInstance installed-only tool initialization', () => {
134
135
  ]);
135
136
  const statePath = path.join(runtimeHomeDir, '.aws-bridge', 'instances', 'agent-installed-only', 'state.json');
136
137
  const state = JSON.parse(await fs.readFile(statePath, 'utf-8'));
137
- expect(state.enabledTools).toEqual(['claude']);
138
+ expect(state.enabledTools).toEqual(['claude', 'opencode', 'codex']);
138
139
  });
139
140
  });
@@ -1 +1 @@
1
- {"version":3,"file":"instance-service.d.ts","sourceRoot":"","sources":["../../src/services/instance-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instance-service.d.ts","sourceRoot":"","sources":["../../src/services/instance-service.ts"],"names":[],"mappings":"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"}
@@ -103,6 +103,7 @@ export class InstanceService {
103
103
  }
104
104
  toAppFlags(appIds) {
105
105
  return {
106
+ acode: appIds.includes("acode"),
106
107
  claude: appIds.includes("claude"),
107
108
  claudecode: appIds.includes("claudecode"),
108
109
  codex: appIds.includes("codex"),
@@ -17,7 +17,7 @@ function createDefaultInstanceState() {
17
17
  initialized: false,
18
18
  skills: [],
19
19
  mcpServers: [],
20
- enabledTools: ['claude', 'opencode', 'codex'],
20
+ enabledTools: ['acode', 'claude', 'opencode', 'codex'],
21
21
  toolStatus: {},
22
22
  skillEnabled: true,
23
23
  mcpEnabled: true,