@vybestack/llxprt-code 0.1.20 → 0.1.22

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 (414) hide show
  1. package/README.md +31 -0
  2. package/dist/package.json +3 -3
  3. package/dist/src/commands/mcp/add.js +11 -0
  4. package/dist/src/commands/mcp/add.js.map +1 -1
  5. package/dist/src/config/auth.test.d.ts +6 -0
  6. package/dist/src/config/auth.test.js +57 -0
  7. package/dist/src/config/auth.test.js.map +1 -0
  8. package/dist/src/config/config.d.ts +1 -1
  9. package/dist/src/config/config.js +27 -14
  10. package/dist/src/config/config.js.map +1 -1
  11. package/dist/src/config/keyBindings.js +3 -2
  12. package/dist/src/config/keyBindings.js.map +1 -1
  13. package/dist/src/config/keyBindings.test.d.ts +6 -0
  14. package/dist/src/config/keyBindings.test.js +51 -0
  15. package/dist/src/config/keyBindings.test.js.map +1 -0
  16. package/dist/src/config/logging/loggingConfig.test.d.ts +6 -0
  17. package/dist/src/config/logging/loggingConfig.test.js +363 -0
  18. package/dist/src/config/logging/loggingConfig.test.js.map +1 -0
  19. package/dist/src/config/settingsSchema.d.ts +0 -9
  20. package/dist/src/config/settingsSchema.js +0 -9
  21. package/dist/src/config/settingsSchema.js.map +1 -1
  22. package/dist/src/config/settingsSchema.test.d.ts +6 -0
  23. package/dist/src/config/settingsSchema.test.js +195 -0
  24. package/dist/src/config/settingsSchema.test.js.map +1 -0
  25. package/dist/src/config/trustedFolders.test.d.ts +6 -0
  26. package/dist/src/config/trustedFolders.test.js +156 -0
  27. package/dist/src/config/trustedFolders.test.js.map +1 -0
  28. package/dist/src/gemini.js +14 -4
  29. package/dist/src/gemini.js.map +1 -1
  30. package/dist/src/gemini.test.d.ts +6 -0
  31. package/dist/src/gemini.test.js +199 -0
  32. package/dist/src/gemini.test.js.map +1 -0
  33. package/dist/src/generated/git-commit.d.ts +1 -1
  34. package/dist/src/generated/git-commit.js +1 -1
  35. package/dist/src/integration-tests/base-url-behavior.integration.test.d.ts +6 -0
  36. package/dist/src/integration-tests/base-url-behavior.integration.test.js +492 -0
  37. package/dist/src/integration-tests/base-url-behavior.integration.test.js.map +1 -0
  38. package/dist/src/integration-tests/cli-args.integration.test.d.ts +6 -0
  39. package/dist/src/integration-tests/cli-args.integration.test.js +398 -0
  40. package/dist/src/integration-tests/cli-args.integration.test.js.map +1 -0
  41. package/dist/src/integration-tests/compression-settings-apply.integration.test.d.ts +6 -0
  42. package/dist/src/integration-tests/compression-settings-apply.integration.test.js +436 -0
  43. package/dist/src/integration-tests/compression-settings-apply.integration.test.js.map +1 -0
  44. package/dist/src/integration-tests/ephemeral-settings.integration.test.d.ts +6 -0
  45. package/dist/src/integration-tests/ephemeral-settings.integration.test.js +318 -0
  46. package/dist/src/integration-tests/ephemeral-settings.integration.test.js.map +1 -0
  47. package/dist/src/integration-tests/model-params-isolation.integration.test.d.ts +6 -0
  48. package/dist/src/integration-tests/model-params-isolation.integration.test.js +564 -0
  49. package/dist/src/integration-tests/model-params-isolation.integration.test.js.map +1 -0
  50. package/dist/src/integration-tests/modelParams.integration.test.d.ts +6 -0
  51. package/dist/src/integration-tests/modelParams.integration.test.js +784 -0
  52. package/dist/src/integration-tests/modelParams.integration.test.js.map +1 -0
  53. package/dist/src/integration-tests/profile-keyfile.integration.test.d.ts +6 -0
  54. package/dist/src/integration-tests/profile-keyfile.integration.test.js +429 -0
  55. package/dist/src/integration-tests/profile-keyfile.integration.test.js.map +1 -0
  56. package/dist/src/integration-tests/profile-system.integration.test.d.ts +6 -0
  57. package/dist/src/integration-tests/profile-system.integration.test.js +364 -0
  58. package/dist/src/integration-tests/profile-system.integration.test.js.map +1 -0
  59. package/dist/src/integration-tests/provider-switching.integration.test.d.ts +6 -0
  60. package/dist/src/integration-tests/provider-switching.integration.test.js +207 -0
  61. package/dist/src/integration-tests/provider-switching.integration.test.js.map +1 -0
  62. package/dist/src/integration-tests/security.integration.test.d.ts +6 -0
  63. package/dist/src/integration-tests/security.integration.test.js +319 -0
  64. package/dist/src/integration-tests/security.integration.test.js.map +1 -0
  65. package/dist/src/integration-tests/test-utils.test.d.ts +6 -0
  66. package/dist/src/integration-tests/test-utils.test.js +221 -0
  67. package/dist/src/integration-tests/test-utils.test.js.map +1 -0
  68. package/dist/src/integration-tests/todo-continuation.integration.test.d.ts +6 -0
  69. package/dist/src/integration-tests/todo-continuation.integration.test.js +559 -0
  70. package/dist/src/integration-tests/todo-continuation.integration.test.js.map +1 -0
  71. package/dist/src/nonInteractiveCli.js +2 -5
  72. package/dist/src/nonInteractiveCli.js.map +1 -1
  73. package/dist/src/providers/logging/LoggingProviderWrapper.test.d.ts +6 -0
  74. package/dist/src/providers/logging/LoggingProviderWrapper.test.js +305 -0
  75. package/dist/src/providers/logging/LoggingProviderWrapper.test.js.map +1 -0
  76. package/dist/src/providers/logging/git-stats.integration.test.d.ts +6 -0
  77. package/dist/src/providers/logging/git-stats.integration.test.js +245 -0
  78. package/dist/src/providers/logging/git-stats.integration.test.js.map +1 -0
  79. package/dist/src/providers/logging/git-stats.test.d.ts +6 -0
  80. package/dist/src/providers/logging/git-stats.test.js +432 -0
  81. package/dist/src/providers/logging/git-stats.test.js.map +1 -0
  82. package/dist/src/providers/logging/multi-provider-logging.integration.test.d.ts +6 -0
  83. package/dist/src/providers/logging/multi-provider-logging.integration.test.js +531 -0
  84. package/dist/src/providers/logging/multi-provider-logging.integration.test.js.map +1 -0
  85. package/dist/src/providers/logging/performance.test.d.ts +6 -0
  86. package/dist/src/providers/logging/performance.test.js +465 -0
  87. package/dist/src/providers/logging/performance.test.js.map +1 -0
  88. package/dist/src/providers/provider-gemini-switching.test.d.ts +6 -0
  89. package/dist/src/providers/provider-gemini-switching.test.js +129 -0
  90. package/dist/src/providers/provider-gemini-switching.test.js.map +1 -0
  91. package/dist/src/providers/provider-switching.integration.test.d.ts +6 -0
  92. package/dist/src/providers/provider-switching.integration.test.js +113 -0
  93. package/dist/src/providers/provider-switching.integration.test.js.map +1 -0
  94. package/dist/src/providers/providerManagerInstance.test.d.ts +6 -0
  95. package/dist/src/providers/providerManagerInstance.test.js +104 -0
  96. package/dist/src/providers/providerManagerInstance.test.js.map +1 -0
  97. package/dist/src/services/BuiltinCommandLoader.test.d.ts +6 -0
  98. package/dist/src/services/BuiltinCommandLoader.test.js +118 -0
  99. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -0
  100. package/dist/src/services/CommandService.test.d.ts +6 -0
  101. package/dist/src/services/CommandService.test.js +232 -0
  102. package/dist/src/services/CommandService.test.js.map +1 -0
  103. package/dist/src/services/FileCommandLoader.js +10 -8
  104. package/dist/src/services/FileCommandLoader.js.map +1 -1
  105. package/dist/src/services/prompt-processors/argumentProcessor.d.ts +2 -7
  106. package/dist/src/services/prompt-processors/argumentProcessor.js +2 -10
  107. package/dist/src/services/prompt-processors/argumentProcessor.js.map +1 -1
  108. package/dist/src/services/prompt-processors/shellProcessor.d.ts +16 -13
  109. package/dist/src/services/prompt-processors/shellProcessor.js +133 -40
  110. package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -1
  111. package/dist/src/services/prompt-processors/types.d.ts +2 -0
  112. package/dist/src/services/prompt-processors/types.js +2 -0
  113. package/dist/src/services/prompt-processors/types.js.map +1 -1
  114. package/dist/src/storage/ConversationStorage.test.d.ts +6 -0
  115. package/dist/src/storage/ConversationStorage.test.js +379 -0
  116. package/dist/src/storage/ConversationStorage.test.js.map +1 -0
  117. package/dist/src/test-utils/customMatchers.d.ts +14 -0
  118. package/dist/src/test-utils/customMatchers.js +46 -0
  119. package/dist/src/test-utils/customMatchers.js.map +1 -0
  120. package/dist/src/test-utils/mockCommandContext.d.ts +18 -0
  121. package/dist/src/test-utils/mockCommandContext.js +86 -0
  122. package/dist/src/test-utils/mockCommandContext.js.map +1 -0
  123. package/dist/src/test-utils/mockCommandContext.test.d.ts +6 -0
  124. package/dist/src/test-utils/mockCommandContext.test.js +51 -0
  125. package/dist/src/test-utils/mockCommandContext.test.js.map +1 -0
  126. package/dist/src/test-utils/render.d.ts +8 -0
  127. package/dist/src/test-utils/render.js +10 -0
  128. package/dist/src/test-utils/render.js.map +1 -0
  129. package/dist/src/test-utils/responsive-testing.d.ts +14 -0
  130. package/dist/src/test-utils/responsive-testing.js +35 -0
  131. package/dist/src/test-utils/responsive-testing.js.map +1 -0
  132. package/dist/src/test-utils/responsive-testing.test.d.ts +6 -0
  133. package/dist/src/test-utils/responsive-testing.test.js +89 -0
  134. package/dist/src/test-utils/responsive-testing.test.js.map +1 -0
  135. package/dist/src/test-utils/testProviderConfig.d.ts +18 -0
  136. package/dist/src/test-utils/testProviderConfig.js +19 -0
  137. package/dist/src/test-utils/testProviderConfig.js.map +1 -0
  138. package/dist/src/ui/App.js +7 -6
  139. package/dist/src/ui/App.js.map +1 -1
  140. package/dist/src/ui/IdeIntegrationNudge.js +1 -1
  141. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  142. package/dist/src/ui/colors.js +25 -2
  143. package/dist/src/ui/colors.js.map +1 -1
  144. package/dist/src/ui/commands/aboutCommand.js +3 -0
  145. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  146. package/dist/src/ui/commands/chatCommand.js +8 -6
  147. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  148. package/dist/src/ui/commands/diagnosticsCommand.js +0 -1
  149. package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -1
  150. package/dist/src/ui/commands/ideCommand.js +3 -3
  151. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  152. package/dist/src/ui/commands/keyCommand.test.d.ts +6 -0
  153. package/dist/src/ui/commands/keyCommand.test.js +128 -0
  154. package/dist/src/ui/commands/keyCommand.test.js.map +1 -0
  155. package/dist/src/ui/commands/profileCommand.test.d.ts +6 -0
  156. package/dist/src/ui/commands/profileCommand.test.js +343 -0
  157. package/dist/src/ui/commands/profileCommand.test.js.map +1 -0
  158. package/dist/src/ui/commands/setCommand.js +41 -0
  159. package/dist/src/ui/commands/setCommand.js.map +1 -1
  160. package/dist/src/ui/commands/setCommand.test.d.ts +6 -0
  161. package/dist/src/ui/commands/setCommand.test.js +431 -0
  162. package/dist/src/ui/commands/setCommand.test.js.map +1 -0
  163. package/dist/src/ui/commands/setupGithubCommand.test.d.ts +6 -0
  164. package/dist/src/ui/commands/setupGithubCommand.test.js +69 -0
  165. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -0
  166. package/dist/src/ui/commands/toolformatCommand.test.d.ts +1 -0
  167. package/dist/src/ui/commands/toolformatCommand.test.js +145 -0
  168. package/dist/src/ui/commands/toolformatCommand.test.js.map +1 -0
  169. package/dist/src/ui/components/AboutBox.d.ts +1 -0
  170. package/dist/src/ui/components/AboutBox.js +1 -1
  171. package/dist/src/ui/components/AboutBox.js.map +1 -1
  172. package/dist/src/ui/components/AuthDialog.js +1 -1
  173. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  174. package/dist/src/ui/components/AuthDialog.test.d.ts +6 -0
  175. package/dist/src/ui/components/AuthDialog.test.js +252 -0
  176. package/dist/src/ui/components/AuthDialog.test.js.map +1 -0
  177. package/dist/src/ui/components/ContextIndicator.ui.test.d.ts +1 -0
  178. package/dist/src/ui/components/ContextIndicator.ui.test.js +89 -0
  179. package/dist/src/ui/components/ContextIndicator.ui.test.js.map +1 -0
  180. package/dist/src/ui/components/ContextSummaryDisplay.js +1 -1
  181. package/dist/src/ui/components/ContextUsageDisplay.semantic.test.d.ts +6 -0
  182. package/dist/src/ui/components/ContextUsageDisplay.semantic.test.js +75 -0
  183. package/dist/src/ui/components/ContextUsageDisplay.semantic.test.js.map +1 -0
  184. package/dist/src/ui/components/FolderTrustDialog.test.d.ts +6 -0
  185. package/dist/src/ui/components/FolderTrustDialog.test.js +26 -0
  186. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -0
  187. package/dist/src/ui/components/Footer.d.ts +1 -0
  188. package/dist/src/ui/components/Footer.js +2 -2
  189. package/dist/src/ui/components/Footer.js.map +1 -1
  190. package/dist/src/ui/components/Footer.responsive.test.d.ts +6 -0
  191. package/dist/src/ui/components/Footer.responsive.test.js +262 -0
  192. package/dist/src/ui/components/Footer.responsive.test.js.map +1 -0
  193. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  194. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  195. package/dist/src/ui/components/HistoryItemDisplay.test.d.ts +6 -0
  196. package/dist/src/ui/components/HistoryItemDisplay.test.js +93 -0
  197. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -0
  198. package/dist/src/ui/components/InputPrompt.js +0 -4
  199. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  200. package/dist/src/ui/components/InputPrompt.paste.test.d.ts +6 -0
  201. package/dist/src/ui/components/InputPrompt.paste.test.js +263 -0
  202. package/dist/src/ui/components/InputPrompt.paste.test.js.map +1 -0
  203. package/dist/src/ui/components/LoadingIndicator.test.d.ts +6 -0
  204. package/dist/src/ui/components/LoadingIndicator.test.js +149 -0
  205. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -0
  206. package/dist/src/ui/components/MemoryUsageDisplay.semantic.test.d.ts +6 -0
  207. package/dist/src/ui/components/MemoryUsageDisplay.semantic.test.js +127 -0
  208. package/dist/src/ui/components/MemoryUsageDisplay.semantic.test.js.map +1 -0
  209. package/dist/src/ui/components/ProviderDialog.responsive.test.d.ts +6 -0
  210. package/dist/src/ui/components/ProviderDialog.responsive.test.js +153 -0
  211. package/dist/src/ui/components/ProviderDialog.responsive.test.js.map +1 -0
  212. package/dist/src/ui/components/ProviderModelDialog.responsive.test.d.ts +6 -0
  213. package/dist/src/ui/components/ProviderModelDialog.responsive.test.js +252 -0
  214. package/dist/src/ui/components/ProviderModelDialog.responsive.test.js.map +1 -0
  215. package/dist/src/ui/components/ProviderModelDialog.test.d.ts +6 -0
  216. package/dist/src/ui/components/ProviderModelDialog.test.js +197 -0
  217. package/dist/src/ui/components/ProviderModelDialog.test.js.map +1 -0
  218. package/dist/src/ui/components/SettingsDialog.test.d.ts +6 -0
  219. package/dist/src/ui/components/SettingsDialog.test.js +555 -0
  220. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -0
  221. package/dist/src/ui/components/ShellConfirmationDialog.js +2 -1
  222. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  223. package/dist/src/ui/components/ShellConfirmationDialog.test.d.ts +6 -0
  224. package/dist/src/ui/components/ShellConfirmationDialog.test.js +40 -0
  225. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -0
  226. package/dist/src/ui/components/TodoPanel.responsive.test.d.ts +6 -0
  227. package/dist/src/ui/components/TodoPanel.responsive.test.js +221 -0
  228. package/dist/src/ui/components/TodoPanel.responsive.test.js.map +1 -0
  229. package/dist/src/ui/components/TodoPanel.semantic.test.d.ts +6 -0
  230. package/dist/src/ui/components/TodoPanel.semantic.test.js +137 -0
  231. package/dist/src/ui/components/TodoPanel.semantic.test.js.map +1 -0
  232. package/dist/src/ui/components/__tests__/LayoutManager.test.d.ts +6 -0
  233. package/dist/src/ui/components/__tests__/LayoutManager.test.js +94 -0
  234. package/dist/src/ui/components/__tests__/LayoutManager.test.js.map +1 -0
  235. package/dist/src/ui/components/messages/DiffRenderer.js +9 -3
  236. package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
  237. package/dist/src/ui/components/messages/DiffRenderer.test.d.ts +6 -0
  238. package/dist/src/ui/components/messages/DiffRenderer.test.js +266 -0
  239. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -0
  240. package/dist/src/ui/components/messages/InfoMessage.js +2 -1
  241. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  242. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +15 -5
  243. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  244. package/dist/src/ui/components/messages/ToolConfirmationMessage.responsive.test.d.ts +6 -0
  245. package/dist/src/ui/components/messages/ToolConfirmationMessage.responsive.test.js +173 -0
  246. package/dist/src/ui/components/messages/ToolConfirmationMessage.responsive.test.js.map +1 -0
  247. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.d.ts +6 -0
  248. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +37 -0
  249. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -0
  250. package/dist/src/ui/components/messages/ToolMessage.test.d.ts +6 -0
  251. package/dist/src/ui/components/messages/ToolMessage.test.js +118 -0
  252. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -0
  253. package/dist/src/ui/components/shared/MaxSizedBox.test.d.ts +6 -0
  254. package/dist/src/ui/components/shared/MaxSizedBox.test.js +154 -0
  255. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -0
  256. package/dist/src/ui/components/shared/RadioButtonSelect.js +1 -1
  257. package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
  258. package/dist/src/ui/components/shared/RadioButtonSelect.test.d.ts +6 -0
  259. package/dist/src/ui/components/shared/RadioButtonSelect.test.js +113 -0
  260. package/dist/src/ui/components/shared/RadioButtonSelect.test.js.map +1 -0
  261. package/dist/src/ui/containers/SessionController.test.d.ts +6 -0
  262. package/dist/src/ui/containers/SessionController.test.js +440 -0
  263. package/dist/src/ui/containers/SessionController.test.js.map +1 -0
  264. package/dist/src/ui/contexts/KeypressContext.d.ts +30 -0
  265. package/dist/src/ui/contexts/KeypressContext.js +314 -0
  266. package/dist/src/ui/contexts/KeypressContext.js.map +1 -0
  267. package/dist/src/ui/contexts/KeypressContext.test.d.ts +6 -0
  268. package/dist/src/ui/contexts/KeypressContext.test.js +220 -0
  269. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -0
  270. package/dist/src/ui/hooks/atCommandProcessor.test.d.ts +6 -0
  271. package/dist/src/ui/hooks/atCommandProcessor.test.js +830 -0
  272. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -0
  273. package/dist/src/ui/hooks/index.d.ts +1 -0
  274. package/dist/src/ui/hooks/index.js +1 -0
  275. package/dist/src/ui/hooks/index.js.map +1 -1
  276. package/dist/src/ui/hooks/shellCommandProcessor.test.d.ts +6 -0
  277. package/dist/src/ui/hooks/shellCommandProcessor.test.js +328 -0
  278. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -0
  279. package/dist/src/ui/hooks/slashCommandProcessor.js +13 -7
  280. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  281. package/dist/src/ui/hooks/useAtCompletion.js +3 -5
  282. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  283. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.d.ts +6 -0
  284. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +191 -0
  285. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -0
  286. package/dist/src/ui/hooks/useEditorSettings.test.d.ts +6 -0
  287. package/dist/src/ui/hooks/useEditorSettings.test.js +221 -0
  288. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -0
  289. package/dist/src/ui/hooks/useGeminiStream.integration.test.d.ts +6 -0
  290. package/dist/src/ui/hooks/useGeminiStream.integration.test.js +800 -0
  291. package/dist/src/ui/hooks/useGeminiStream.integration.test.js.map +1 -0
  292. package/dist/src/ui/hooks/useGeminiStream.js +12 -47
  293. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  294. package/dist/src/ui/hooks/useGitBranchName.test.d.ts +6 -0
  295. package/dist/src/ui/hooks/useGitBranchName.test.js +170 -0
  296. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -0
  297. package/dist/src/ui/hooks/useHistoryManager.test.d.ts +6 -0
  298. package/dist/src/ui/hooks/useHistoryManager.test.js +171 -0
  299. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -0
  300. package/dist/src/ui/hooks/useInputHistory.test.d.ts +6 -0
  301. package/dist/src/ui/hooks/useInputHistory.test.js +207 -0
  302. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -0
  303. package/dist/src/ui/hooks/useKeypress.d.ts +4 -24
  304. package/dist/src/ui/hooks/useKeypress.js +9 -330
  305. package/dist/src/ui/hooks/useKeypress.js.map +1 -1
  306. package/dist/src/ui/hooks/useKeypress.test.d.ts +6 -0
  307. package/dist/src/ui/hooks/useKeypress.test.js +176 -0
  308. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -0
  309. package/dist/src/ui/hooks/usePhraseCycler.js +1 -0
  310. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  311. package/dist/src/ui/hooks/useResponsive.test.d.ts +6 -0
  312. package/dist/src/ui/hooks/useResponsive.test.js +124 -0
  313. package/dist/src/ui/hooks/useResponsive.test.js.map +1 -0
  314. package/dist/src/ui/hooks/useReverseSearchCompletion.test.d.ts +6 -0
  315. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +163 -0
  316. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -0
  317. package/dist/src/ui/hooks/useShellHistory.test.d.ts +6 -0
  318. package/dist/src/ui/hooks/useShellHistory.test.js +162 -0
  319. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -0
  320. package/dist/src/ui/hooks/useSlashCompletion.test.d.ts +6 -0
  321. package/dist/src/ui/hooks/useSlashCompletion.test.js +929 -0
  322. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -0
  323. package/dist/src/ui/hooks/useStableCallback.test.d.ts +6 -0
  324. package/dist/src/ui/hooks/useStableCallback.test.js +57 -0
  325. package/dist/src/ui/hooks/useStableCallback.test.js.map +1 -0
  326. package/dist/src/ui/hooks/useToolScheduler.test.d.ts +6 -0
  327. package/dist/src/ui/hooks/useToolScheduler.test.js +841 -0
  328. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -0
  329. package/dist/src/ui/keyMatchers.test.d.ts +6 -0
  330. package/dist/src/ui/keyMatchers.test.js +276 -0
  331. package/dist/src/ui/keyMatchers.test.js.map +1 -0
  332. package/dist/src/ui/reducers/appReducer.test.d.ts +6 -0
  333. package/dist/src/ui/reducers/appReducer.test.js +519 -0
  334. package/dist/src/ui/reducers/appReducer.test.js.map +1 -0
  335. package/dist/src/ui/themes/color-utils.test.d.ts +6 -0
  336. package/dist/src/ui/themes/color-utils.test.js +197 -0
  337. package/dist/src/ui/themes/color-utils.test.js.map +1 -0
  338. package/dist/src/ui/themes/semantic-resolver.js +16 -7
  339. package/dist/src/ui/themes/semantic-resolver.js.map +1 -1
  340. package/dist/src/ui/themes/semantic-resolver.test.d.ts +6 -0
  341. package/dist/src/ui/themes/semantic-resolver.test.js +246 -0
  342. package/dist/src/ui/themes/semantic-resolver.test.js.map +1 -0
  343. package/dist/src/ui/themes/semantic-tokens.d.ts +18 -33
  344. package/dist/src/ui/themes/semantic-tokens.js +88 -1
  345. package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
  346. package/dist/src/ui/themes/semantic-tokens.test.d.ts +6 -0
  347. package/dist/src/ui/themes/semantic-tokens.test.js +289 -0
  348. package/dist/src/ui/themes/semantic-tokens.test.js.map +1 -0
  349. package/dist/src/ui/themes/theme-compat.d.ts +1 -1
  350. package/dist/src/ui/themes/theme-compat.js +7 -2
  351. package/dist/src/ui/themes/theme-compat.js.map +1 -1
  352. package/dist/src/ui/themes/theme-manager.test.d.ts +6 -0
  353. package/dist/src/ui/themes/theme-manager.test.js +160 -0
  354. package/dist/src/ui/themes/theme-manager.test.js.map +1 -0
  355. package/dist/src/ui/types.d.ts +12 -1
  356. package/dist/src/ui/types.js +1 -0
  357. package/dist/src/ui/types.js.map +1 -1
  358. package/dist/src/ui/utils/InlineMarkdownRenderer.js +8 -1
  359. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  360. package/dist/src/ui/utils/MarkdownDisplay.test.d.ts +6 -0
  361. package/dist/src/ui/utils/MarkdownDisplay.test.js +151 -0
  362. package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -0
  363. package/dist/src/ui/utils/clipboardUtils.test.d.ts +6 -0
  364. package/dist/src/ui/utils/clipboardUtils.test.js +65 -0
  365. package/dist/src/ui/utils/clipboardUtils.test.js.map +1 -0
  366. package/dist/src/ui/utils/commandUtils.test.d.ts +6 -0
  367. package/dist/src/ui/utils/commandUtils.test.js +294 -0
  368. package/dist/src/ui/utils/commandUtils.test.js.map +1 -0
  369. package/dist/src/ui/utils/displayUtils.test.d.ts +6 -0
  370. package/dist/src/ui/utils/displayUtils.test.js +42 -0
  371. package/dist/src/ui/utils/displayUtils.test.js.map +1 -0
  372. package/dist/src/ui/utils/formatters.test.d.ts +6 -0
  373. package/dist/src/ui/utils/formatters.test.js +56 -0
  374. package/dist/src/ui/utils/formatters.test.js.map +1 -0
  375. package/dist/src/ui/utils/markdownUtilities.test.d.ts +6 -0
  376. package/dist/src/ui/utils/markdownUtilities.test.js +42 -0
  377. package/dist/src/ui/utils/markdownUtilities.test.js.map +1 -0
  378. package/dist/src/ui/utils/platformConstants.d.ts +5 -0
  379. package/dist/src/ui/utils/platformConstants.js +5 -0
  380. package/dist/src/ui/utils/platformConstants.js.map +1 -1
  381. package/dist/src/ui/utils/responsive.test.d.ts +6 -0
  382. package/dist/src/ui/utils/responsive.test.js +107 -0
  383. package/dist/src/ui/utils/responsive.test.js.map +1 -0
  384. package/dist/src/ui/utils/secureInputHandler.test.d.ts +6 -0
  385. package/dist/src/ui/utils/secureInputHandler.test.js +274 -0
  386. package/dist/src/ui/utils/secureInputHandler.test.js.map +1 -0
  387. package/dist/src/ui/utils/updateCheck.test.d.ts +6 -0
  388. package/dist/src/ui/utils/updateCheck.test.js +202 -0
  389. package/dist/src/ui/utils/updateCheck.test.js.map +1 -0
  390. package/dist/src/utils/ConversationContext.test.d.ts +6 -0
  391. package/dist/src/utils/ConversationContext.test.js +64 -0
  392. package/dist/src/utils/ConversationContext.test.js.map +1 -0
  393. package/dist/src/utils/gitUtils.test.d.ts +6 -0
  394. package/dist/src/utils/gitUtils.test.js +113 -0
  395. package/dist/src/utils/gitUtils.test.js.map +1 -0
  396. package/dist/src/utils/installationInfo.test.d.ts +6 -0
  397. package/dist/src/utils/installationInfo.test.js +242 -0
  398. package/dist/src/utils/installationInfo.test.js.map +1 -0
  399. package/dist/src/utils/privacy/ConversationDataRedactor.test.d.ts +6 -0
  400. package/dist/src/utils/privacy/ConversationDataRedactor.test.js +463 -0
  401. package/dist/src/utils/privacy/ConversationDataRedactor.test.js.map +1 -0
  402. package/dist/src/utils/readStdin.js +10 -0
  403. package/dist/src/utils/readStdin.js.map +1 -1
  404. package/dist/src/utils/sandbox.js +2 -2
  405. package/dist/src/utils/sandbox.js.map +1 -1
  406. package/dist/src/utils/settingsUtils.test.d.ts +6 -0
  407. package/dist/src/utils/settingsUtils.test.js +514 -0
  408. package/dist/src/utils/settingsUtils.test.js.map +1 -0
  409. package/dist/src/utils/userStartupWarnings.js +2 -2
  410. package/dist/src/utils/userStartupWarnings.test.d.ts +6 -0
  411. package/dist/src/utils/userStartupWarnings.test.js +67 -0
  412. package/dist/src/utils/userStartupWarnings.test.js.map +1 -0
  413. package/dist/tsconfig.tsbuildinfo +1 -1
  414. package/package.json +3 -3
