@vybestack/llxprt-code 0.4.8 → 0.5.0-nightly.251102.6bb3db7a

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 (269) hide show
  1. package/dist/package.json +5 -3
  2. package/dist/src/auth/__tests__/oauthManager.safety.test.d.ts +6 -0
  3. package/dist/src/auth/__tests__/oauthManager.safety.test.js +49 -0
  4. package/dist/src/auth/__tests__/oauthManager.safety.test.js.map +1 -0
  5. package/dist/src/auth/oauth-manager.d.ts +11 -0
  6. package/dist/src/auth/oauth-manager.js +62 -29
  7. package/dist/src/auth/oauth-manager.js.map +1 -1
  8. package/dist/src/auth/oauth-manager.spec.js +7 -2
  9. package/dist/src/auth/oauth-manager.spec.js.map +1 -1
  10. package/dist/src/config/__tests__/nonInteractiveTools.test.d.ts +6 -0
  11. package/dist/src/config/__tests__/nonInteractiveTools.test.js +13 -0
  12. package/dist/src/config/__tests__/nonInteractiveTools.test.js.map +1 -0
  13. package/dist/src/config/__tests__/profileBootstrap.test.d.ts +6 -0
  14. package/dist/src/config/__tests__/profileBootstrap.test.js +91 -0
  15. package/dist/src/config/__tests__/profileBootstrap.test.js.map +1 -0
  16. package/dist/src/config/config.d.ts +6 -2
  17. package/dist/src/config/config.js +219 -18
  18. package/dist/src/config/config.js.map +1 -1
  19. package/dist/src/config/profileBootstrap.d.ts +64 -0
  20. package/dist/src/config/profileBootstrap.js +140 -0
  21. package/dist/src/config/profileBootstrap.js.map +1 -0
  22. package/dist/src/gemini.js +68 -23
  23. package/dist/src/gemini.js.map +1 -1
  24. package/dist/src/gemini.test.js +1 -2
  25. package/dist/src/gemini.test.js.map +1 -1
  26. package/dist/src/generated/git-commit.d.ts +1 -1
  27. package/dist/src/generated/git-commit.js +1 -1
  28. package/dist/src/integration-tests/base-url-behavior.integration.test.js +110 -450
  29. package/dist/src/integration-tests/base-url-behavior.integration.test.js.map +1 -1
  30. package/dist/src/integration-tests/model-params-isolation.integration.test.js +101 -539
  31. package/dist/src/integration-tests/model-params-isolation.integration.test.js.map +1 -1
  32. package/dist/src/integration-tests/modelParams.integration.test.js +86 -761
  33. package/dist/src/integration-tests/modelParams.integration.test.js.map +1 -1
  34. package/dist/src/integration-tests/provider-multi-runtime.integration.test.d.ts +6 -0
  35. package/dist/src/integration-tests/provider-multi-runtime.integration.test.js +198 -0
  36. package/dist/src/integration-tests/provider-multi-runtime.integration.test.js.map +1 -0
  37. package/dist/src/integration-tests/provider-switching.integration.test.js +97 -151
  38. package/dist/src/integration-tests/provider-switching.integration.test.js.map +1 -1
  39. package/dist/src/integration-tests/runtime-isolation.test.d.ts +13 -0
  40. package/dist/src/integration-tests/runtime-isolation.test.js +170 -0
  41. package/dist/src/integration-tests/runtime-isolation.test.js.map +1 -0
  42. package/dist/src/integration-tests/test-utils.js +19 -2
  43. package/dist/src/integration-tests/test-utils.js.map +1 -1
  44. package/dist/src/integration-tests/test-utils.test.js +9 -8
  45. package/dist/src/integration-tests/test-utils.test.js.map +1 -1
  46. package/dist/src/integration-tests/todo-continuation.integration.test.js +5 -2
  47. package/dist/src/integration-tests/todo-continuation.integration.test.js.map +1 -1
  48. package/dist/src/integration-tests/tools-governance.integration.test.d.ts +6 -0
  49. package/dist/src/integration-tests/tools-governance.integration.test.js +98 -0
  50. package/dist/src/integration-tests/tools-governance.integration.test.js.map +1 -0
  51. package/dist/src/nonInteractiveCli.js +36 -11
  52. package/dist/src/nonInteractiveCli.js.map +1 -1
  53. package/dist/src/providers/logging/git-stats.test.js +11 -1
  54. package/dist/src/providers/logging/git-stats.test.js.map +1 -1
  55. package/dist/src/providers/logging/multi-provider-logging.integration.test.js +1 -2
  56. package/dist/src/providers/logging/multi-provider-logging.integration.test.js.map +1 -1
  57. package/dist/src/providers/logging/performance.test.js +1 -1
  58. package/dist/src/providers/logging/performance.test.js.map +1 -1
  59. package/dist/src/providers/oauth-provider-registration.d.ts +2 -2
  60. package/dist/src/providers/oauth-provider-registration.js +25 -9
  61. package/dist/src/providers/oauth-provider-registration.js.map +1 -1
  62. package/dist/src/providers/provider-gemini-switching.test.js +67 -89
  63. package/dist/src/providers/provider-gemini-switching.test.js.map +1 -1
  64. package/dist/src/providers/provider-switching.integration.test.js +42 -98
  65. package/dist/src/providers/provider-switching.integration.test.js.map +1 -1
  66. package/dist/src/providers/providerConfigUtils.d.ts +12 -7
  67. package/dist/src/providers/providerConfigUtils.js +31 -99
  68. package/dist/src/providers/providerConfigUtils.js.map +1 -1
  69. package/dist/src/providers/providerManagerInstance.d.ts +17 -1
  70. package/dist/src/providers/providerManagerInstance.js +157 -175
  71. package/dist/src/providers/providerManagerInstance.js.map +1 -1
  72. package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js +19 -15
  73. package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js.map +1 -1
  74. package/dist/src/providers/providerManagerInstance.test.js +2 -5
  75. package/dist/src/providers/providerManagerInstance.test.js.map +1 -1
  76. package/dist/src/runtime/__tests__/profileApplication.test.d.ts +5 -0
  77. package/dist/src/runtime/__tests__/profileApplication.test.js +232 -0
  78. package/dist/src/runtime/__tests__/profileApplication.test.js.map +1 -0
  79. package/dist/src/runtime/__tests__/runtimeIsolation.test.d.ts +5 -0
  80. package/dist/src/runtime/__tests__/runtimeIsolation.test.js +376 -0
  81. package/dist/src/runtime/__tests__/runtimeIsolation.test.js.map +1 -0
  82. package/dist/src/runtime/agentRuntimeAdapter.d.ts +249 -0
  83. package/dist/src/runtime/agentRuntimeAdapter.js +506 -0
  84. package/dist/src/runtime/agentRuntimeAdapter.js.map +1 -0
  85. package/dist/src/runtime/agentRuntimeAdapter.spec.d.ts +6 -0
  86. package/dist/src/runtime/agentRuntimeAdapter.spec.js +866 -0
  87. package/dist/src/runtime/agentRuntimeAdapter.spec.js.map +1 -0
  88. package/dist/src/runtime/messages.d.ts +28 -0
  89. package/dist/src/runtime/messages.js +64 -0
  90. package/dist/src/runtime/messages.js.map +1 -0
  91. package/dist/src/runtime/profileApplication.d.ts +33 -0
  92. package/dist/src/runtime/profileApplication.js +191 -0
  93. package/dist/src/runtime/profileApplication.js.map +1 -0
  94. package/dist/src/runtime/providerConfigUtils.test.d.ts +1 -0
  95. package/dist/src/runtime/providerConfigUtils.test.js +68 -0
  96. package/dist/src/runtime/providerConfigUtils.test.js.map +1 -0
  97. package/dist/src/runtime/runtimeContextFactory.d.ts +102 -0
  98. package/dist/src/runtime/runtimeContextFactory.js +190 -0
  99. package/dist/src/runtime/runtimeContextFactory.js.map +1 -0
  100. package/dist/src/runtime/runtimeSettings.d.ts +217 -0
  101. package/dist/src/runtime/runtimeSettings.js +1094 -0
  102. package/dist/src/runtime/runtimeSettings.js.map +1 -0
  103. package/dist/src/runtime/runtimeSettings.test.d.ts +1 -0
  104. package/dist/src/runtime/runtimeSettings.test.js +320 -0
  105. package/dist/src/runtime/runtimeSettings.test.js.map +1 -0
  106. package/dist/src/services/BuiltinCommandLoader.d.ts +13 -4
  107. package/dist/src/services/BuiltinCommandLoader.js +17 -4
  108. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  109. package/dist/src/services/McpPromptLoader.js +34 -13
  110. package/dist/src/services/McpPromptLoader.js.map +1 -1
  111. package/dist/src/test-utils/mockCommandContext.js +5 -2
  112. package/dist/src/test-utils/mockCommandContext.js.map +1 -1
  113. package/dist/src/ui/App.js +29 -49
  114. package/dist/src/ui/App.js.map +1 -1
  115. package/dist/src/ui/commands/aboutCommand.js +59 -38
  116. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  117. package/dist/src/ui/commands/authCommand.js +7 -9
  118. package/dist/src/ui/commands/authCommand.js.map +1 -1
  119. package/dist/src/ui/commands/baseurlCommand.js +8 -44
  120. package/dist/src/ui/commands/baseurlCommand.js.map +1 -1
  121. package/dist/src/ui/commands/chatCommand.js +28 -12
  122. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  123. package/dist/src/ui/commands/diagnosticsCommand.d.ts +0 -3
  124. package/dist/src/ui/commands/diagnosticsCommand.js +45 -191
  125. package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -1
  126. package/dist/src/ui/commands/keyCommand.js +9 -58
  127. package/dist/src/ui/commands/keyCommand.js.map +1 -1
  128. package/dist/src/ui/commands/keyCommand.test.js +48 -102
  129. package/dist/src/ui/commands/keyCommand.test.js.map +1 -1
  130. package/dist/src/ui/commands/keyfileCommand.js +42 -93
  131. package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
  132. package/dist/src/ui/commands/logoutCommand.js +2 -2
  133. package/dist/src/ui/commands/logoutCommand.js.map +1 -1
  134. package/dist/src/ui/commands/mcpCommand.js +29 -7
  135. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  136. package/dist/src/ui/commands/modelCommand.js +8 -59
  137. package/dist/src/ui/commands/modelCommand.js.map +1 -1
  138. package/dist/src/ui/commands/profileCommand.js +151 -267
  139. package/dist/src/ui/commands/profileCommand.js.map +1 -1
  140. package/dist/src/ui/commands/profileCommand.test.js +88 -344
  141. package/dist/src/ui/commands/profileCommand.test.js.map +1 -1
  142. package/dist/src/ui/commands/providerCommand.js +9 -3
  143. package/dist/src/ui/commands/providerCommand.js.map +1 -1
  144. package/dist/src/ui/commands/restoreCommand.js +38 -18
  145. package/dist/src/ui/commands/restoreCommand.js.map +1 -1
  146. package/dist/src/ui/commands/schema/argumentResolver.test.d.ts +6 -0
  147. package/dist/src/ui/commands/schema/argumentResolver.test.js +619 -0
  148. package/dist/src/ui/commands/schema/argumentResolver.test.js.map +1 -0
  149. package/dist/src/ui/commands/schema/index.d.ts +15 -0
  150. package/dist/src/ui/commands/schema/index.js +320 -0
  151. package/dist/src/ui/commands/schema/index.js.map +1 -0
  152. package/dist/src/ui/commands/schema/types.d.ts +61 -0
  153. package/dist/src/ui/commands/schema/types.js +12 -0
  154. package/dist/src/ui/commands/schema/types.js.map +1 -0
  155. package/dist/src/ui/commands/setCommand.js +641 -325
  156. package/dist/src/ui/commands/setCommand.js.map +1 -1
  157. package/dist/src/ui/commands/setCommand.test.js +92 -388
  158. package/dist/src/ui/commands/setCommand.test.js.map +1 -1
  159. package/dist/src/ui/commands/statusCommand.js +2 -2
  160. package/dist/src/ui/commands/statusCommand.js.map +1 -1
  161. package/dist/src/ui/commands/subagentCommand.d.ts +16 -0
  162. package/dist/src/ui/commands/subagentCommand.js +674 -0
  163. package/dist/src/ui/commands/subagentCommand.js.map +1 -0
  164. package/dist/src/ui/commands/test/setCommand.mutation.test.d.ts +6 -0
  165. package/dist/src/ui/commands/test/setCommand.mutation.test.js +132 -0
  166. package/dist/src/ui/commands/test/setCommand.mutation.test.js.map +1 -0
  167. package/dist/src/ui/commands/test/setCommand.phase09.test.d.ts +6 -0
  168. package/dist/src/ui/commands/test/setCommand.phase09.test.js +222 -0
  169. package/dist/src/ui/commands/test/setCommand.phase09.test.js.map +1 -0
  170. package/dist/src/ui/commands/test/subagentCommand.schema.test.d.ts +6 -0
  171. package/dist/src/ui/commands/test/subagentCommand.schema.test.js +125 -0
  172. package/dist/src/ui/commands/test/subagentCommand.schema.test.js.map +1 -0
  173. package/dist/src/ui/commands/test/subagentCommand.test.d.ts +1 -0
  174. package/dist/src/ui/commands/test/subagentCommand.test.js +598 -0
  175. package/dist/src/ui/commands/test/subagentCommand.test.js.map +1 -0
  176. package/dist/src/ui/commands/toolformatCommand.js +25 -98
  177. package/dist/src/ui/commands/toolformatCommand.js.map +1 -1
  178. package/dist/src/ui/commands/toolformatCommand.test.js +56 -102
  179. package/dist/src/ui/commands/toolformatCommand.test.js.map +1 -1
  180. package/dist/src/ui/commands/toolsCommand.js +187 -31
  181. package/dist/src/ui/commands/toolsCommand.js.map +1 -1
  182. package/dist/src/ui/commands/types.d.ts +11 -2
  183. package/dist/src/ui/commands/types.js.map +1 -1
  184. package/dist/src/ui/components/AuthDialog.js +16 -55
  185. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  186. package/dist/src/ui/components/Footer.js +4 -5
  187. package/dist/src/ui/components/Footer.js.map +1 -1
  188. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  189. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  190. package/dist/src/ui/components/InputPrompt.js +1 -1
  191. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  192. package/dist/src/ui/components/StatsDisplay.js +6 -11
  193. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  194. package/dist/src/ui/components/SuggestionsDisplay.d.ts +13 -1
  195. package/dist/src/ui/components/SuggestionsDisplay.js +22 -3
  196. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  197. package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +1 -0
  198. package/dist/src/ui/components/messages/ToolGroupMessage.js +14 -14
  199. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  200. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +1 -0
  201. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  202. package/dist/src/ui/containers/SessionController.js +61 -117
  203. package/dist/src/ui/containers/SessionController.js.map +1 -1
  204. package/dist/src/ui/contexts/RuntimeContext.d.ts +61 -0
  205. package/dist/src/ui/contexts/RuntimeContext.js +118 -0
  206. package/dist/src/ui/contexts/RuntimeContext.js.map +1 -0
  207. package/dist/src/ui/contexts/TodoProvider.d.ts +1 -0
  208. package/dist/src/ui/contexts/TodoProvider.js +10 -8
  209. package/dist/src/ui/contexts/TodoProvider.js.map +1 -1
  210. package/dist/src/ui/contexts/ToolCallProvider.d.ts +1 -0
  211. package/dist/src/ui/contexts/ToolCallProvider.js +10 -9
  212. package/dist/src/ui/contexts/ToolCallProvider.js.map +1 -1
  213. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.d.ts +6 -0
  214. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js +39 -0
  215. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js.map +1 -0
  216. package/dist/src/ui/hooks/atCommandProcessor.js +11 -3
  217. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  218. package/dist/src/ui/hooks/atCommandProcessor.test.js +3 -1
  219. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  220. package/dist/src/ui/hooks/shellCommandProcessor.js +4 -1
  221. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  222. package/dist/src/ui/hooks/shellCommandProcessor.test.js +1 -0
  223. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  224. package/dist/src/ui/hooks/slashCommandProcessor.js +27 -1
  225. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  226. package/dist/src/ui/hooks/useAuthCommand.js +11 -3
  227. package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
  228. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -0
  229. package/dist/src/ui/hooks/useCommandCompletion.js +2 -0
  230. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  231. package/dist/src/ui/hooks/useGeminiStream.js +37 -11
  232. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  233. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.d.ts +6 -0
  234. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js +232 -0
  235. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js.map +1 -0
  236. package/dist/src/ui/hooks/useLoadProfileDialog.d.ts +1 -1
  237. package/dist/src/ui/hooks/useLoadProfileDialog.js +18 -57
  238. package/dist/src/ui/hooks/useLoadProfileDialog.js.map +1 -1
  239. package/dist/src/ui/hooks/useOpenAIProviderInfo.d.ts +1 -1
  240. package/dist/src/ui/hooks/useOpenAIProviderInfo.js +12 -7
  241. package/dist/src/ui/hooks/useOpenAIProviderInfo.js.map +1 -1
  242. package/dist/src/ui/hooks/useProviderDialog.d.ts +1 -1
  243. package/dist/src/ui/hooks/useProviderDialog.js +17 -90
  244. package/dist/src/ui/hooks/useProviderDialog.js.map +1 -1
  245. package/dist/src/ui/hooks/useProviderModelDialog.d.ts +2 -2
  246. package/dist/src/ui/hooks/useProviderModelDialog.js +11 -12
  247. package/dist/src/ui/hooks/useProviderModelDialog.js.map +1 -1
  248. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +3 -1
  249. package/dist/src/ui/hooks/useReactToolScheduler.js +144 -34
  250. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  251. package/dist/src/ui/hooks/useSlashCompletion.d.ts +32 -0
  252. package/dist/src/ui/hooks/useSlashCompletion.js +154 -77
  253. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  254. package/dist/src/ui/hooks/useSlashCompletion.test.js +39 -14
  255. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  256. package/dist/src/ui/hooks/useToolScheduler.test.js +108 -79
  257. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  258. package/dist/src/ui/types.d.ts +1 -0
  259. package/dist/src/ui/types.js.map +1 -1
  260. package/dist/src/utils/sandbox.js +7 -5
  261. package/dist/src/utils/sandbox.js.map +1 -1
  262. package/dist/src/validateNonInterActiveAuth.js +4 -2
  263. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  264. package/dist/src/zed-integration/schema.d.ts +30 -30
  265. package/dist/src/zed-integration/zedIntegration.js +112 -39
  266. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  267. package/dist/tsconfig.build.tsbuildinfo +1 -0
  268. package/package.json +5 -3
  269. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,866 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * @plan PLAN-20251027-STATELESS5.P07
8
+ * @requirement REQ-STAT5-002
9
+ * @pseudocode cli-runtime-adapter.md lines 51-609
10
+ *
11
+ * Comprehensive TDD tests for AgentRuntimeAdapter behavior.
12
+ * RED phase: All tests fail against stub implementation.
13
+ * GREEN phase: Phase 08 implements the actual adapter logic.
14
+ */
15
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
16
+ import { AgentRuntimeAdapter, bootstrapForegroundAgent, resolveRuntimeStateFromFlags, setRuntimeAdapter, getRuntimeAdapter, resetRuntimeAdapter, setRuntimeProvider, getRuntimeProvider, setRuntimeModel, getRuntimeModel, switchRuntimeProvider, } from './agentRuntimeAdapter.js';
17
+ import { createAgentRuntimeState, updateAgentRuntimeState, subscribeToAgentRuntimeState, AuthType, } from '@vybestack/llxprt-code-core';
18
+ // Mock fs module for keyfile reading
19
+ vi.mock('fs', async (importOriginal) => {
20
+ const actual = await importOriginal();
21
+ return {
22
+ ...actual,
23
+ readFileSync: vi.fn((path) => {
24
+ if (path === '/path/to/keyfile') {
25
+ return 'test-api-key-from-file';
26
+ }
27
+ throw new Error(`ENOENT: no such file or directory, open '${path}'`);
28
+ }),
29
+ };
30
+ });
31
+ // Mock Config for testing
32
+ function createMockConfig() {
33
+ const mockProviderManager = {
34
+ hasProvider: vi.fn((name) => ['gemini', 'anthropic', 'openai'].includes(name)),
35
+ getProvider: vi.fn((name) => ({
36
+ getDefaultModel: vi.fn(() => {
37
+ const defaults = {
38
+ gemini: 'gemini-2.0-flash',
39
+ anthropic: 'claude-3-5-sonnet-20241022',
40
+ openai: 'gpt-4',
41
+ };
42
+ return defaults[name] || 'default-model';
43
+ }),
44
+ })),
45
+ getProviderByName: vi.fn((name) => {
46
+ if (!['gemini', 'anthropic', 'openai'].includes(name)) {
47
+ return undefined;
48
+ }
49
+ return {
50
+ getDefaultModel: vi.fn(() => {
51
+ const defaults = {
52
+ gemini: 'gemini-2.0-flash',
53
+ anthropic: 'claude-3-5-sonnet-20241022',
54
+ openai: 'gpt-4',
55
+ };
56
+ return defaults[name] || 'default-model';
57
+ }),
58
+ };
59
+ }),
60
+ getProviderNames: vi.fn(() => ['gemini', 'anthropic', 'openai']),
61
+ listProviders: vi.fn(() => ['gemini', 'anthropic', 'openai']),
62
+ };
63
+ return {
64
+ getProvider: vi.fn(() => 'gemini'),
65
+ setProvider: vi.fn(),
66
+ getModel: vi.fn(() => 'gemini-2.0-flash'),
67
+ setModel: vi.fn(),
68
+ getAuthType: vi.fn(() => AuthType.USE_GEMINI),
69
+ getSessionId: vi.fn(() => 'test-session-id'),
70
+ getProxy: vi.fn(() => undefined),
71
+ setProxy: vi.fn(),
72
+ getEphemeralSetting: vi.fn((key) => {
73
+ if (key === 'base-url')
74
+ return undefined;
75
+ return undefined;
76
+ }),
77
+ setEphemeralSetting: vi.fn(),
78
+ getProviderManager: vi.fn(() => mockProviderManager),
79
+ refreshAuth: vi.fn(async () => { }),
80
+ getSettingsService: vi.fn(() => ({})),
81
+ };
82
+ }
83
+ describe('AgentRuntimeAdapter - Constructor and Initialization', () => {
84
+ /**
85
+ * @plan PLAN-20251027-STATELESS5.P07
86
+ * @requirement REQ-STAT5-002.1
87
+ * @pseudocode cli-runtime-adapter.md lines 51-88
88
+ *
89
+ * Tests adapter construction, state initialization, and config mirroring.
90
+ */
91
+ it('should initialize adapter with runtime state and legacy config', () => {
92
+ // @plan PLAN-20251027-STATELESS5.P07
93
+ // @requirement REQ-STAT5-002.1
94
+ // @pseudocode cli-runtime-adapter.md lines 56-75
95
+ const params = {
96
+ runtimeId: 'test-runtime',
97
+ provider: 'gemini',
98
+ model: 'gemini-2.0-flash',
99
+ authType: AuthType.USE_GEMINI,
100
+ sessionId: 'test-session',
101
+ };
102
+ const runtimeState = createAgentRuntimeState(params);
103
+ const config = createMockConfig();
104
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
105
+ expect(adapter.getProvider()).toBe('gemini');
106
+ expect(adapter.getModel()).toBe('gemini-2.0-flash');
107
+ expect(adapter.getAuthType()).toBe(AuthType.USE_GEMINI);
108
+ });
109
+ it('should mirror initial state to legacy config on construction', () => {
110
+ // @plan PLAN-20251027-STATELESS5.P07
111
+ // @requirement REQ-STAT5-002.3
112
+ // @pseudocode cli-runtime-adapter.md lines 67-68
113
+ const params = {
114
+ runtimeId: 'test-runtime',
115
+ provider: 'anthropic',
116
+ model: 'claude-3-5-sonnet-20241022',
117
+ authType: AuthType.OAUTH,
118
+ authPayload: { token: 'test-token' },
119
+ baseUrl: 'https://api.anthropic.com',
120
+ sessionId: 'test-session',
121
+ };
122
+ const runtimeState = createAgentRuntimeState(params);
123
+ const config = createMockConfig();
124
+ new AgentRuntimeAdapter(runtimeState, config);
125
+ expect(config.setProvider).toHaveBeenCalledWith('anthropic');
126
+ expect(config.setModel).toHaveBeenCalledWith('claude-3-5-sonnet-20241022');
127
+ expect(config.setEphemeralSetting).toHaveBeenCalledWith('base-url', 'https://api.anthropic.com');
128
+ });
129
+ it('should subscribe to runtime state changes on construction', () => {
130
+ // @plan PLAN-20251027-STATELESS5.P07
131
+ // @requirement REQ-STAT5-002.1
132
+ // @pseudocode cli-runtime-adapter.md lines 70-73
133
+ const params = {
134
+ runtimeId: 'test-runtime',
135
+ provider: 'gemini',
136
+ model: 'gemini-2.0-flash',
137
+ authType: AuthType.USE_GEMINI,
138
+ sessionId: 'test-session',
139
+ };
140
+ const runtimeState = createAgentRuntimeState(params);
141
+ const config = createMockConfig();
142
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
143
+ // Update state and verify adapter reflects the change
144
+ updateAgentRuntimeState(runtimeState, { model: 'gemini-2.5-flash' });
145
+ // After subscription, adapter should reflect new state
146
+ expect(adapter.getModel()).toBe('gemini-2.5-flash');
147
+ });
148
+ });
149
+ describe('AgentRuntimeAdapter - Read Operations', () => {
150
+ /**
151
+ * @plan PLAN-20251027-STATELESS5.P07
152
+ * @requirement REQ-STAT5-002.1
153
+ * @pseudocode cli-runtime-adapter.md lines 199-221
154
+ *
155
+ * Tests synchronous getters that delegate to runtime state.
156
+ */
157
+ let adapter;
158
+ let runtimeState;
159
+ let config;
160
+ beforeEach(() => {
161
+ const params = {
162
+ runtimeId: 'test-runtime',
163
+ provider: 'gemini',
164
+ model: 'gemini-2.0-flash',
165
+ authType: AuthType.USE_GEMINI,
166
+ authPayload: { apiKey: 'test-key' },
167
+ baseUrl: 'https://custom.api.com',
168
+ sessionId: 'test-session-123',
169
+ modelParams: { temperature: 0.7 },
170
+ };
171
+ runtimeState = createAgentRuntimeState(params);
172
+ config = createMockConfig();
173
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
174
+ });
175
+ it('should return current provider name via getProvider', () => {
176
+ // @plan PLAN-20251027-STATELESS5.P07
177
+ // @requirement REQ-STAT5-002.1
178
+ // @pseudocode cli-runtime-adapter.md lines 199-203
179
+ expect(adapter.getProvider()).toBe('gemini');
180
+ });
181
+ it('should return current model name via getModel', () => {
182
+ // @plan PLAN-20251027-STATELESS5.P07
183
+ // @requirement REQ-STAT5-002.1
184
+ // @pseudocode cli-runtime-adapter.md lines 205-206
185
+ expect(adapter.getModel()).toBe('gemini-2.0-flash');
186
+ });
187
+ it('should return current auth type via getAuthType', () => {
188
+ // @plan PLAN-20251027-STATELESS5.P07
189
+ // @requirement REQ-STAT5-002.1
190
+ // @pseudocode cli-runtime-adapter.md lines 208-209
191
+ expect(adapter.getAuthType()).toBe(AuthType.USE_GEMINI);
192
+ });
193
+ it('should return current session ID via getSessionId', () => {
194
+ // @plan PLAN-20251027-STATELESS5.P07
195
+ // @requirement REQ-STAT5-002.1
196
+ // @pseudocode cli-runtime-adapter.md lines 211-212
197
+ expect(adapter.getSessionId()).toBe('test-session-123');
198
+ });
199
+ it('should return current base URL via getBaseUrl', () => {
200
+ // @plan PLAN-20251027-STATELESS5.P07
201
+ // @requirement REQ-STAT5-002.1
202
+ // @pseudocode cli-runtime-adapter.md lines 214-215
203
+ expect(adapter.getBaseUrl()).toBe('https://custom.api.com');
204
+ });
205
+ it('should return runtime state reference via getRuntimeState', () => {
206
+ // @plan PLAN-20251027-STATELESS5.P07
207
+ // @requirement REQ-STAT5-002.1
208
+ // @pseudocode cli-runtime-adapter.md lines 217-218
209
+ const state = adapter.getRuntimeState();
210
+ expect(state.runtimeId).toBe('test-runtime');
211
+ expect(state.provider).toBe('gemini');
212
+ expect(state.model).toBe('gemini-2.0-flash');
213
+ });
214
+ it('should return sanitized snapshot via getSnapshot', () => {
215
+ // @plan PLAN-20251027-STATELESS5.P07
216
+ // @requirement REQ-STAT5-001.3
217
+ // @pseudocode cli-runtime-adapter.md lines 220-221
218
+ const snapshot = adapter.getSnapshot();
219
+ expect(snapshot.runtimeId).toBe('test-runtime');
220
+ expect(snapshot.provider).toBe('gemini');
221
+ expect(snapshot.model).toBe('gemini-2.0-flash');
222
+ expect(snapshot.authType).toBe(AuthType.USE_GEMINI);
223
+ // Auth payload should be sanitized
224
+ expect(snapshot.authPayload?.apiKey).not.toBe('test-key');
225
+ });
226
+ });
227
+ describe('AgentRuntimeAdapter - Write Operations (Single Field)', () => {
228
+ /**
229
+ * @plan PLAN-20251027-STATELESS5.P07
230
+ * @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
231
+ * @pseudocode cli-runtime-adapter.md lines 227-272
232
+ *
233
+ * Tests single field updates with config mirroring.
234
+ */
235
+ let adapter;
236
+ let config;
237
+ beforeEach(() => {
238
+ const params = {
239
+ runtimeId: 'test-runtime',
240
+ provider: 'gemini',
241
+ model: 'gemini-2.0-flash',
242
+ authType: AuthType.USE_GEMINI,
243
+ sessionId: 'test-session',
244
+ };
245
+ const runtimeState = createAgentRuntimeState(params);
246
+ config = createMockConfig();
247
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
248
+ });
249
+ it('should update provider and default model via setProvider', () => {
250
+ // @plan PLAN-20251027-STATELESS5.P07
251
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
252
+ // @pseudocode cli-runtime-adapter.md lines 227-249
253
+ adapter.setProvider('anthropic');
254
+ expect(adapter.getProvider()).toBe('anthropic');
255
+ expect(adapter.getModel()).toBe('claude-3-5-sonnet-20241022'); // Default for anthropic
256
+ expect(adapter.getBaseUrl()).toBeUndefined(); // Cleared
257
+ });
258
+ it('should mirror provider update to legacy config', () => {
259
+ // @plan PLAN-20251027-STATELESS5.P07
260
+ // @requirement REQ-STAT5-002.3
261
+ // @pseudocode cli-runtime-adapter.md lines 244-248
262
+ adapter.setProvider('anthropic');
263
+ expect(config.setProvider).toHaveBeenCalledWith('anthropic');
264
+ expect(config.setModel).toHaveBeenCalledWith('claude-3-5-sonnet-20241022');
265
+ });
266
+ it('should throw error when setting invalid provider', () => {
267
+ // @plan PLAN-20251027-STATELESS5.P07
268
+ // @requirement REQ-STAT5-002.1
269
+ // @pseudocode cli-runtime-adapter.md lines 229-231
270
+ expect(() => adapter.setProvider('invalid-provider')).toThrow();
271
+ expect(() => adapter.setProvider('invalid-provider')).toThrow(/not found/);
272
+ });
273
+ it('should update model via setModel', () => {
274
+ // @plan PLAN-20251027-STATELESS5.P07
275
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
276
+ // @pseudocode cli-runtime-adapter.md lines 250-256
277
+ adapter.setModel('gemini-2.5-flash');
278
+ expect(adapter.getModel()).toBe('gemini-2.5-flash');
279
+ expect(config.setModel).toHaveBeenCalledWith('gemini-2.5-flash');
280
+ });
281
+ it('should update auth type via setAuthType', () => {
282
+ // @plan PLAN-20251027-STATELESS5.P07
283
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
284
+ // @pseudocode cli-runtime-adapter.md lines 258-264
285
+ adapter.setAuthType(AuthType.API_KEY);
286
+ expect(adapter.getAuthType()).toBe(AuthType.API_KEY);
287
+ });
288
+ it('should update base URL via setBaseUrl', () => {
289
+ // @plan PLAN-20251027-STATELESS5.P07
290
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
291
+ // @pseudocode cli-runtime-adapter.md lines 266-272
292
+ adapter.setBaseUrl('https://custom.api.com');
293
+ expect(adapter.getBaseUrl()).toBe('https://custom.api.com');
294
+ expect(config.setEphemeralSetting).toHaveBeenCalledWith('base-url', 'https://custom.api.com');
295
+ });
296
+ });
297
+ describe('AgentRuntimeAdapter - Batch Write Operations', () => {
298
+ /**
299
+ * @plan PLAN-20251027-STATELESS5.P07
300
+ * @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
301
+ * @pseudocode cli-runtime-adapter.md lines 280-316
302
+ *
303
+ * Tests atomic multi-field updates via switchProvider.
304
+ */
305
+ let adapter;
306
+ let config;
307
+ beforeEach(() => {
308
+ const params = {
309
+ runtimeId: 'test-runtime',
310
+ provider: 'gemini',
311
+ model: 'gemini-2.0-flash',
312
+ authType: AuthType.USE_GEMINI,
313
+ baseUrl: 'https://old.api.com',
314
+ sessionId: 'test-session',
315
+ };
316
+ const runtimeState = createAgentRuntimeState(params);
317
+ config = createMockConfig();
318
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
319
+ });
320
+ it('should atomically switch provider with default model', () => {
321
+ // @plan PLAN-20251027-STATELESS5.P07
322
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
323
+ // @pseudocode cli-runtime-adapter.md lines 280-316
324
+ adapter.switchProvider('anthropic');
325
+ expect(adapter.getProvider()).toBe('anthropic');
326
+ expect(adapter.getModel()).toBe('claude-3-5-sonnet-20241022'); // Default model
327
+ expect(adapter.getBaseUrl()).toBeUndefined(); // Base URL cleared
328
+ });
329
+ it('should switch provider with explicit model', () => {
330
+ // @plan PLAN-20251027-STATELESS5.P07
331
+ // @requirement REQ-STAT5-002.1, REQ-STAT5-002.3
332
+ // @pseudocode cli-runtime-adapter.md lines 290-293
333
+ adapter.switchProvider('anthropic', { model: 'claude-3-opus-20240229' });
334
+ expect(adapter.getProvider()).toBe('anthropic');
335
+ expect(adapter.getModel()).toBe('claude-3-opus-20240229'); // Explicit model
336
+ });
337
+ it('should clear ephemeral settings when clearSettings is true', () => {
338
+ // @plan PLAN-20251027-STATELESS5.P07
339
+ // @requirement REQ-STAT5-002.3
340
+ // @pseudocode cli-runtime-adapter.md lines 302-306
341
+ adapter.switchProvider('anthropic', { clearSettings: true });
342
+ expect(config.setEphemeralSetting).toHaveBeenCalledWith('base-url', undefined);
343
+ });
344
+ it('should preserve settings when clearSettings is false', () => {
345
+ // @plan PLAN-20251027-STATELESS5.P07
346
+ // @requirement REQ-STAT5-002.3
347
+ // @pseudocode cli-runtime-adapter.md lines 302-306
348
+ const setEphemeralCalls = config.setEphemeralSetting.mock.calls.length;
349
+ adapter.switchProvider('anthropic', { clearSettings: false });
350
+ // Should not call setEphemeralSetting with undefined (except for base-url clear)
351
+ const newCalls = config.setEphemeralSetting
352
+ .mock.calls.length;
353
+ expect(newCalls).toBeGreaterThan(setEphemeralCalls);
354
+ });
355
+ it('should throw error when switching to invalid provider', () => {
356
+ // @plan PLAN-20251027-STATELESS5.P07
357
+ // @requirement REQ-STAT5-002.1
358
+ // @pseudocode cli-runtime-adapter.md lines 286-289
359
+ expect(() => adapter.switchProvider('invalid-provider')).toThrow();
360
+ expect(() => adapter.switchProvider('invalid-provider')).toThrow(/not found/);
361
+ });
362
+ it('should not emit multiple events for batch update', () => {
363
+ // @plan PLAN-20251027-STATELESS5.P07
364
+ // @requirement REQ-STAT5-002.3
365
+ // @pseudocode cli-runtime-adapter.md lines 308-312
366
+ const callback = vi.fn();
367
+ subscribeToAgentRuntimeState('test-runtime', callback);
368
+ adapter.switchProvider('anthropic');
369
+ // Should emit only 1 event despite updating provider + model + baseUrl
370
+ expect(callback).toHaveBeenCalledTimes(1);
371
+ });
372
+ });
373
+ describe('AgentRuntimeAdapter - Config Mirroring', () => {
374
+ /**
375
+ * @plan PLAN-20251027-STATELESS5.P07
376
+ * @requirement REQ-STAT5-002.3
377
+ * @pseudocode cli-runtime-adapter.md lines 329-351
378
+ *
379
+ * Tests that runtime state changes mirror to legacy Config.
380
+ */
381
+ let adapter;
382
+ let config;
383
+ beforeEach(() => {
384
+ const params = {
385
+ runtimeId: 'test-runtime',
386
+ provider: 'gemini',
387
+ model: 'gemini-2.0-flash',
388
+ authType: AuthType.USE_GEMINI,
389
+ sessionId: 'test-session',
390
+ };
391
+ const runtimeState = createAgentRuntimeState(params);
392
+ config = createMockConfig();
393
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
394
+ });
395
+ it('should mirror provider updates to config', () => {
396
+ // @plan PLAN-20251027-STATELESS5.P07
397
+ // @requirement REQ-STAT5-002.3
398
+ // @pseudocode cli-runtime-adapter.md lines 331-333
399
+ adapter.setProvider('anthropic');
400
+ expect(config.setProvider).toHaveBeenCalledWith('anthropic');
401
+ });
402
+ it('should mirror model updates to config', () => {
403
+ // @plan PLAN-20251027-STATELESS5.P07
404
+ // @requirement REQ-STAT5-002.3
405
+ // @pseudocode cli-runtime-adapter.md lines 334
406
+ adapter.setModel('gemini-2.5-flash');
407
+ expect(config.setModel).toHaveBeenCalledWith('gemini-2.5-flash');
408
+ });
409
+ it('should mirror auth type updates to config', () => {
410
+ // @plan PLAN-20251027-STATELESS5.P07
411
+ // @requirement REQ-STAT5-002.3
412
+ // @pseudocode cli-runtime-adapter.md lines 335
413
+ adapter.setAuthType(AuthType.API_KEY);
414
+ // Auth type update should be reflected in adapter
415
+ expect(adapter.getAuthType()).toBe(AuthType.API_KEY);
416
+ });
417
+ it('should mirror base URL updates to config ephemeral settings', () => {
418
+ // @plan PLAN-20251027-STATELESS5.P07
419
+ // @requirement REQ-STAT5-002.3
420
+ // @pseudocode cli-runtime-adapter.md lines 337-341
421
+ adapter.setBaseUrl('https://custom.api.com');
422
+ expect(config.setEphemeralSetting).toHaveBeenCalledWith('base-url', 'https://custom.api.com');
423
+ });
424
+ it('should clear base URL in config when set to undefined', () => {
425
+ // @plan PLAN-20251027-STATELESS5.P07
426
+ // @requirement REQ-STAT5-002.3
427
+ // @pseudocode cli-runtime-adapter.md lines 340-341
428
+ adapter.setBaseUrl('https://custom.api.com');
429
+ config.setEphemeralSetting.mockClear();
430
+ adapter.switchProvider('anthropic'); // Clears base URL
431
+ expect(config.setEphemeralSetting).toHaveBeenCalledWith('base-url', undefined);
432
+ });
433
+ it('should not mirror session ID to config', () => {
434
+ // @plan PLAN-20251027-STATELESS5.P07
435
+ // @requirement REQ-STAT5-002.3
436
+ // @pseudocode cli-runtime-adapter.md lines 349
437
+ const sessionId = adapter.getSessionId();
438
+ expect(sessionId).toBe('test-session');
439
+ // Session ID is immutable and not mirrored
440
+ expect(config.setEphemeralSetting).not.toHaveBeenCalledWith('session-id', expect.anything());
441
+ });
442
+ it('should not mirror auth payload directly to config', () => {
443
+ // @plan PLAN-20251027-STATELESS5.P07
444
+ // @requirement REQ-STAT5-002.3
445
+ // @pseudocode cli-runtime-adapter.md lines 350
446
+ adapter.setAuthType(AuthType.API_KEY);
447
+ // Auth payload is sensitive and not mirrored as ephemeral setting
448
+ expect(config.setEphemeralSetting).not.toHaveBeenCalledWith('auth-payload', expect.anything());
449
+ });
450
+ });
451
+ describe('AgentRuntimeAdapter - Lifecycle Management', () => {
452
+ /**
453
+ * @plan PLAN-20251027-STATELESS5.P07
454
+ * @requirement REQ-STAT5-002.1
455
+ * @pseudocode cli-runtime-adapter.md lines 597-609
456
+ *
457
+ * Tests adapter disposal and resource cleanup.
458
+ */
459
+ it('should unsubscribe from runtime state events on dispose', () => {
460
+ // @plan PLAN-20251027-STATELESS5.P07
461
+ // @requirement REQ-STAT5-002.1
462
+ // @pseudocode cli-runtime-adapter.md lines 598-601
463
+ const params = {
464
+ runtimeId: 'test-runtime',
465
+ provider: 'gemini',
466
+ model: 'gemini-2.0-flash',
467
+ authType: AuthType.USE_GEMINI,
468
+ sessionId: 'test-session',
469
+ };
470
+ const runtimeState = createAgentRuntimeState(params);
471
+ const config = createMockConfig();
472
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
473
+ const callback = vi.fn();
474
+ subscribeToAgentRuntimeState('test-runtime', callback);
475
+ adapter.dispose();
476
+ // After dispose, adapter should not respond to state changes
477
+ updateAgentRuntimeState(runtimeState, { model: 'gemini-2.5-flash' });
478
+ // Callback still called (not adapter's subscription)
479
+ expect(callback).toHaveBeenCalled();
480
+ });
481
+ it('should allow multiple dispose calls without error', () => {
482
+ // @plan PLAN-20251027-STATELESS5.P07
483
+ // @requirement REQ-STAT5-002.1
484
+ // @pseudocode cli-runtime-adapter.md lines 597-609
485
+ const params = {
486
+ runtimeId: 'test-runtime',
487
+ provider: 'gemini',
488
+ model: 'gemini-2.0-flash',
489
+ authType: AuthType.USE_GEMINI,
490
+ sessionId: 'test-session',
491
+ };
492
+ const runtimeState = createAgentRuntimeState(params);
493
+ const config = createMockConfig();
494
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
495
+ expect(() => {
496
+ adapter.dispose();
497
+ adapter.dispose();
498
+ }).not.toThrow();
499
+ });
500
+ });
501
+ describe('AgentRuntimeAdapter - Global Registry', () => {
502
+ /**
503
+ * @plan PLAN-20251027-STATELESS5.P07
504
+ * @requirement REQ-STAT5-002.1
505
+ * @pseudocode cli-runtime-adapter.md lines 366-376
506
+ *
507
+ * Tests global adapter registry for CLI helpers.
508
+ */
509
+ afterEach(() => {
510
+ // Reset global adapter after each test
511
+ try {
512
+ getRuntimeAdapter()?.dispose();
513
+ }
514
+ catch {
515
+ // No adapter set
516
+ }
517
+ resetRuntimeAdapter();
518
+ });
519
+ it('should set and get global runtime adapter', () => {
520
+ // @plan PLAN-20251027-STATELESS5.P07
521
+ // @requirement REQ-STAT5-002.1
522
+ // @pseudocode cli-runtime-adapter.md lines 366-376
523
+ const params = {
524
+ runtimeId: 'test-runtime',
525
+ provider: 'gemini',
526
+ model: 'gemini-2.0-flash',
527
+ authType: AuthType.USE_GEMINI,
528
+ sessionId: 'test-session',
529
+ };
530
+ const runtimeState = createAgentRuntimeState(params);
531
+ const config = createMockConfig();
532
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
533
+ setRuntimeAdapter(adapter);
534
+ const retrievedAdapter = getRuntimeAdapter();
535
+ expect(retrievedAdapter).toBe(adapter);
536
+ });
537
+ it('should throw error when getting adapter before initialization', () => {
538
+ // @plan PLAN-20251027-STATELESS5.P07
539
+ // @requirement REQ-STAT5-002.1
540
+ // @pseudocode cli-runtime-adapter.md lines 369-375
541
+ expect(() => getRuntimeAdapter()).toThrow();
542
+ expect(() => getRuntimeAdapter()).toThrow(/not initialized/);
543
+ });
544
+ });
545
+ describe('CLI Bootstrap Functions - resolveRuntimeStateFromFlags', () => {
546
+ /**
547
+ * @plan PLAN-20251027-STATELESS5.P07
548
+ * @requirement REQ-STAT5-002.2
549
+ * @pseudocode cli-runtime-adapter.md lines 138-186
550
+ *
551
+ * Tests CLI flag resolution and precedence.
552
+ */
553
+ let config;
554
+ beforeEach(() => {
555
+ config = createMockConfig();
556
+ });
557
+ it('should use config defaults when no flags provided', () => {
558
+ // @plan PLAN-20251027-STATELESS5.P07
559
+ // @requirement REQ-STAT5-002.2
560
+ // @pseudocode cli-runtime-adapter.md lines 145-152
561
+ const flags = {};
562
+ const params = resolveRuntimeStateFromFlags(flags, config);
563
+ expect(params.provider).toBe('gemini');
564
+ expect(params.model).toBe('gemini-2.0-flash');
565
+ expect(params.authType).toBe(AuthType.USE_GEMINI);
566
+ });
567
+ it('should override provider from CLI flag', () => {
568
+ // @plan PLAN-20251027-STATELESS5.P07
569
+ // @requirement REQ-STAT5-002.2
570
+ // @pseudocode cli-runtime-adapter.md lines 154-157
571
+ const flags = {
572
+ provider: 'anthropic',
573
+ };
574
+ const params = resolveRuntimeStateFromFlags(flags, config);
575
+ expect(params.provider).toBe('anthropic');
576
+ });
577
+ it('should override model from CLI flag', () => {
578
+ // @plan PLAN-20251027-STATELESS5.P07
579
+ // @requirement REQ-STAT5-002.2
580
+ // @pseudocode cli-runtime-adapter.md lines 159-160
581
+ const flags = {
582
+ model: 'gemini-2.5-flash',
583
+ };
584
+ const params = resolveRuntimeStateFromFlags(flags, config);
585
+ expect(params.model).toBe('gemini-2.5-flash');
586
+ });
587
+ it('should set API_KEY auth type from --key flag', () => {
588
+ // @plan PLAN-20251027-STATELESS5.P07
589
+ // @requirement REQ-STAT5-002.2
590
+ // @pseudocode cli-runtime-adapter.md lines 162-168
591
+ const flags = {
592
+ key: 'test-api-key-12345',
593
+ };
594
+ const params = resolveRuntimeStateFromFlags(flags, config);
595
+ expect(params.authType).toBe(AuthType.API_KEY);
596
+ expect(params.authPayload).toEqual({ apiKey: 'test-api-key-12345' });
597
+ });
598
+ it('should set API_KEY auth type from --keyfile flag', () => {
599
+ // @plan PLAN-20251027-STATELESS5.P07
600
+ // @requirement REQ-STAT5-002.2
601
+ // @pseudocode cli-runtime-adapter.md lines 162-168
602
+ const flags = {
603
+ keyfile: '/path/to/keyfile',
604
+ };
605
+ const params = resolveRuntimeStateFromFlags(flags, config);
606
+ expect(params.authType).toBe(AuthType.API_KEY);
607
+ expect(params.authPayload?.apiKey).toBeTruthy();
608
+ });
609
+ it('should process --set flag for base-url', () => {
610
+ // @plan PLAN-20251027-STATELESS5.P07
611
+ // @requirement REQ-STAT5-002.2
612
+ // @pseudocode cli-runtime-adapter.md lines 169-176
613
+ const flags = {
614
+ set: [['base-url', 'https://custom.api.com']],
615
+ };
616
+ const params = resolveRuntimeStateFromFlags(flags, config);
617
+ expect(params.baseUrl).toBe('https://custom.api.com');
618
+ });
619
+ it('should process --set flag for model params', () => {
620
+ // @plan PLAN-20251027-STATELESS5.P07
621
+ // @requirement REQ-STAT5-002.2
622
+ // @pseudocode cli-runtime-adapter.md lines 169-176
623
+ const flags = {
624
+ set: [
625
+ ['temperature', '0.9'],
626
+ ['max-tokens', '2000'],
627
+ ],
628
+ };
629
+ const params = resolveRuntimeStateFromFlags(flags, config);
630
+ expect(params.modelParams?.temperature).toBe('0.9');
631
+ expect(params.modelParams?.['max-tokens']).toBe('2000');
632
+ });
633
+ it('should prioritize CLI flags over config defaults', () => {
634
+ // @plan PLAN-20251027-STATELESS5.P07
635
+ // @requirement REQ-STAT5-002.2
636
+ // @pseudocode cli-runtime-adapter.md lines 154-160
637
+ const flags = {
638
+ provider: 'anthropic',
639
+ model: 'claude-3-opus-20240229',
640
+ };
641
+ const params = resolveRuntimeStateFromFlags(flags, config);
642
+ expect(params.provider).toBe('anthropic');
643
+ expect(params.model).toBe('claude-3-opus-20240229');
644
+ });
645
+ });
646
+ describe('CLI Bootstrap Functions - bootstrapForegroundAgent', () => {
647
+ /**
648
+ * @plan PLAN-20251027-STATELESS5.P07
649
+ * @requirement REQ-STAT5-002.2
650
+ * @pseudocode cli-runtime-adapter.md lines 101-132
651
+ *
652
+ * Tests full foreground agent bootstrap flow.
653
+ */
654
+ let config;
655
+ beforeEach(() => {
656
+ config = createMockConfig();
657
+ });
658
+ it('should bootstrap foreground agent with adapter and client', async () => {
659
+ // @plan PLAN-20251027-STATELESS5.P07
660
+ // @requirement REQ-STAT5-002.2
661
+ // @pseudocode cli-runtime-adapter.md lines 101-132
662
+ const flags = {
663
+ provider: 'gemini',
664
+ model: 'gemini-2.0-flash',
665
+ };
666
+ const result = await bootstrapForegroundAgent(flags, config);
667
+ expect(result.adapter.getProvider()).toBe('gemini');
668
+ expect(result.adapter.getModel()).toBe('gemini-2.0-flash');
669
+ });
670
+ it('should create runtime state from resolved flags', async () => {
671
+ // @plan PLAN-20251027-STATELESS5.P07
672
+ // @requirement REQ-STAT5-002.2
673
+ // @pseudocode cli-runtime-adapter.md lines 106-113
674
+ const flags = {
675
+ provider: 'anthropic',
676
+ model: 'claude-3-5-sonnet-20241022',
677
+ };
678
+ const result = await bootstrapForegroundAgent(flags, config);
679
+ expect(result.adapter.getProvider()).toBe('anthropic');
680
+ expect(result.adapter.getModel()).toBe('claude-3-5-sonnet-20241022');
681
+ });
682
+ it('should create adapter with runtime state and config', async () => {
683
+ // @plan PLAN-20251027-STATELESS5.P07
684
+ // @requirement REQ-STAT5-002.2
685
+ // @pseudocode cli-runtime-adapter.md lines 115-116
686
+ const flags = {
687
+ provider: 'gemini',
688
+ };
689
+ const result = await bootstrapForegroundAgent(flags, config);
690
+ const state = result.adapter.getRuntimeState();
691
+ expect(state.runtimeId).toBeTruthy();
692
+ expect(state.provider).toBe('gemini');
693
+ });
694
+ it('should pass runtime state to GeminiClient', async () => {
695
+ // @plan PLAN-20251027-STATELESS5.P07
696
+ // @requirement REQ-STAT5-002.2
697
+ // @pseudocode cli-runtime-adapter.md lines 124-129
698
+ const flags = {
699
+ provider: 'gemini',
700
+ };
701
+ const result = await bootstrapForegroundAgent(flags, config);
702
+ // Client should have access to runtime state
703
+ expect(result.client).toBeTruthy();
704
+ });
705
+ });
706
+ describe('Legacy Helper Functions - Provider Operations', () => {
707
+ /**
708
+ * @plan PLAN-20251027-STATELESS5.P07
709
+ * @requirement REQ-STAT5-002.1
710
+ * @pseudocode cli-runtime-adapter.md lines 378-398
711
+ *
712
+ * Tests legacy helper functions that delegate to adapter.
713
+ */
714
+ let adapter;
715
+ beforeEach(() => {
716
+ const params = {
717
+ runtimeId: 'test-runtime',
718
+ provider: 'gemini',
719
+ model: 'gemini-2.0-flash',
720
+ authType: AuthType.USE_GEMINI,
721
+ sessionId: 'test-session',
722
+ };
723
+ const runtimeState = createAgentRuntimeState(params);
724
+ const config = createMockConfig();
725
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
726
+ setRuntimeAdapter(adapter);
727
+ });
728
+ afterEach(() => {
729
+ adapter.dispose();
730
+ resetRuntimeAdapter();
731
+ });
732
+ it('should set provider via setRuntimeProvider helper', () => {
733
+ // @plan PLAN-20251027-STATELESS5.P07
734
+ // @requirement REQ-STAT5-002.1
735
+ // @pseudocode cli-runtime-adapter.md lines 378-381
736
+ setRuntimeProvider('anthropic');
737
+ expect(getRuntimeProvider()).toBe('anthropic');
738
+ });
739
+ it('should get provider via getRuntimeProvider helper', () => {
740
+ // @plan PLAN-20251027-STATELESS5.P07
741
+ // @requirement REQ-STAT5-002.1
742
+ // @pseudocode cli-runtime-adapter.md lines 383-386
743
+ const provider = getRuntimeProvider();
744
+ expect(provider).toBe('gemini');
745
+ });
746
+ it('should set model via setRuntimeModel helper', () => {
747
+ // @plan PLAN-20251027-STATELESS5.P07
748
+ // @requirement REQ-STAT5-002.1
749
+ // @pseudocode cli-runtime-adapter.md lines 388-390
750
+ setRuntimeModel('gemini-2.5-flash');
751
+ expect(getRuntimeModel()).toBe('gemini-2.5-flash');
752
+ });
753
+ it('should get model via getRuntimeModel helper', () => {
754
+ // @plan PLAN-20251027-STATELESS5.P07
755
+ // @requirement REQ-STAT5-002.1
756
+ // @pseudocode cli-runtime-adapter.md lines 392-394
757
+ const model = getRuntimeModel();
758
+ expect(model).toBe('gemini-2.0-flash');
759
+ });
760
+ it('should switch provider atomically via switchRuntimeProvider helper', () => {
761
+ // @plan PLAN-20251027-STATELESS5.P07
762
+ // @requirement REQ-STAT5-002.1
763
+ // @pseudocode cli-runtime-adapter.md lines 396-398
764
+ switchRuntimeProvider('anthropic', 'claude-3-opus-20240229');
765
+ expect(getRuntimeProvider()).toBe('anthropic');
766
+ expect(getRuntimeModel()).toBe('claude-3-opus-20240229');
767
+ });
768
+ it('should use default model when switching provider without explicit model', () => {
769
+ // @plan PLAN-20251027-STATELESS5.P07
770
+ // @requirement REQ-STAT5-002.1
771
+ // @pseudocode cli-runtime-adapter.md lines 396-398
772
+ switchRuntimeProvider('anthropic');
773
+ expect(getRuntimeProvider()).toBe('anthropic');
774
+ expect(getRuntimeModel()).toBe('claude-3-5-sonnet-20241022'); // Default model
775
+ });
776
+ });
777
+ describe('AgentRuntimeAdapter - Event Handling', () => {
778
+ /**
779
+ * @plan PLAN-20251027-STATELESS5.P07
780
+ * @requirement REQ-STAT5-002.1
781
+ * @pseudocode cli-runtime-adapter.md lines 76-87
782
+ *
783
+ * Tests that adapter responds to runtime state changes.
784
+ */
785
+ it('should mirror state changes to config when subscribed', () => {
786
+ // @plan PLAN-20251027-STATELESS5.P07
787
+ // @requirement REQ-STAT5-002.3
788
+ // @pseudocode cli-runtime-adapter.md lines 76-87
789
+ const params = {
790
+ runtimeId: 'test-runtime',
791
+ provider: 'gemini',
792
+ model: 'gemini-2.0-flash',
793
+ authType: AuthType.USE_GEMINI,
794
+ sessionId: 'test-session',
795
+ };
796
+ const runtimeState = createAgentRuntimeState(params);
797
+ const config = createMockConfig();
798
+ new AgentRuntimeAdapter(runtimeState, config);
799
+ config.setModel.mockClear();
800
+ // Update runtime state externally
801
+ updateAgentRuntimeState(runtimeState, { model: 'gemini-2.5-flash' });
802
+ // Adapter should have mirrored to config
803
+ expect(config.setModel).toHaveBeenCalledWith('gemini-2.5-flash');
804
+ });
805
+ it('should update local runtime state reference on change event', () => {
806
+ // @plan PLAN-20251027-STATELESS5.P07
807
+ // @requirement REQ-STAT5-002.1
808
+ // @pseudocode cli-runtime-adapter.md lines 77-78
809
+ const params = {
810
+ runtimeId: 'test-runtime',
811
+ provider: 'gemini',
812
+ model: 'gemini-2.0-flash',
813
+ authType: AuthType.USE_GEMINI,
814
+ sessionId: 'test-session',
815
+ };
816
+ const runtimeState = createAgentRuntimeState(params);
817
+ const config = createMockConfig();
818
+ const adapter = new AgentRuntimeAdapter(runtimeState, config);
819
+ // Update runtime state externally
820
+ updateAgentRuntimeState(runtimeState, { model: 'gemini-2.5-flash' });
821
+ // Adapter should reflect the change
822
+ expect(adapter.getModel()).toBe('gemini-2.5-flash');
823
+ });
824
+ });
825
+ describe('AgentRuntimeAdapter - Error Handling', () => {
826
+ /**
827
+ * @plan PLAN-20251027-STATELESS5.P07
828
+ * @requirement REQ-STAT5-001.1
829
+ * @pseudocode cli-runtime-adapter.md lines 569-592
830
+ *
831
+ * Tests adapter-level error handling and validation.
832
+ */
833
+ let adapter;
834
+ beforeEach(() => {
835
+ const params = {
836
+ runtimeId: 'test-runtime',
837
+ provider: 'gemini',
838
+ model: 'gemini-2.0-flash',
839
+ authType: AuthType.USE_GEMINI,
840
+ sessionId: 'test-session',
841
+ };
842
+ const runtimeState = createAgentRuntimeState(params);
843
+ const config = createMockConfig();
844
+ adapter = new AgentRuntimeAdapter(runtimeState, config);
845
+ });
846
+ it('should throw descriptive error for invalid provider', () => {
847
+ // @plan PLAN-20251027-STATELESS5.P07
848
+ // @requirement REQ-STAT5-001.1
849
+ // @pseudocode cli-runtime-adapter.md lines 575-579
850
+ expect(() => adapter.setProvider('invalid-provider')).toThrow();
851
+ expect(() => adapter.setProvider('invalid-provider')).toThrow(/not found/);
852
+ });
853
+ it('should include available providers in error message', () => {
854
+ // @plan PLAN-20251027-STATELESS5.P07
855
+ // @requirement REQ-STAT5-001.1
856
+ // @pseudocode cli-runtime-adapter.md lines 575-579
857
+ try {
858
+ adapter.setProvider('invalid-provider');
859
+ expect.fail('Should have thrown error');
860
+ }
861
+ catch (error) {
862
+ expect(error.message).toMatch(/gemini|anthropic|openai/);
863
+ }
864
+ });
865
+ });
866
+ //# sourceMappingURL=agentRuntimeAdapter.spec.js.map