@@ -0,0 +1,800 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ /**
8
+ * INTEGRATION TESTS FOR TODO CONTINUATION FUNCTIONALITY
9
+ *
10
+ * These tests are designed to verify the behavioral integration between
11
+ * useGeminiStream and the todo continuation system. They serve as both:
12
+ * 1. Specification of expected behavior per requirements REQ-001 through REQ-004
13
+ * 2. Functional tests that will pass once the integration is implemented
14
+ *
15
+ * CURRENT STATUS: These tests expect functionality that is not yet fully implemented.
16
+ * The useGeminiStream hook currently has a NotYetImplemented stub for todo continuation.
17
+ *
18
+ * IMPLEMENTATION NOTES:
19
+ * - The todo continuation logic exists in useTodoContinuation.ts
20
+ * - The integration point in useGeminiStream.ts is stubbed out
21
+ * - The GeminiClient.sendMessageStream API needs ephemeral message support
22
+ *
23
+ * These tests will be useful when:
24
+ * 1. The NotYetImplemented stub is removed from useGeminiStream
25
+ * 2. The GeminiClient API is extended to support ephemeral messages
26
+ * 3. The _handleStreamCompleted call is activated in useGeminiStream
27
+ */
28
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
29
+ import { renderHook, act, waitFor } from '@testing-library/react';
30
+ import React from 'react';
31
+ import { useGeminiStream } from './useGeminiStream.js';
32
+ import { useReactToolScheduler, } from './useReactToolScheduler.js';
33
+ import { AuthType, GeminiEventType as ServerGeminiEventType, ApprovalMode, } from '@vybestack/llxprt-code-core';
34
+ import { StreamingState, } from '../types.js';
35
+ import { TodoContext } from '../contexts/TodoContext.js';
36
+ // --- MOCKS ---
37
+ const mockSendMessageStream = vi
38
+ .fn()
39
+ .mockReturnValue((async function* () { })());
40
+ const mockStartChat = vi.fn();
41
+ const MockedGeminiClientClass = vi.hoisted(() => vi.fn().mockImplementation(function (_config) {
42
+ this.startChat = mockStartChat;
43
+ this.sendMessageStream = mockSendMessageStream;
44
+ this.addHistory = vi.fn();
45
+ this.isInitialized = vi.fn().mockReturnValue(true);
46
+ }));
47
+ const MockedUserPromptEvent = vi.hoisted(() => vi.fn().mockImplementation(() => { }));
48
+ vi.mock('@vybestack/llxprt-code-core', async (importOriginal) => {
49
+ const actualCoreModule = (await importOriginal());
50
+ return {
51
+ ...actualCoreModule,
52
+ GitService: vi.fn(),
53
+ GeminiClient: MockedGeminiClientClass,
54
+ UserPromptEvent: MockedUserPromptEvent,
55
+ parseAndFormatApiError: mockParseAndFormatApiError,
56
+ };
57
+ });
58
+ const mockUseReactToolScheduler = useReactToolScheduler;
59
+ vi.mock('./useReactToolScheduler.js', async (importOriginal) => {
60
+ const actualSchedulerModule = (await importOriginal());
61
+ return {
62
+ ...(actualSchedulerModule || {}),
63
+ useReactToolScheduler: vi.fn(),
64
+ };
65
+ });
66
+ vi.mock('ink', async (importOriginal) => {
67
+ const actualInkModule = (await importOriginal());
68
+ return { ...(actualInkModule || {}), useInput: vi.fn() };
69
+ });
70
+ vi.mock('./shellCommandProcessor.js', () => ({
71
+ useShellCommandProcessor: vi.fn().mockReturnValue({
72
+ handleShellCommand: vi.fn(),
73
+ }),
74
+ }));
75
+ vi.mock('./atCommandProcessor.js', () => ({
76
+ handleAtCommand: vi
77
+ .fn()
78
+ .mockResolvedValue({ shouldProceed: true, processedQuery: 'mocked' }),
79
+ }));
80
+ vi.mock('../utils/markdownUtilities.js', () => ({
81
+ findLastSafeSplitPoint: vi.fn((s) => s.length),
82
+ }));
83
+ vi.mock('./useStateAndRef.js', () => ({
84
+ useStateAndRef: vi.fn((initial) => {
85
+ let val = initial;
86
+ const ref = { current: val };
87
+ const setVal = vi.fn((updater) => {
88
+ if (typeof updater === 'function') {
89
+ val = updater(val);
90
+ }
91
+ else {
92
+ val = updater;
93
+ }
94
+ ref.current = val;
95
+ });
96
+ return [ref, setVal];
97
+ }),
98
+ }));
99
+ vi.mock('./useLogger.js', () => ({
100
+ useLogger: vi.fn().mockReturnValue({
101
+ logMessage: vi.fn().mockResolvedValue(undefined),
102
+ }),
103
+ }));
104
+ const mockStartNewPrompt = vi.fn();
105
+ const mockAddUsage = vi.fn();
106
+ vi.mock('../contexts/SessionContext.js', () => ({
107
+ useSessionStats: vi.fn(() => ({
108
+ startNewPrompt: mockStartNewPrompt,
109
+ addUsage: mockAddUsage,
110
+ getPromptCount: vi.fn(() => 5),
111
+ })),
112
+ }));
113
+ vi.mock('./slashCommandProcessor.js', () => ({
114
+ handleSlashCommand: vi.fn().mockReturnValue(false),
115
+ }));
116
+ const mockParseAndFormatApiError = vi.hoisted(() => vi.fn());
117
+ // --- END MOCKS ---
118
+ describe('Todo Continuation Integration - useGeminiStream', () => {
119
+ /**
120
+ * @requirement CURRENT_STATE
121
+ * @scenario Integration not yet implemented
122
+ * @given Current codebase state
123
+ * @when Stream completes
124
+ * @then Integration is stubbed out with NotYetImplemented
125
+ * @note This test verifies the current state and should be updated when implementation is complete
126
+ */
127
+ it('should currently have todo continuation integration stubbed out', async () => {
128
+ // This test verifies the current implementation state
129
+ // It should be updated/removed when the actual integration is implemented
130
+ const activeTodos = createActiveTodos();
131
+ mockSendMessageStream.mockReturnValue((async function* () {
132
+ yield {
133
+ type: ServerGeminiEventType.Content,
134
+ value: 'Response without tool calls',
135
+ };
136
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
137
+ })());
138
+ const { result } = renderTestHook([], activeTodos);
139
+ await act(async () => {
140
+ result.current.submitQuery('What should I work on?');
141
+ });
142
+ await waitFor(() => {
143
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
144
+ });
145
+ // Currently, no continuation prompt should be sent because the integration is stubbed
146
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
147
+ expect(mockSendMessageStream).toHaveBeenCalledWith('What should I work on?', expect.any(AbortSignal), expect.any(String));
148
+ });
149
+ let mockAddItem;
150
+ let mockSetShowHelp;
151
+ let mockConfig;
152
+ let mockOnDebugMessage;
153
+ let mockHandleSlashCommand;
154
+ let mockScheduleToolCalls;
155
+ let mockMarkToolsAsSubmitted;
156
+ let mockTodoContext;
157
+ beforeEach(() => {
158
+ vi.clearAllMocks();
159
+ mockAddItem = vi.fn();
160
+ mockSetShowHelp = vi.fn();
161
+ mockOnDebugMessage = vi.fn();
162
+ mockHandleSlashCommand = vi.fn().mockResolvedValue(false);
163
+ // Create mock todo context
164
+ mockTodoContext = {
165
+ todos: [],
166
+ updateTodos: vi.fn(),
167
+ refreshTodos: vi.fn(),
168
+ };
169
+ // Create mock config with ephemeral settings support
170
+ const mockGetEphemeralSettings = vi.fn(() => ({
171
+ 'todo-continuation': true,
172
+ }));
173
+ const mockGetGeminiClient = vi.fn().mockImplementation(() => {
174
+ const clientInstance = new MockedGeminiClientClass(mockConfig);
175
+ return clientInstance;
176
+ });
177
+ const contentGeneratorConfig = {
178
+ model: 'test-model',
179
+ apiKey: 'test-key',
180
+ vertexai: false,
181
+ authType: AuthType.USE_GEMINI,
182
+ };
183
+ mockConfig = {
184
+ apiKey: 'test-api-key',
185
+ model: 'gemini-pro',
186
+ sandbox: false,
187
+ targetDir: '/test/dir',
188
+ debugMode: false,
189
+ question: undefined,
190
+ fullContext: false,
191
+ coreTools: [],
192
+ toolDiscoveryCommand: undefined,
193
+ toolCallCommand: undefined,
194
+ mcpServerCommand: undefined,
195
+ mcpServers: undefined,
196
+ userAgent: 'test-agent',
197
+ userMemory: '',
198
+ llxprtMdFileCount: 0,
199
+ alwaysSkipModificationConfirmation: false,
200
+ vertexai: false,
201
+ showMemoryUsage: false,
202
+ contextFileName: undefined,
203
+ getToolRegistry: vi.fn(() => Promise.resolve({ getFunctionDeclarations: vi.fn(() => []) })),
204
+ getProjectRoot: vi.fn(() => '/test/dir'),
205
+ getCheckpointingEnabled: vi.fn(() => false),
206
+ getGeminiClient: mockGetGeminiClient,
207
+ getUsageStatisticsEnabled: () => true,
208
+ getDebugMode: () => false,
209
+ addHistory: vi.fn(),
210
+ getSessionId() {
211
+ return 'test-session-id';
212
+ },
213
+ setQuotaErrorOccurred: vi.fn(),
214
+ getQuotaErrorOccurred: vi.fn(() => false),
215
+ getModel: vi.fn(() => 'gemini-2.5-pro'),
216
+ getContentGeneratorConfig: vi
217
+ .fn()
218
+ .mockReturnValue(contentGeneratorConfig),
219
+ getEphemeralSettings: mockGetEphemeralSettings,
220
+ getApprovalMode: vi.fn(() => ApprovalMode.DEFAULT),
221
+ };
222
+ // Mock return value for useReactToolScheduler
223
+ mockScheduleToolCalls = vi.fn();
224
+ mockMarkToolsAsSubmitted = vi.fn();
225
+ mockUseReactToolScheduler.mockReturnValue([
226
+ [], // Default to empty array for toolCalls
227
+ mockScheduleToolCalls,
228
+ mockMarkToolsAsSubmitted,
229
+ ]);
230
+ // Reset mocks for GeminiClient instance methods
231
+ mockStartChat.mockClear().mockResolvedValue({
232
+ sendMessageStream: mockSendMessageStream,
233
+ });
234
+ mockSendMessageStream
235
+ .mockClear()
236
+ .mockReturnValue((async function* () { })());
237
+ });
238
+ const mockLoadedSettings = {
239
+ merged: { preferredEditor: 'vscode' },
240
+ user: { path: '/user/settings.json', settings: {} },
241
+ workspace: { path: '/workspace/.llxprt/settings.json', settings: {} },
242
+ errors: [],
243
+ forScope: vi.fn(),
244
+ setValue: vi.fn(),
245
+ };
246
+ const createActiveTodos = () => [
247
+ {
248
+ id: 'todo-1',
249
+ content: 'Implement user auth',
250
+ status: 'in_progress',
251
+ priority: 'high',
252
+ },
253
+ {
254
+ id: 'todo-2',
255
+ content: 'Add validation',
256
+ status: 'pending',
257
+ priority: 'medium',
258
+ },
259
+ ];
260
+ const TodoContextProvider = ({ children, todos = [], }) => {
261
+ const contextValue = {
262
+ ...mockTodoContext,
263
+ todos,
264
+ };
265
+ return React.createElement(TodoContext.Provider, { value: contextValue }, children);
266
+ };
267
+ const renderTestHook = (initialToolCalls = [], todos = [], ephemeralSettings = { 'todo-continuation': true }) => {
268
+ // Update mock config with provided ephemeral settings
269
+ mockConfig.getEphemeralSettings.mockReturnValue(ephemeralSettings);
270
+ let currentToolCalls = initialToolCalls;
271
+ const setToolCalls = (newToolCalls) => {
272
+ currentToolCalls = newToolCalls;
273
+ };
274
+ mockUseReactToolScheduler.mockImplementation(() => [
275
+ currentToolCalls,
276
+ mockScheduleToolCalls,
277
+ mockMarkToolsAsSubmitted,
278
+ ]);
279
+ const client = mockConfig.getGeminiClient();
280
+ const { result, rerender } = renderHook((props) => {
281
+ if (props.toolCalls) {
282
+ setToolCalls(props.toolCalls);
283
+ }
284
+ return useGeminiStream(props.client, props.history, props.addItem, props.setShowHelp, props.config, props.onDebugMessage, props.handleSlashCommand, props.shellModeActive, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { });
285
+ }, {
286
+ initialProps: {
287
+ client,
288
+ history: [],
289
+ addItem: mockAddItem,
290
+ setShowHelp: mockSetShowHelp,
291
+ config: mockConfig,
292
+ onDebugMessage: mockOnDebugMessage,
293
+ handleSlashCommand: mockHandleSlashCommand,
294
+ shellModeActive: false,
295
+ loadedSettings: mockLoadedSettings,
296
+ toolCalls: initialToolCalls,
297
+ },
298
+ wrapper: ({ children }) => TodoContextProvider({ children, todos }),
299
+ });
300
+ return {
301
+ result,
302
+ rerender,
303
+ mockMarkToolsAsSubmitted,
304
+ mockSendMessageStream,
305
+ client,
306
+ };
307
+ };
308
+ /**
309
+ * @requirement REQ-001.1, REQ-001.2, REQ-002.1
310
+ * @scenario Model completes with active todo and no tool calls
311
+ * @given Active todo 'Implement user auth', model completes streaming
312
+ * @when Stream completes without tool calls
313
+ * @then Continuation prompt sent with task description
314
+ * @and Prompt marked as ephemeral (not in history)
315
+ * @note SPECIFICATION TEST - will pass when integration is implemented
316
+ */
317
+ it.skip('should send continuation prompt when stream completes with active todo and no tool calls', async () => {
318
+ const activeTodos = createActiveTodos();
319
+ // Mock stream that completes without tool calls
320
+ mockSendMessageStream.mockReturnValue((async function* () {
321
+ yield {
322
+ type: ServerGeminiEventType.Content,
323
+ value: 'I see the todos but made no tool calls',
324
+ };
325
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
326
+ })());
327
+ const { result } = renderTestHook([], activeTodos);
328
+ // Submit a query that will complete without tool calls
329
+ await act(async () => {
330
+ result.current.submitQuery('What should I work on?');
331
+ });
332
+ // Wait for the stream to complete
333
+ await waitFor(() => {
334
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
335
+ });
336
+ // Verify continuation prompt was sent
337
+ await waitFor(() => {
338
+ expect(mockSendMessageStream).toHaveBeenCalledWith('Please continue working on the following task: "Implement user auth"', { ephemeral: true });
339
+ });
340
+ // Verify the call was made twice: original query + continuation
341
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
342
+ });
343
+ /**
344
+ * @requirement REQ-001.1
345
+ * @scenario Model completes with tool calls pending
346
+ * @given Active todo exists, model makes tool calls
347
+ * @when Stream completes with tool calls
348
+ * @then NO continuation prompt sent
349
+ * @note SPECIFICATION TEST - will pass when integration is implemented
350
+ */
351
+ it.skip('should NOT send continuation prompt when stream completes with tool calls made', async () => {
352
+ const activeTodos = createActiveTodos();
353
+ // Mock stream that includes tool calls
354
+ mockSendMessageStream.mockReturnValue((async function* () {
355
+ yield {
356
+ type: ServerGeminiEventType.Content,
357
+ value: 'Let me help with that task',
358
+ };
359
+ yield {
360
+ type: ServerGeminiEventType.ToolCallRequest,
361
+ value: [
362
+ {
363
+ callId: 'call-1',
364
+ name: 'ReadFile',
365
+ args: { filePath: '/src/auth.ts' },
366
+ },
367
+ ],
368
+ };
369
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
370
+ })());
371
+ const { result } = renderTestHook([], activeTodos);
372
+ await act(async () => {
373
+ result.current.submitQuery('Continue working on auth');
374
+ });
375
+ // Wait for the stream to complete
376
+ await waitFor(() => {
377
+ expect(result.current.streamingState).toBe(StreamingState.Responding);
378
+ });
379
+ // Give additional time for any potential continuation prompt
380
+ await new Promise((resolve) => setTimeout(resolve, 100));
381
+ // Verify NO continuation prompt was sent (only original query)
382
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
383
+ expect(mockSendMessageStream).toHaveBeenCalledWith('Continue working on auth', expect.any(AbortSignal), expect.any(String));
384
+ });
385
+ /**
386
+ * @requirement REQ-001.4, REQ-004.1
387
+ * @scenario Continuation disabled via setting
388
+ * @given todo-continuation = false, active todo exists
389
+ * @when Stream completes without tool calls
390
+ * @then NO continuation prompt sent
391
+ */
392
+ it('should NOT send continuation prompt when todo-continuation is disabled', async () => {
393
+ const activeTodos = createActiveTodos();
394
+ // Mock stream that completes without tool calls
395
+ mockSendMessageStream.mockReturnValue((async function* () {
396
+ yield {
397
+ type: ServerGeminiEventType.Content,
398
+ value: 'Response without tool calls',
399
+ };
400
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
401
+ })());
402
+ // Render with continuation disabled
403
+ const { result } = renderTestHook([], activeTodos, {
404
+ 'todo-continuation': false,
405
+ });
406
+ await act(async () => {
407
+ result.current.submitQuery('What next?');
408
+ });
409
+ await waitFor(() => {
410
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
411
+ });
412
+ // Give time for any potential continuation attempt
413
+ await new Promise((resolve) => setTimeout(resolve, 100));
414
+ // Verify NO continuation prompt was sent
415
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
416
+ expect(mockSendMessageStream).toHaveBeenCalledWith('What next?', expect.any(AbortSignal), expect.any(String));
417
+ });
418
+ /**
419
+ * @requirement REQ-002.3
420
+ * @scenario YOLO mode uses stronger prompt
421
+ * @given YOLO mode active, todo exists
422
+ * @when Stream completes
423
+ * @then Prompt contains 'without waiting for confirmation'
424
+ * @note SPECIFICATION TEST - will pass when integration is implemented
425
+ */
426
+ it.skip('should use stronger continuation prompt in YOLO mode', async () => {
427
+ const activeTodos = createActiveTodos();
428
+ // Set YOLO mode
429
+ mockConfig.getApprovalMode.mockReturnValue(ApprovalMode.YOLO);
430
+ mockSendMessageStream.mockReturnValue((async function* () {
431
+ yield {
432
+ type: ServerGeminiEventType.Content,
433
+ value: 'Task analysis complete',
434
+ };
435
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
436
+ })());
437
+ const { result } = renderTestHook([], activeTodos);
438
+ await act(async () => {
439
+ result.current.submitQuery('Analyze the task');
440
+ });
441
+ await waitFor(() => {
442
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
443
+ });
444
+ // Verify YOLO continuation prompt was sent
445
+ await waitFor(() => {
446
+ expect(mockSendMessageStream).toHaveBeenCalledWith('Continue to proceed with the active task without waiting for confirmation: "Implement user auth"', { ephemeral: true });
447
+ });
448
+ });
449
+ /**
450
+ * @requirement REQ-003.4
451
+ * @scenario todo_pause available to model
452
+ * @given Active continuation scenario
453
+ * @when Model lists available tools
454
+ * @then todo_pause tool is accessible
455
+ */
456
+ it('should make todo_pause tool available during continuation', async () => {
457
+ const activeTodos = createActiveTodos();
458
+ // Mock tool registry that includes todo_pause
459
+ const mockToolRegistry = {
460
+ getFunctionDeclarations: vi.fn(() => [
461
+ {
462
+ name: 'todo_pause',
463
+ description: 'Pause the current todo task',
464
+ parameters: {
465
+ type: 'object',
466
+ properties: {
467
+ reason: { type: 'string' },
468
+ },
469
+ required: ['reason'],
470
+ },
471
+ },
472
+ {
473
+ name: 'ReadFile',
474
+ description: 'Read a file',
475
+ parameters: { type: 'object', properties: {} },
476
+ },
477
+ ]),
478
+ };
479
+ mockConfig.getToolRegistry.mockReturnValue(Promise.resolve(mockToolRegistry));
480
+ mockSendMessageStream.mockReturnValue((async function* () {
481
+ yield {
482
+ type: ServerGeminiEventType.Content,
483
+ value: 'Looking at available tools',
484
+ };
485
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
486
+ })());
487
+ const { result } = renderTestHook([], activeTodos);
488
+ await act(async () => {
489
+ result.current.submitQuery('What tools are available?');
490
+ });
491
+ // Verify tool registry includes todo_pause
492
+ const toolRegistry = await mockConfig.getToolRegistry();
493
+ const toolSchemas = toolRegistry.getFunctionDeclarations();
494
+ const todoPauseTool = toolSchemas.find((tool) => tool.name === 'todo_pause');
495
+ expect(todoPauseTool).toBeDefined();
496
+ expect(todoPauseTool.description).toContain('Pause');
497
+ });
498
+ /**
499
+ * @requirement REQ-001.2
500
+ * @scenario Only pending/in_progress todos trigger continuation
501
+ * @given Mix of todo statuses
502
+ * @when Stream completes without tool calls
503
+ * @then Only active todos considered for continuation
504
+ */
505
+ it.skip('should only consider pending and in_progress todos for continuation', async () => {
506
+ const mixedStatusTodos = [
507
+ {
508
+ id: 'todo-1',
509
+ content: 'Completed task',
510
+ status: 'completed',
511
+ priority: 'high',
512
+ },
513
+ {
514
+ id: 'todo-2',
515
+ content: 'Active pending task',
516
+ status: 'pending',
517
+ priority: 'medium',
518
+ },
519
+ ];
520
+ mockSendMessageStream.mockReturnValue((async function* () {
521
+ yield {
522
+ type: ServerGeminiEventType.Content,
523
+ value: 'Response without tool calls',
524
+ };
525
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
526
+ })());
527
+ const { result } = renderTestHook([], mixedStatusTodos);
528
+ await act(async () => {
529
+ result.current.submitQuery('Show me todos');
530
+ });
531
+ await waitFor(() => {
532
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
533
+ });
534
+ // Verify continuation prompt uses the pending task, not the completed one
535
+ await waitFor(() => {
536
+ expect(mockSendMessageStream).toHaveBeenCalledWith('Please continue working on the following task: "Active pending task"', { ephemeral: true });
537
+ });
538
+ });
539
+ /**
540
+ * @requirement REQ-001.3
541
+ * @scenario Prioritize in_progress over pending todos
542
+ * @given Both pending and in_progress todos exist
543
+ * @when Stream completes
544
+ * @then in_progress todo is selected for continuation
545
+ */
546
+ it.skip('should prioritize in_progress todos over pending for continuation', async () => {
547
+ const prioritizedTodos = [
548
+ {
549
+ id: 'todo-1',
550
+ content: 'Pending task',
551
+ status: 'pending',
552
+ priority: 'high',
553
+ },
554
+ {
555
+ id: 'todo-2',
556
+ content: 'In progress task',
557
+ status: 'in_progress',
558
+ priority: 'low', // Lower priority but in_progress should win
559
+ },
560
+ ];
561
+ mockSendMessageStream.mockReturnValue((async function* () {
562
+ yield {
563
+ type: ServerGeminiEventType.Content,
564
+ value: 'Task status check',
565
+ };
566
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
567
+ })());
568
+ const { result } = renderTestHook([], prioritizedTodos);
569
+ await act(async () => {
570
+ result.current.submitQuery('Check task status');
571
+ });
572
+ await waitFor(() => {
573
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
574
+ });
575
+ // Verify in_progress task is selected despite lower priority
576
+ await waitFor(() => {
577
+ expect(mockSendMessageStream).toHaveBeenCalledWith('Please continue working on the following task: "In progress task"', { ephemeral: true });
578
+ });
579
+ });
580
+ /**
581
+ * @requirement REQ-001.5
582
+ * @scenario No continuation when no active todos
583
+ * @given No pending or in_progress todos
584
+ * @when Stream completes without tool calls
585
+ * @then NO continuation prompt sent
586
+ */
587
+ it('should NOT send continuation prompt when no active todos exist', async () => {
588
+ const completedTodos = [
589
+ {
590
+ id: 'todo-1',
591
+ content: 'Done task',
592
+ status: 'completed',
593
+ priority: 'high',
594
+ },
595
+ ];
596
+ mockSendMessageStream.mockReturnValue((async function* () {
597
+ yield {
598
+ type: ServerGeminiEventType.Content,
599
+ value: 'All tasks complete',
600
+ };
601
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
602
+ })());
603
+ const { result } = renderTestHook([], completedTodos);
604
+ await act(async () => {
605
+ result.current.submitQuery('How are we doing?');
606
+ });
607
+ await waitFor(() => {
608
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
609
+ });
610
+ // Give time for any potential continuation attempt
611
+ await new Promise((resolve) => setTimeout(resolve, 100));
612
+ // Verify NO continuation prompt was sent
613
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
614
+ });
615
+ /**
616
+ * @requirement REQ-002.1
617
+ * @scenario Continuation prompt is ephemeral
618
+ * @given Active todo and stream completion
619
+ * @when Continuation prompt is sent
620
+ * @then Prompt is marked with ephemeral flag
621
+ */
622
+ it.skip('should mark continuation prompts as ephemeral (not stored in history)', async () => {
623
+ const activeTodos = createActiveTodos();
624
+ mockSendMessageStream.mockReturnValue((async function* () {
625
+ yield {
626
+ type: ServerGeminiEventType.Content,
627
+ value: 'Regular response',
628
+ };
629
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
630
+ })());
631
+ const { result, client } = renderTestHook([], activeTodos);
632
+ await act(async () => {
633
+ result.current.submitQuery('Continue task');
634
+ });
635
+ await waitFor(() => {
636
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
637
+ });
638
+ // Verify ephemeral flag is set correctly
639
+ await waitFor(() => {
640
+ expect(mockSendMessageStream).toHaveBeenCalledWith(expect.stringContaining('Please continue working on the following task:'), { ephemeral: true });
641
+ });
642
+ // Verify the continuation prompt is NOT added to client history
643
+ // (Only the original user query should be in history)
644
+ expect(client.addHistory).toHaveBeenCalledTimes(1);
645
+ });
646
+ /**
647
+ * @requirement REQ-001.6
648
+ * @scenario Prevent rapid fire continuations
649
+ * @given Active todo and continuation in progress
650
+ * @when Multiple streams complete quickly
651
+ * @then Only one continuation prompt sent
652
+ */
653
+ it.skip('should prevent multiple rapid continuation prompts', async () => {
654
+ const activeTodos = createActiveTodos();
655
+ // Mock multiple quick completions
656
+ let completionCount = 0;
657
+ mockSendMessageStream.mockImplementation(() => {
658
+ completionCount++;
659
+ return (async function* () {
660
+ yield {
661
+ type: ServerGeminiEventType.Content,
662
+ value: `Quick response ${completionCount}`,
663
+ };
664
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
665
+ })();
666
+ });
667
+ const { result } = renderTestHook([], activeTodos);
668
+ // Rapidly submit multiple queries
669
+ await act(async () => {
670
+ result.current.submitQuery('Query 1');
671
+ });
672
+ await act(async () => {
673
+ result.current.submitQuery('Query 2');
674
+ });
675
+ await waitFor(() => {
676
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
677
+ });
678
+ // Allow time for any potential extra continuation attempts
679
+ await new Promise((resolve) => setTimeout(resolve, 200));
680
+ // Verify continuation was attempted only once despite multiple completions
681
+ const continuationCalls = mockSendMessageStream.mock.calls.filter((call) => call[0]?.includes('Please continue working on the following task:'));
682
+ expect(continuationCalls.length).toBeLessThanOrEqual(1);
683
+ });
684
+ /**
685
+ * ACTIVE TESTS - These test the current implementation state and architecture
686
+ */
687
+ /**
688
+ * @requirement INTEGRATION_ARCHITECTURE
689
+ * @scenario Todo continuation hook is properly integrated
690
+ * @given useGeminiStream hook is rendered
691
+ * @when Hook is initialized
692
+ * @then useTodoContinuation hook is called with proper parameters
693
+ */
694
+ it('should properly integrate useTodoContinuation hook', () => {
695
+ const activeTodos = createActiveTodos();
696
+ const { result } = renderTestHook([], activeTodos);
697
+ // Verify the hook renders successfully with todo context integration
698
+ expect(result.current).toBeDefined();
699
+ expect(result.current.submitQuery).toBeDefined();
700
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
701
+ // Verify the mock config was set up correctly
702
+ expect(mockConfig.getEphemeralSettings).toBeDefined();
703
+ });
704
+ /**
705
+ * @requirement REQ-004.1
706
+ * @scenario Configuration setting is properly read
707
+ * @given Various todo-continuation settings
708
+ * @when Hook is initialized
709
+ * @then getEphemeralSettings is called to check todo-continuation setting
710
+ */
711
+ it('should read todo-continuation configuration setting', () => {
712
+ const settingsVariations = [
713
+ { 'todo-continuation': true },
714
+ { 'todo-continuation': false },
715
+ { 'other-setting': 'value' }, // no todo-continuation setting
716
+ {}, // empty settings
717
+ ];
718
+ settingsVariations.forEach((settings) => {
719
+ // Reset mocks for each test iteration
720
+ vi.clearAllMocks();
721
+ mockConfig.getEphemeralSettings.mockReturnValue(settings);
722
+ const { result } = renderTestHook([], [], settings);
723
+ // Verify hook integration works with all setting variations
724
+ expect(result.current).toBeDefined();
725
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
726
+ // Verify the configuration mock is properly set up
727
+ expect(mockConfig.getEphemeralSettings()).toEqual(settings);
728
+ });
729
+ });
730
+ /**
731
+ * @requirement REQ-003.4
732
+ * @scenario todo_pause tool availability
733
+ * @given Tool registry configuration
734
+ * @when Tools are requested
735
+ * @then todo_pause tool is available in the registry
736
+ */
737
+ it('should have todo_pause tool available in tool registry', async () => {
738
+ // Set up tool registry with todo_pause tool
739
+ const mockToolRegistry = {
740
+ getFunctionDeclarations: vi.fn(() => [
741
+ {
742
+ name: 'todo_pause',
743
+ description: 'Pause the current todo task',
744
+ parameters: {
745
+ type: 'object',
746
+ properties: {
747
+ reason: { type: 'string', description: 'Reason for pausing' },
748
+ },
749
+ required: ['reason'],
750
+ },
751
+ },
752
+ {
753
+ name: 'ReadFile',
754
+ description: 'Read a file',
755
+ parameters: { type: 'object', properties: {} },
756
+ },
757
+ ]),
758
+ };
759
+ mockConfig.getToolRegistry.mockReturnValue(Promise.resolve(mockToolRegistry));
760
+ const activeTodos = createActiveTodos();
761
+ renderTestHook([], activeTodos);
762
+ // Verify tool registry includes todo_pause
763
+ const toolRegistry = await mockConfig.getToolRegistry();
764
+ const toolSchemas = toolRegistry.getFunctionDeclarations();
765
+ const todoPauseTool = toolSchemas.find((tool) => tool.name === 'todo_pause');
766
+ expect(todoPauseTool).toBeDefined();
767
+ expect(todoPauseTool.description).toContain('Pause');
768
+ expect(todoPauseTool.parameters.properties.reason).toBeDefined();
769
+ expect(todoPauseTool.parameters.required).toContain('reason');
770
+ });
771
+ /**
772
+ * @requirement CURRENT_STATE
773
+ * @scenario Hook integration exists but is not activated
774
+ * @given Current implementation with NotYetImplemented stub
775
+ * @when Stream processing completes
776
+ * @then Hook integration code path exists but doesn't execute continuation logic
777
+ */
778
+ it('should have hook integration architecture in place but not activated', async () => {
779
+ const activeTodos = createActiveTodos();
780
+ mockSendMessageStream.mockReturnValue((async function* () {
781
+ yield {
782
+ type: ServerGeminiEventType.Content,
783
+ value: 'Test response',
784
+ };
785
+ yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
786
+ })());
787
+ const { result } = renderTestHook([], activeTodos);
788
+ await act(async () => {
789
+ result.current.submitQuery('Test query');
790
+ });
791
+ await waitFor(() => {
792
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
793
+ });
794
+ // The architectural integration should be there (hook is called)
795
+ // but the actual continuation logic should not execute due to NotYetImplemented stub
796
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
797
+ expect(mockSendMessageStream).not.toHaveBeenCalledWith(expect.stringContaining('Please continue working'), expect.anything());
798
+ });
799
+ });
800
+ //# sourceMappingURL=useGeminiStream.integration.test.js.map