@umsai/ums-code 0.1.4-v2 → 0.3.0-v2

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 (382) hide show
  1. package/dist/package.json +11 -3
  2. package/dist/src/config/config.d.ts +6 -0
  3. package/dist/src/config/config.js +102 -11
  4. package/dist/src/config/config.js.map +1 -1
  5. package/dist/src/config/settings.d.ts +5 -0
  6. package/dist/src/config/settings.js +15 -1
  7. package/dist/src/config/settings.js.map +1 -1
  8. package/dist/src/config/settingsSchema.d.ts +75 -17
  9. package/dist/src/config/settingsSchema.js +57 -17
  10. package/dist/src/config/settingsSchema.js.map +1 -1
  11. package/dist/src/config/webSearch.d.ts +35 -0
  12. package/dist/src/config/webSearch.js +87 -0
  13. package/dist/src/config/webSearch.js.map +1 -0
  14. package/dist/src/core/auth.d.ts +1 -1
  15. package/dist/src/core/auth.js +19 -3
  16. package/dist/src/core/auth.js.map +1 -1
  17. package/dist/src/core/initializer.js +13 -2
  18. package/dist/src/core/initializer.js.map +1 -1
  19. package/dist/src/core/theme.js +4 -1
  20. package/dist/src/core/theme.js.map +1 -1
  21. package/dist/src/gemini.d.ts +1 -1
  22. package/dist/src/gemini.js +53 -44
  23. package/dist/src/gemini.js.map +1 -1
  24. package/dist/src/gemini.test.js +117 -0
  25. package/dist/src/gemini.test.js.map +1 -1
  26. package/dist/src/generated/git-commit.d.ts +2 -2
  27. package/dist/src/generated/git-commit.js +2 -2
  28. package/dist/src/i18n/index.d.ts +18 -0
  29. package/dist/src/i18n/index.js +184 -0
  30. package/dist/src/i18n/index.js.map +1 -0
  31. package/dist/src/i18n/locales/en.js +1129 -0
  32. package/dist/src/i18n/locales/zh.js +1052 -0
  33. package/dist/src/nonInteractive/control/ControlContext.d.ts +63 -0
  34. package/dist/src/nonInteractive/control/ControlContext.js +31 -0
  35. package/dist/src/nonInteractive/control/ControlContext.js.map +1 -0
  36. package/dist/src/nonInteractive/control/ControlDispatcher.d.ts +86 -0
  37. package/dist/src/nonInteractive/control/ControlDispatcher.js +238 -0
  38. package/dist/src/nonInteractive/control/ControlDispatcher.js.map +1 -0
  39. package/dist/src/nonInteractive/control/ControlDispatcher.test.d.ts +6 -0
  40. package/dist/src/nonInteractive/control/ControlDispatcher.test.js +549 -0
  41. package/dist/src/nonInteractive/control/ControlDispatcher.test.js.map +1 -0
  42. package/dist/src/nonInteractive/control/ControlService.d.ts +78 -0
  43. package/dist/src/nonInteractive/control/ControlService.js +154 -0
  44. package/dist/src/nonInteractive/control/ControlService.js.map +1 -0
  45. package/dist/src/nonInteractive/control/controllers/baseController.d.ts +50 -0
  46. package/dist/src/nonInteractive/control/controllers/baseController.js +102 -0
  47. package/dist/src/nonInteractive/control/controllers/baseController.js.map +1 -0
  48. package/dist/src/nonInteractive/control/controllers/hookController.d.ts +25 -0
  49. package/dist/src/nonInteractive/control/controllers/hookController.js +42 -0
  50. package/dist/src/nonInteractive/control/controllers/hookController.js.map +1 -0
  51. package/dist/src/nonInteractive/control/controllers/mcpController.d.ts +42 -0
  52. package/dist/src/nonInteractive/control/controllers/mcpController.js +205 -0
  53. package/dist/src/nonInteractive/control/controllers/mcpController.js.map +1 -0
  54. package/dist/src/nonInteractive/control/controllers/permissionController.d.ts +78 -0
  55. package/dist/src/nonInteractive/control/controllers/permissionController.js +358 -0
  56. package/dist/src/nonInteractive/control/controllers/permissionController.js.map +1 -0
  57. package/dist/src/nonInteractive/control/controllers/systemController.d.ts +56 -0
  58. package/dist/src/nonInteractive/control/controllers/systemController.js +166 -0
  59. package/dist/src/nonInteractive/control/controllers/systemController.js.map +1 -0
  60. package/dist/src/nonInteractive/control/types/serviceAPIs.d.ts +120 -0
  61. package/dist/src/nonInteractive/control/types/serviceAPIs.js +7 -0
  62. package/dist/src/nonInteractive/control/types/serviceAPIs.js.map +1 -0
  63. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.d.ts +446 -0
  64. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.js +891 -0
  65. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.js.map +1 -0
  66. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.d.ts +6 -0
  67. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.js +1197 -0
  68. package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.js.map +1 -0
  69. package/dist/src/nonInteractive/io/JsonOutputAdapter.d.ts +29 -0
  70. package/dist/src/nonInteractive/io/JsonOutputAdapter.js +56 -0
  71. package/dist/src/nonInteractive/io/JsonOutputAdapter.js.map +1 -0
  72. package/dist/src/nonInteractive/io/JsonOutputAdapter.test.d.ts +6 -0
  73. package/dist/src/nonInteractive/io/JsonOutputAdapter.test.js +624 -0
  74. package/dist/src/nonInteractive/io/JsonOutputAdapter.test.js.map +1 -0
  75. package/dist/src/nonInteractive/io/StreamJsonInputReader.d.ts +16 -0
  76. package/dist/src/nonInteractive/io/StreamJsonInputReader.js +54 -0
  77. package/dist/src/nonInteractive/io/StreamJsonInputReader.js.map +1 -0
  78. package/dist/src/nonInteractive/io/StreamJsonInputReader.test.d.ts +6 -0
  79. package/dist/src/nonInteractive/io/StreamJsonInputReader.test.js +178 -0
  80. package/dist/src/nonInteractive/io/StreamJsonInputReader.test.js.map +1 -0
  81. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.d.ts +69 -0
  82. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.js +185 -0
  83. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.js.map +1 -0
  84. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.d.ts +6 -0
  85. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.js +808 -0
  86. package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.js.map +1 -0
  87. package/dist/src/nonInteractive/session.d.ts +23 -0
  88. package/dist/src/nonInteractive/session.js +549 -0
  89. package/dist/src/nonInteractive/session.js.map +1 -0
  90. package/dist/src/nonInteractive/session.test.d.ts +6 -0
  91. package/dist/src/nonInteractive/session.test.js +407 -0
  92. package/dist/src/nonInteractive/session.test.js.map +1 -0
  93. package/dist/src/nonInteractive/types.d.ts +344 -0
  94. package/dist/src/nonInteractive/types.js +78 -0
  95. package/dist/src/nonInteractive/types.js.map +1 -0
  96. package/dist/src/nonInteractiveCli.d.ts +21 -1
  97. package/dist/src/nonInteractiveCli.js +204 -57
  98. package/dist/src/nonInteractiveCli.js.map +1 -1
  99. package/dist/src/nonInteractiveCliCommands.d.ts +19 -1
  100. package/dist/src/nonInteractiveCliCommands.js +69 -4
  101. package/dist/src/nonInteractiveCliCommands.js.map +1 -1
  102. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  103. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  104. package/dist/src/services/FileCommandLoader.js +4 -1
  105. package/dist/src/services/FileCommandLoader.js.map +1 -1
  106. package/dist/src/ui/AppContainer.js +41 -38
  107. package/dist/src/ui/AppContainer.js.map +1 -1
  108. package/dist/src/ui/auth/AuthDialog.d.ts +1 -13
  109. package/dist/src/ui/auth/AuthDialog.js +41 -111
  110. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  111. package/dist/src/ui/auth/AuthDialog.test.js +49 -19
  112. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  113. package/dist/src/ui/auth/AuthInProgress.js +2 -1
  114. package/dist/src/ui/auth/AuthInProgress.js.map +1 -1
  115. package/dist/src/ui/auth/useAuth.d.ts +9 -8
  116. package/dist/src/ui/auth/useAuth.js +135 -63
  117. package/dist/src/ui/auth/useAuth.js.map +1 -1
  118. package/dist/src/ui/commands/aboutCommand.js +7 -31
  119. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  120. package/dist/src/ui/commands/agentsCommand.js +10 -3
  121. package/dist/src/ui/commands/agentsCommand.js.map +1 -1
  122. package/dist/src/ui/commands/approvalModeCommand.js +8 -329
  123. package/dist/src/ui/commands/approvalModeCommand.js.map +1 -1
  124. package/dist/src/ui/commands/approvalModeCommand.test.js +19 -263
  125. package/dist/src/ui/commands/approvalModeCommand.test.js.map +1 -1
  126. package/dist/src/ui/commands/authCommand.js +4 -1
  127. package/dist/src/ui/commands/authCommand.js.map +1 -1
  128. package/dist/src/ui/commands/bugCommand.js +13 -47
  129. package/dist/src/ui/commands/bugCommand.js.map +1 -1
  130. package/dist/src/ui/commands/chatCommand.js +51 -25
  131. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  132. package/dist/src/ui/commands/clearCommand.js +6 -3
  133. package/dist/src/ui/commands/clearCommand.js.map +1 -1
  134. package/dist/src/ui/commands/compressCommand.js +9 -4
  135. package/dist/src/ui/commands/compressCommand.js.map +1 -1
  136. package/dist/src/ui/commands/copyCommand.js +4 -1
  137. package/dist/src/ui/commands/copyCommand.js.map +1 -1
  138. package/dist/src/ui/commands/directoryCommand.js +30 -12
  139. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  140. package/dist/src/ui/commands/docsCommand.js +9 -3
  141. package/dist/src/ui/commands/docsCommand.js.map +1 -1
  142. package/dist/src/ui/commands/editorCommand.js +4 -1
  143. package/dist/src/ui/commands/editorCommand.js.map +1 -1
  144. package/dist/src/ui/commands/extensionsCommand.js +10 -3
  145. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  146. package/dist/src/ui/commands/helpCommand.js +4 -1
  147. package/dist/src/ui/commands/helpCommand.js.map +1 -1
  148. package/dist/src/ui/commands/ideCommand.js +23 -7
  149. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  150. package/dist/src/ui/commands/initCommand.js +5 -3
  151. package/dist/src/ui/commands/initCommand.js.map +1 -1
  152. package/dist/src/ui/commands/languageCommand.d.ts +7 -0
  153. package/dist/src/ui/commands/languageCommand.js +386 -0
  154. package/dist/src/ui/commands/languageCommand.js.map +1 -0
  155. package/dist/src/ui/commands/mcpCommand.js +38 -18
  156. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  157. package/dist/src/ui/commands/memoryCommand.js +54 -25
  158. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  159. package/dist/src/ui/commands/modelCommand.js +9 -4
  160. package/dist/src/ui/commands/modelCommand.js.map +1 -1
  161. package/dist/src/ui/commands/permissionsCommand.js +4 -1
  162. package/dist/src/ui/commands/permissionsCommand.js.map +1 -1
  163. package/dist/src/ui/commands/quitCommand.js +7 -2
  164. package/dist/src/ui/commands/quitCommand.js.map +1 -1
  165. package/dist/src/ui/commands/settingsCommand.js +4 -1
  166. package/dist/src/ui/commands/settingsCommand.js.map +1 -1
  167. package/dist/src/ui/commands/setupGithubCommand.js +4 -1
  168. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  169. package/dist/src/ui/commands/statsCommand.js +11 -4
  170. package/dist/src/ui/commands/statsCommand.js.map +1 -1
  171. package/dist/src/ui/commands/summaryCommand.js +15 -8
  172. package/dist/src/ui/commands/summaryCommand.js.map +1 -1
  173. package/dist/src/ui/commands/terminalSetupCommand.js +9 -3
  174. package/dist/src/ui/commands/terminalSetupCommand.js.map +1 -1
  175. package/dist/src/ui/commands/themeCommand.js +4 -1
  176. package/dist/src/ui/commands/themeCommand.js.map +1 -1
  177. package/dist/src/ui/commands/toolsCommand.js +5 -2
  178. package/dist/src/ui/commands/toolsCommand.js.map +1 -1
  179. package/dist/src/ui/commands/types.d.ts +1 -1
  180. package/dist/src/ui/commands/types.js.map +1 -1
  181. package/dist/src/ui/commands/vimCommand.js +4 -1
  182. package/dist/src/ui/commands/vimCommand.js.map +1 -1
  183. package/dist/src/ui/components/AboutBox.d.ts +2 -9
  184. package/dist/src/ui/components/AboutBox.js +6 -2
  185. package/dist/src/ui/components/AboutBox.js.map +1 -1
  186. package/dist/src/ui/components/ApprovalModeDialog.d.ts +21 -0
  187. package/dist/src/ui/components/ApprovalModeDialog.js +68 -0
  188. package/dist/src/ui/components/ApprovalModeDialog.js.map +1 -0
  189. package/dist/src/ui/components/AutoAcceptIndicator.js +7 -6
  190. package/dist/src/ui/components/AutoAcceptIndicator.js.map +1 -1
  191. package/dist/src/ui/components/Composer.js +4 -3
  192. package/dist/src/ui/components/Composer.js.map +1 -1
  193. package/dist/src/ui/components/ConfigInitDisplay.js +7 -3
  194. package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
  195. package/dist/src/ui/components/ContextSummaryDisplay.js +33 -9
  196. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  197. package/dist/src/ui/components/DialogManager.js +60 -13
  198. package/dist/src/ui/components/DialogManager.js.map +1 -1
  199. package/dist/src/ui/components/EditorSettingsDialog.js +8 -3
  200. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  201. package/dist/src/ui/components/Help.js +14 -4
  202. package/dist/src/ui/components/Help.js.map +1 -1
  203. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  204. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  205. package/dist/src/ui/components/HistoryItemDisplay.test.js +17 -8
  206. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
  207. package/dist/src/ui/components/InputPrompt.js +10 -136
  208. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  209. package/dist/src/ui/components/LoadingIndicator.js +6 -1
  210. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  211. package/dist/src/ui/components/ModelDialog.js +2 -1
  212. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  213. package/dist/src/ui/components/ModelStatsDisplay.js +6 -5
  214. package/dist/src/ui/components/ModelStatsDisplay.js.map +1 -1
  215. package/dist/src/ui/components/OpenAIKeyPrompt.d.ts +19 -1
  216. package/dist/src/ui/components/OpenAIKeyPrompt.js +38 -6
  217. package/dist/src/ui/components/OpenAIKeyPrompt.js.map +1 -1
  218. package/dist/src/ui/components/ProQuotaDialog.js +5 -4
  219. package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
  220. package/dist/src/ui/components/QuitConfirmationDialog.js +6 -5
  221. package/dist/src/ui/components/QuitConfirmationDialog.js.map +1 -1
  222. package/dist/src/ui/components/QwenOAuthProgress.d.ts +2 -2
  223. package/dist/src/ui/components/QwenOAuthProgress.js +14 -7
  224. package/dist/src/ui/components/QwenOAuthProgress.js.map +1 -1
  225. package/dist/src/ui/components/QwenOAuthProgress.test.js +1 -0
  226. package/dist/src/ui/components/QwenOAuthProgress.test.js.map +1 -1
  227. package/dist/src/ui/components/SessionSummaryDisplay.js +2 -1
  228. package/dist/src/ui/components/SessionSummaryDisplay.js.map +1 -1
  229. package/dist/src/ui/components/SettingsDialog.d.ts +3 -1
  230. package/dist/src/ui/components/SettingsDialog.js +35 -12
  231. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  232. package/dist/src/ui/components/SettingsDialog.test.js +5 -4
  233. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  234. package/dist/src/ui/components/ShellConfirmationDialog.js +5 -4
  235. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  236. package/dist/src/ui/components/StatsDisplay.js +5 -4
  237. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  238. package/dist/src/ui/components/ThemeDialog.js +5 -2
  239. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  240. package/dist/src/ui/components/ToolStatsDisplay.js +3 -2
  241. package/dist/src/ui/components/ToolStatsDisplay.js.map +1 -1
  242. package/dist/src/ui/components/WelcomeBackDialog.js +13 -4
  243. package/dist/src/ui/components/WelcomeBackDialog.js.map +1 -1
  244. package/dist/src/ui/components/messages/CompressionMessage.js +10 -6
  245. package/dist/src/ui/components/messages/CompressionMessage.js.map +1 -1
  246. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +40 -29
  247. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  248. package/dist/src/ui/components/shared/BaseSelectionList.test.js +1 -1
  249. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  250. package/dist/src/ui/components/shared/ScopeSelector.js +3 -1
  251. package/dist/src/ui/components/shared/ScopeSelector.js.map +1 -1
  252. package/dist/src/ui/components/subagents/create/AgentCreationWizard.js +39 -26
  253. package/dist/src/ui/components/subagents/create/AgentCreationWizard.js.map +1 -1
  254. package/dist/src/ui/components/subagents/create/CreationSummary.js +20 -10
  255. package/dist/src/ui/components/subagents/create/CreationSummary.js.map +1 -1
  256. package/dist/src/ui/components/subagents/create/DescriptionInput.js +6 -3
  257. package/dist/src/ui/components/subagents/create/DescriptionInput.js.map +1 -1
  258. package/dist/src/ui/components/subagents/create/GenerationMethodSelector.js +7 -2
  259. package/dist/src/ui/components/subagents/create/GenerationMethodSelector.js.map +1 -1
  260. package/dist/src/ui/components/subagents/create/LocationSelector.js +7 -2
  261. package/dist/src/ui/components/subagents/create/LocationSelector.js.map +1 -1
  262. package/dist/src/ui/components/subagents/create/ToolSelector.js +8 -7
  263. package/dist/src/ui/components/subagents/create/ToolSelector.js.map +1 -1
  264. package/dist/src/ui/components/subagents/manage/ActionSelectionStep.js +29 -4
  265. package/dist/src/ui/components/subagents/manage/ActionSelectionStep.js.map +1 -1
  266. package/dist/src/ui/components/subagents/manage/AgentDeleteStep.js +6 -3
  267. package/dist/src/ui/components/subagents/manage/AgentDeleteStep.js.map +1 -1
  268. package/dist/src/ui/components/subagents/manage/AgentEditStep.js +14 -5
  269. package/dist/src/ui/components/subagents/manage/AgentEditStep.js.map +1 -1
  270. package/dist/src/ui/components/subagents/manage/AgentSelectionStep.js +13 -6
  271. package/dist/src/ui/components/subagents/manage/AgentSelectionStep.js.map +1 -1
  272. package/dist/src/ui/components/subagents/manage/AgentViewerStep.js +3 -2
  273. package/dist/src/ui/components/subagents/manage/AgentViewerStep.js.map +1 -1
  274. package/dist/src/ui/components/subagents/manage/AgentsManagerDialog.js +14 -13
  275. package/dist/src/ui/components/subagents/manage/AgentsManagerDialog.js.map +1 -1
  276. package/dist/src/ui/components/subagents/runtime/AgentExecutionDisplay.js +8 -8
  277. package/dist/src/ui/components/views/McpStatus.js +28 -15
  278. package/dist/src/ui/components/views/McpStatus.js.map +1 -1
  279. package/dist/src/ui/components/views/ToolsList.js +2 -1
  280. package/dist/src/ui/components/views/ToolsList.js.map +1 -1
  281. package/dist/src/ui/contexts/UIActionsContext.d.ts +5 -4
  282. package/dist/src/ui/contexts/UIActionsContext.js +1 -0
  283. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  284. package/dist/src/ui/contexts/UIStateContext.d.ts +5 -7
  285. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  286. package/dist/src/ui/editors/editorSettingsManager.js +1 -0
  287. package/dist/src/ui/editors/editorSettingsManager.js.map +1 -1
  288. package/dist/src/ui/hooks/atCommandProcessor.test.js +2 -0
  289. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  290. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -0
  291. package/dist/src/ui/hooks/slashCommandProcessor.js +4 -7
  292. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  293. package/dist/src/ui/hooks/useApprovalModeCommand.d.ts +14 -0
  294. package/dist/src/ui/hooks/useApprovalModeCommand.js +33 -0
  295. package/dist/src/ui/hooks/useApprovalModeCommand.js.map +1 -0
  296. package/dist/src/ui/hooks/useAttentionNotifications.d.ts +14 -0
  297. package/dist/src/ui/hooks/useAttentionNotifications.js +41 -0
  298. package/dist/src/ui/hooks/useAttentionNotifications.js.map +1 -0
  299. package/dist/src/ui/hooks/useAttentionNotifications.test.d.ts +6 -0
  300. package/dist/src/ui/hooks/useAttentionNotifications.test.js +113 -0
  301. package/dist/src/ui/hooks/useAttentionNotifications.test.js.map +1 -0
  302. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -4
  303. package/dist/src/ui/hooks/useCommandCompletion.js +1 -23
  304. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  305. package/dist/src/ui/hooks/useDialogClose.d.ts +6 -3
  306. package/dist/src/ui/hooks/useDialogClose.js +5 -0
  307. package/dist/src/ui/hooks/useDialogClose.js.map +1 -1
  308. package/dist/src/ui/hooks/useGitBranchName.js +6 -3
  309. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  310. package/dist/src/ui/hooks/useGitBranchName.test.js +39 -21
  311. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  312. package/dist/src/ui/hooks/useInitializationAuthError.d.ts +22 -0
  313. package/dist/src/ui/hooks/useInitializationAuthError.js +40 -0
  314. package/dist/src/ui/hooks/useInitializationAuthError.js.map +1 -0
  315. package/dist/src/ui/hooks/usePhraseCycler.js +6 -4
  316. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  317. package/dist/src/ui/hooks/useQwenAuth.d.ts +7 -12
  318. package/dist/src/ui/hooks/useQwenAuth.js +4 -8
  319. package/dist/src/ui/hooks/useQwenAuth.js.map +1 -1
  320. package/dist/src/ui/hooks/useQwenAuth.test.js +72 -98
  321. package/dist/src/ui/hooks/useQwenAuth.test.js.map +1 -1
  322. package/dist/src/ui/hooks/useThemeCommand.js +8 -3
  323. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  324. package/dist/src/ui/models/availableModels.js +7 -2
  325. package/dist/src/ui/models/availableModels.js.map +1 -1
  326. package/dist/src/ui/types.d.ts +32 -14
  327. package/dist/src/ui/types.js.map +1 -1
  328. package/dist/src/ui/utils/clipboardUtils.js +3 -3
  329. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  330. package/dist/src/ui/utils/commandUtils.d.ts +16 -0
  331. package/dist/src/ui/utils/commandUtils.js +16 -1
  332. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  333. package/dist/src/ui/utils/commandUtils.test.js +5 -2
  334. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  335. package/dist/src/ui/utils/terminalSetup.js +45 -18
  336. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  337. package/dist/src/utils/attentionNotification.d.ts +20 -0
  338. package/dist/src/utils/attentionNotification.js +34 -0
  339. package/dist/src/utils/attentionNotification.js.map +1 -0
  340. package/dist/src/utils/attentionNotification.test.d.ts +6 -0
  341. package/dist/src/utils/attentionNotification.test.js +46 -0
  342. package/dist/src/utils/attentionNotification.test.js.map +1 -0
  343. package/dist/src/utils/dialogScopeUtils.d.ts +0 -4
  344. package/dist/src/utils/dialogScopeUtils.js +5 -2
  345. package/dist/src/utils/dialogScopeUtils.js.map +1 -1
  346. package/dist/src/utils/errors.d.ts +10 -2
  347. package/dist/src/utils/errors.js +14 -13
  348. package/dist/src/utils/errors.js.map +1 -1
  349. package/dist/src/utils/errors.test.js +91 -54
  350. package/dist/src/utils/errors.test.js.map +1 -1
  351. package/dist/src/utils/nonInteractiveHelpers.d.ts +88 -0
  352. package/dist/src/utils/nonInteractiveHelpers.js +470 -0
  353. package/dist/src/utils/nonInteractiveHelpers.js.map +1 -0
  354. package/dist/src/utils/nonInteractiveHelpers.test.d.ts +6 -0
  355. package/dist/src/utils/nonInteractiveHelpers.test.js +945 -0
  356. package/dist/src/utils/nonInteractiveHelpers.test.js.map +1 -0
  357. package/dist/src/utils/sandbox.js +1 -1
  358. package/dist/src/utils/sandbox.js.map +1 -1
  359. package/dist/src/utils/settingsUtils.js +7 -1
  360. package/dist/src/utils/settingsUtils.js.map +1 -1
  361. package/dist/src/utils/systemInfo.d.ts +66 -0
  362. package/dist/src/utils/systemInfo.js +125 -0
  363. package/dist/src/utils/systemInfo.js.map +1 -0
  364. package/dist/src/utils/systemInfo.test.d.ts +6 -0
  365. package/dist/src/utils/systemInfo.test.js +259 -0
  366. package/dist/src/utils/systemInfo.test.js.map +1 -0
  367. package/dist/src/utils/systemInfoFields.d.ts +22 -0
  368. package/dist/src/utils/systemInfoFields.js +96 -0
  369. package/dist/src/utils/systemInfoFields.js.map +1 -0
  370. package/dist/src/utils/userStartupWarnings.js +9 -4
  371. package/dist/src/utils/userStartupWarnings.js.map +1 -1
  372. package/dist/src/validateNonInterActiveAuth.js +27 -6
  373. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  374. package/dist/src/zed-integration/acp.js +1 -2
  375. package/dist/src/zed-integration/acp.js.map +1 -1
  376. package/dist/src/zed-integration/schema.d.ts +506 -264
  377. package/dist/src/zed-integration/schema.js +13 -0
  378. package/dist/src/zed-integration/schema.js.map +1 -1
  379. package/dist/src/zed-integration/zedIntegration.js +376 -32
  380. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  381. package/dist/tsconfig.tsbuildinfo +1 -1
  382. package/package.json +12 -4
@@ -0,0 +1,808 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { GeminiEventType } from '@umsai/ums-code-core';
8
+ import { StreamJsonOutputAdapter } from './StreamJsonOutputAdapter.js';
9
+ function createMockConfig() {
10
+ return {
11
+ getSessionId: vi.fn().mockReturnValue('test-session-id'),
12
+ getModel: vi.fn().mockReturnValue('test-model'),
13
+ };
14
+ }
15
+ describe('StreamJsonOutputAdapter', () => {
16
+ let adapter;
17
+ let mockConfig;
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ let stdoutWriteSpy;
20
+ beforeEach(() => {
21
+ mockConfig = createMockConfig();
22
+ stdoutWriteSpy = vi
23
+ .spyOn(process.stdout, 'write')
24
+ .mockImplementation(() => true);
25
+ });
26
+ afterEach(() => {
27
+ stdoutWriteSpy.mockRestore();
28
+ });
29
+ describe('with partial messages enabled', () => {
30
+ beforeEach(() => {
31
+ adapter = new StreamJsonOutputAdapter(mockConfig, true);
32
+ });
33
+ describe('startAssistantMessage', () => {
34
+ it('should reset state for new message', () => {
35
+ adapter.startAssistantMessage();
36
+ adapter.processEvent({
37
+ type: GeminiEventType.Content,
38
+ value: 'First',
39
+ });
40
+ adapter.finalizeAssistantMessage();
41
+ adapter.startAssistantMessage();
42
+ adapter.processEvent({
43
+ type: GeminiEventType.Content,
44
+ value: 'Second',
45
+ });
46
+ const message = adapter.finalizeAssistantMessage();
47
+ expect(message.message.content[0]).toMatchObject({
48
+ type: 'text',
49
+ text: 'Second',
50
+ });
51
+ });
52
+ });
53
+ describe('processEvent with stream events', () => {
54
+ beforeEach(() => {
55
+ adapter.startAssistantMessage();
56
+ });
57
+ it('should emit stream events for text deltas', () => {
58
+ adapter.processEvent({
59
+ type: GeminiEventType.Content,
60
+ value: 'Hello',
61
+ });
62
+ const calls = stdoutWriteSpy.mock.calls;
63
+ expect(calls.length).toBeGreaterThan(0);
64
+ const deltaEventCall = calls.find((call) => {
65
+ try {
66
+ const parsed = JSON.parse(call[0]);
67
+ return (parsed.type === 'stream_event' &&
68
+ parsed.event.type === 'content_block_delta');
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ });
74
+ expect(deltaEventCall).toBeDefined();
75
+ const parsed = JSON.parse(deltaEventCall[0]);
76
+ expect(parsed.event.type).toBe('content_block_delta');
77
+ expect(parsed.event.delta).toMatchObject({
78
+ type: 'text_delta',
79
+ text: 'Hello',
80
+ });
81
+ });
82
+ it('should emit message_start event on first content', () => {
83
+ adapter.processEvent({
84
+ type: GeminiEventType.Content,
85
+ value: 'First',
86
+ });
87
+ const calls = stdoutWriteSpy.mock.calls;
88
+ const messageStartCall = calls.find((call) => {
89
+ try {
90
+ const parsed = JSON.parse(call[0]);
91
+ return (parsed.type === 'stream_event' &&
92
+ parsed.event.type === 'message_start');
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ });
98
+ expect(messageStartCall).toBeDefined();
99
+ });
100
+ it('should emit content_block_start for new blocks', () => {
101
+ adapter.processEvent({
102
+ type: GeminiEventType.Content,
103
+ value: 'Text',
104
+ });
105
+ const calls = stdoutWriteSpy.mock.calls;
106
+ const blockStartCall = calls.find((call) => {
107
+ try {
108
+ const parsed = JSON.parse(call[0]);
109
+ return (parsed.type === 'stream_event' &&
110
+ parsed.event.type === 'content_block_start');
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ });
116
+ expect(blockStartCall).toBeDefined();
117
+ });
118
+ it('should emit thinking delta events', () => {
119
+ adapter.processEvent({
120
+ type: GeminiEventType.Thought,
121
+ value: {
122
+ subject: 'Planning',
123
+ description: 'Thinking',
124
+ },
125
+ });
126
+ const calls = stdoutWriteSpy.mock.calls;
127
+ const deltaCall = calls.find((call) => {
128
+ try {
129
+ const parsed = JSON.parse(call[0]);
130
+ return (parsed.type === 'stream_event' &&
131
+ parsed.event.type === 'content_block_delta' &&
132
+ parsed.event.delta.type === 'thinking_delta');
133
+ }
134
+ catch {
135
+ return false;
136
+ }
137
+ });
138
+ expect(deltaCall).toBeDefined();
139
+ });
140
+ it('should emit message_stop on finalization', () => {
141
+ adapter.processEvent({
142
+ type: GeminiEventType.Content,
143
+ value: 'Text',
144
+ });
145
+ adapter.finalizeAssistantMessage();
146
+ const calls = stdoutWriteSpy.mock.calls;
147
+ const messageStopCall = calls.find((call) => {
148
+ try {
149
+ const parsed = JSON.parse(call[0]);
150
+ return (parsed.type === 'stream_event' &&
151
+ parsed.event.type === 'message_stop');
152
+ }
153
+ catch {
154
+ return false;
155
+ }
156
+ });
157
+ expect(messageStopCall).toBeDefined();
158
+ });
159
+ });
160
+ });
161
+ describe('with partial messages disabled', () => {
162
+ beforeEach(() => {
163
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
164
+ });
165
+ it('should not emit stream events', () => {
166
+ adapter.startAssistantMessage();
167
+ adapter.processEvent({
168
+ type: GeminiEventType.Content,
169
+ value: 'Text',
170
+ });
171
+ const calls = stdoutWriteSpy.mock.calls;
172
+ const streamEventCall = calls.find((call) => {
173
+ try {
174
+ const parsed = JSON.parse(call[0]);
175
+ return parsed.type === 'stream_event';
176
+ }
177
+ catch {
178
+ return false;
179
+ }
180
+ });
181
+ expect(streamEventCall).toBeUndefined();
182
+ });
183
+ it('should still emit final assistant message', () => {
184
+ adapter.startAssistantMessage();
185
+ adapter.processEvent({
186
+ type: GeminiEventType.Content,
187
+ value: 'Text',
188
+ });
189
+ adapter.finalizeAssistantMessage();
190
+ const calls = stdoutWriteSpy.mock.calls;
191
+ const assistantCall = calls.find((call) => {
192
+ try {
193
+ const parsed = JSON.parse(call[0]);
194
+ return parsed.type === 'assistant';
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ });
200
+ expect(assistantCall).toBeDefined();
201
+ });
202
+ });
203
+ describe('processEvent', () => {
204
+ beforeEach(() => {
205
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
206
+ adapter.startAssistantMessage();
207
+ });
208
+ it('should append text content from Content events', () => {
209
+ adapter.processEvent({
210
+ type: GeminiEventType.Content,
211
+ value: 'Hello',
212
+ });
213
+ adapter.processEvent({
214
+ type: GeminiEventType.Content,
215
+ value: ' World',
216
+ });
217
+ const message = adapter.finalizeAssistantMessage();
218
+ expect(message.message.content).toHaveLength(1);
219
+ expect(message.message.content[0]).toMatchObject({
220
+ type: 'text',
221
+ text: 'Hello World',
222
+ });
223
+ });
224
+ it('should append citation content from Citation events', () => {
225
+ adapter.processEvent({
226
+ type: GeminiEventType.Citation,
227
+ value: 'Citation text',
228
+ });
229
+ const message = adapter.finalizeAssistantMessage();
230
+ expect(message.message.content[0]).toMatchObject({
231
+ type: 'text',
232
+ text: expect.stringContaining('Citation text'),
233
+ });
234
+ });
235
+ it('should ignore non-string citation values', () => {
236
+ adapter.processEvent({
237
+ type: GeminiEventType.Citation,
238
+ value: 123,
239
+ });
240
+ const message = adapter.finalizeAssistantMessage();
241
+ expect(message.message.content).toHaveLength(0);
242
+ });
243
+ it('should append thinking from Thought events', () => {
244
+ adapter.processEvent({
245
+ type: GeminiEventType.Thought,
246
+ value: {
247
+ subject: 'Planning',
248
+ description: 'Thinking about the task',
249
+ },
250
+ });
251
+ const message = adapter.finalizeAssistantMessage();
252
+ expect(message.message.content).toHaveLength(1);
253
+ expect(message.message.content[0]).toMatchObject({
254
+ type: 'thinking',
255
+ thinking: 'Planning: Thinking about the task',
256
+ signature: 'Planning',
257
+ });
258
+ });
259
+ it('should handle thinking with only subject', () => {
260
+ adapter.processEvent({
261
+ type: GeminiEventType.Thought,
262
+ value: {
263
+ subject: 'Planning',
264
+ description: '',
265
+ },
266
+ });
267
+ const message = adapter.finalizeAssistantMessage();
268
+ expect(message.message.content[0]).toMatchObject({
269
+ type: 'thinking',
270
+ signature: 'Planning',
271
+ });
272
+ });
273
+ it('should append tool use from ToolCallRequest events', () => {
274
+ adapter.processEvent({
275
+ type: GeminiEventType.ToolCallRequest,
276
+ value: {
277
+ callId: 'tool-call-1',
278
+ name: 'test_tool',
279
+ args: { param1: 'value1' },
280
+ isClientInitiated: false,
281
+ prompt_id: 'prompt-1',
282
+ },
283
+ });
284
+ const message = adapter.finalizeAssistantMessage();
285
+ expect(message.message.content).toHaveLength(1);
286
+ expect(message.message.content[0]).toMatchObject({
287
+ type: 'tool_use',
288
+ id: 'tool-call-1',
289
+ name: 'test_tool',
290
+ input: { param1: 'value1' },
291
+ });
292
+ });
293
+ it('should set stop_reason to tool_use when message contains only tool_use blocks', () => {
294
+ adapter.processEvent({
295
+ type: GeminiEventType.ToolCallRequest,
296
+ value: {
297
+ callId: 'tool-call-1',
298
+ name: 'test_tool',
299
+ args: { param1: 'value1' },
300
+ isClientInitiated: false,
301
+ prompt_id: 'prompt-1',
302
+ },
303
+ });
304
+ const message = adapter.finalizeAssistantMessage();
305
+ expect(message.message.stop_reason).toBe('tool_use');
306
+ });
307
+ it('should set stop_reason to null when message contains text blocks', () => {
308
+ adapter.processEvent({
309
+ type: GeminiEventType.Content,
310
+ value: 'Some text',
311
+ });
312
+ const message = adapter.finalizeAssistantMessage();
313
+ expect(message.message.stop_reason).toBeNull();
314
+ });
315
+ it('should set stop_reason to null when message contains thinking blocks', () => {
316
+ adapter.processEvent({
317
+ type: GeminiEventType.Thought,
318
+ value: {
319
+ subject: 'Planning',
320
+ description: 'Thinking about the task',
321
+ },
322
+ });
323
+ const message = adapter.finalizeAssistantMessage();
324
+ expect(message.message.stop_reason).toBeNull();
325
+ });
326
+ it('should set stop_reason to tool_use when message contains multiple tool_use blocks', () => {
327
+ adapter.processEvent({
328
+ type: GeminiEventType.ToolCallRequest,
329
+ value: {
330
+ callId: 'tool-call-1',
331
+ name: 'test_tool_1',
332
+ args: { param1: 'value1' },
333
+ isClientInitiated: false,
334
+ prompt_id: 'prompt-1',
335
+ },
336
+ });
337
+ adapter.processEvent({
338
+ type: GeminiEventType.ToolCallRequest,
339
+ value: {
340
+ callId: 'tool-call-2',
341
+ name: 'test_tool_2',
342
+ args: { param2: 'value2' },
343
+ isClientInitiated: false,
344
+ prompt_id: 'prompt-1',
345
+ },
346
+ });
347
+ const message = adapter.finalizeAssistantMessage();
348
+ expect(message.message.content).toHaveLength(2);
349
+ expect(message.message.content.every((block) => block.type === 'tool_use')).toBe(true);
350
+ expect(message.message.stop_reason).toBe('tool_use');
351
+ });
352
+ it('should update usage from Finished event', () => {
353
+ const usageMetadata = {
354
+ promptTokenCount: 100,
355
+ candidatesTokenCount: 50,
356
+ cachedContentTokenCount: 10,
357
+ totalTokenCount: 160,
358
+ };
359
+ adapter.processEvent({
360
+ type: GeminiEventType.Finished,
361
+ value: {
362
+ reason: undefined,
363
+ usageMetadata,
364
+ },
365
+ });
366
+ const message = adapter.finalizeAssistantMessage();
367
+ expect(message.message.usage).toMatchObject({
368
+ input_tokens: 100,
369
+ output_tokens: 50,
370
+ cache_read_input_tokens: 10,
371
+ total_tokens: 160,
372
+ });
373
+ });
374
+ it('should ignore events after finalization', () => {
375
+ adapter.finalizeAssistantMessage();
376
+ const originalContent = adapter.finalizeAssistantMessage().message.content;
377
+ adapter.processEvent({
378
+ type: GeminiEventType.Content,
379
+ value: 'Should be ignored',
380
+ });
381
+ const message = adapter.finalizeAssistantMessage();
382
+ expect(message.message.content).toEqual(originalContent);
383
+ });
384
+ });
385
+ describe('finalizeAssistantMessage', () => {
386
+ beforeEach(() => {
387
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
388
+ adapter.startAssistantMessage();
389
+ });
390
+ it('should build and emit a complete assistant message', () => {
391
+ adapter.processEvent({
392
+ type: GeminiEventType.Content,
393
+ value: 'Test response',
394
+ });
395
+ const message = adapter.finalizeAssistantMessage();
396
+ expect(message.type).toBe('assistant');
397
+ expect(message.uuid).toBeTruthy();
398
+ expect(message.session_id).toBe('test-session-id');
399
+ expect(message.parent_tool_use_id).toBeNull();
400
+ expect(message.message.role).toBe('assistant');
401
+ expect(message.message.model).toBe('test-model');
402
+ expect(message.message.content).toHaveLength(1);
403
+ });
404
+ it('should emit message to stdout immediately', () => {
405
+ adapter.processEvent({
406
+ type: GeminiEventType.Content,
407
+ value: 'Test',
408
+ });
409
+ stdoutWriteSpy.mockClear();
410
+ adapter.finalizeAssistantMessage();
411
+ expect(stdoutWriteSpy).toHaveBeenCalled();
412
+ const output = stdoutWriteSpy.mock.calls[0][0];
413
+ const parsed = JSON.parse(output);
414
+ expect(parsed.type).toBe('assistant');
415
+ });
416
+ it('should store message in lastAssistantMessage', () => {
417
+ adapter.processEvent({
418
+ type: GeminiEventType.Content,
419
+ value: 'Test',
420
+ });
421
+ const message = adapter.finalizeAssistantMessage();
422
+ // Access protected property for testing
423
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
424
+ expect(adapter.lastAssistantMessage).toEqual(message);
425
+ });
426
+ it('should return same message on subsequent calls', () => {
427
+ adapter.processEvent({
428
+ type: GeminiEventType.Content,
429
+ value: 'Test',
430
+ });
431
+ const message1 = adapter.finalizeAssistantMessage();
432
+ const message2 = adapter.finalizeAssistantMessage();
433
+ expect(message1).toEqual(message2);
434
+ });
435
+ it('should split different block types into separate assistant messages', () => {
436
+ stdoutWriteSpy.mockClear();
437
+ adapter.processEvent({
438
+ type: GeminiEventType.Content,
439
+ value: 'Text',
440
+ });
441
+ adapter.processEvent({
442
+ type: GeminiEventType.Thought,
443
+ value: { subject: 'Thinking', description: 'Thought' },
444
+ });
445
+ const message = adapter.finalizeAssistantMessage();
446
+ expect(message.message.content).toHaveLength(1);
447
+ expect(message.message.content[0].type).toBe('thinking');
448
+ const assistantMessages = stdoutWriteSpy.mock.calls
449
+ .map((call) => JSON.parse(call[0]))
450
+ .filter((payload) => {
451
+ if (typeof payload !== 'object' ||
452
+ payload === null ||
453
+ !('type' in payload) ||
454
+ payload.type !== 'assistant' ||
455
+ !('message' in payload)) {
456
+ return false;
457
+ }
458
+ const message = payload.message;
459
+ if (typeof message !== 'object' ||
460
+ message === null ||
461
+ !('content' in message)) {
462
+ return false;
463
+ }
464
+ const content = message.content;
465
+ return (Array.isArray(content) &&
466
+ content.length > 0 &&
467
+ content.every((block) => typeof block === 'object' &&
468
+ block !== null &&
469
+ 'type' in block));
470
+ });
471
+ expect(assistantMessages).toHaveLength(2);
472
+ const observedTypes = assistantMessages.map((payload) => payload.message.content[0]?.type ?? '');
473
+ expect(observedTypes).toEqual(['text', 'thinking']);
474
+ for (const payload of assistantMessages) {
475
+ const uniqueTypes = new Set(payload.message.content.map((block) => block.type));
476
+ expect(uniqueTypes.size).toBeLessThanOrEqual(1);
477
+ }
478
+ });
479
+ it('should throw if message not started', () => {
480
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
481
+ expect(() => adapter.finalizeAssistantMessage()).toThrow('Message not started');
482
+ });
483
+ });
484
+ describe('emitResult', () => {
485
+ beforeEach(() => {
486
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
487
+ adapter.startAssistantMessage();
488
+ adapter.processEvent({
489
+ type: GeminiEventType.Content,
490
+ value: 'Response text',
491
+ });
492
+ adapter.finalizeAssistantMessage();
493
+ });
494
+ it('should emit success result immediately', () => {
495
+ stdoutWriteSpy.mockClear();
496
+ adapter.emitResult({
497
+ isError: false,
498
+ durationMs: 1000,
499
+ apiDurationMs: 800,
500
+ numTurns: 1,
501
+ });
502
+ expect(stdoutWriteSpy).toHaveBeenCalled();
503
+ const output = stdoutWriteSpy.mock.calls[0][0];
504
+ const parsed = JSON.parse(output);
505
+ expect(parsed.type).toBe('result');
506
+ expect(parsed.is_error).toBe(false);
507
+ expect(parsed.subtype).toBe('success');
508
+ expect(parsed.result).toBe('Response text');
509
+ expect(parsed.duration_ms).toBe(1000);
510
+ expect(parsed.num_turns).toBe(1);
511
+ });
512
+ it('should emit error result', () => {
513
+ stdoutWriteSpy.mockClear();
514
+ adapter.emitResult({
515
+ isError: true,
516
+ errorMessage: 'Test error',
517
+ durationMs: 500,
518
+ apiDurationMs: 300,
519
+ numTurns: 1,
520
+ });
521
+ const output = stdoutWriteSpy.mock.calls[0][0];
522
+ const parsed = JSON.parse(output);
523
+ expect(parsed.is_error).toBe(true);
524
+ expect(parsed.subtype).toBe('error_during_execution');
525
+ expect(parsed.error?.message).toBe('Test error');
526
+ });
527
+ it('should use provided summary over extracted text', () => {
528
+ stdoutWriteSpy.mockClear();
529
+ adapter.emitResult({
530
+ isError: false,
531
+ summary: 'Custom summary',
532
+ durationMs: 1000,
533
+ apiDurationMs: 800,
534
+ numTurns: 1,
535
+ });
536
+ const output = stdoutWriteSpy.mock.calls[0][0];
537
+ const parsed = JSON.parse(output);
538
+ expect(parsed.result).toBe('Custom summary');
539
+ });
540
+ it('should include usage information', () => {
541
+ const usage = {
542
+ input_tokens: 100,
543
+ output_tokens: 50,
544
+ total_tokens: 150,
545
+ };
546
+ stdoutWriteSpy.mockClear();
547
+ adapter.emitResult({
548
+ isError: false,
549
+ usage,
550
+ durationMs: 1000,
551
+ apiDurationMs: 800,
552
+ numTurns: 1,
553
+ });
554
+ const output = stdoutWriteSpy.mock.calls[0][0];
555
+ const parsed = JSON.parse(output);
556
+ expect(parsed.usage).toEqual(usage);
557
+ });
558
+ it('should handle result without assistant message', () => {
559
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
560
+ stdoutWriteSpy.mockClear();
561
+ adapter.emitResult({
562
+ isError: false,
563
+ durationMs: 1000,
564
+ apiDurationMs: 800,
565
+ numTurns: 1,
566
+ });
567
+ const output = stdoutWriteSpy.mock.calls[0][0];
568
+ const parsed = JSON.parse(output);
569
+ expect(parsed.result).toBe('');
570
+ });
571
+ });
572
+ describe('emitUserMessage', () => {
573
+ beforeEach(() => {
574
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
575
+ });
576
+ it('should emit user message immediately', () => {
577
+ stdoutWriteSpy.mockClear();
578
+ const parts = [{ text: 'Hello user' }];
579
+ adapter.emitUserMessage(parts);
580
+ expect(stdoutWriteSpy).toHaveBeenCalled();
581
+ const output = stdoutWriteSpy.mock.calls[0][0];
582
+ const parsed = JSON.parse(output);
583
+ expect(parsed.type).toBe('user');
584
+ expect(Array.isArray(parsed.message.content)).toBe(true);
585
+ if (Array.isArray(parsed.message.content)) {
586
+ expect(parsed.message.content).toHaveLength(1);
587
+ expect(parsed.message.content[0]).toEqual({
588
+ type: 'text',
589
+ text: 'Hello user',
590
+ });
591
+ }
592
+ });
593
+ it('should handle parent_tool_use_id', () => {
594
+ const parts = [{ text: 'Tool response' }];
595
+ adapter.emitUserMessage(parts);
596
+ const output = stdoutWriteSpy.mock.calls[0][0];
597
+ const parsed = JSON.parse(output);
598
+ // emitUserMessage currently sets parent_tool_use_id to null
599
+ expect(parsed.parent_tool_use_id).toBeNull();
600
+ });
601
+ });
602
+ describe('emitToolResult', () => {
603
+ beforeEach(() => {
604
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
605
+ });
606
+ it('should emit tool result message immediately', () => {
607
+ stdoutWriteSpy.mockClear();
608
+ const request = {
609
+ callId: 'tool-1',
610
+ name: 'test_tool',
611
+ args: {},
612
+ isClientInitiated: false,
613
+ prompt_id: 'prompt-1',
614
+ };
615
+ const response = {
616
+ callId: 'tool-1',
617
+ responseParts: [],
618
+ resultDisplay: 'Tool executed successfully',
619
+ error: undefined,
620
+ errorType: undefined,
621
+ };
622
+ adapter.emitToolResult(request, response);
623
+ expect(stdoutWriteSpy).toHaveBeenCalled();
624
+ const output = stdoutWriteSpy.mock.calls[0][0];
625
+ const parsed = JSON.parse(output);
626
+ expect(parsed.type).toBe('user');
627
+ expect(parsed.parent_tool_use_id).toBeNull();
628
+ const block = parsed.message.content[0];
629
+ expect(block).toMatchObject({
630
+ type: 'tool_result',
631
+ tool_use_id: 'tool-1',
632
+ content: 'Tool executed successfully',
633
+ is_error: false,
634
+ });
635
+ });
636
+ it('should mark error tool results', () => {
637
+ const request = {
638
+ callId: 'tool-1',
639
+ name: 'test_tool',
640
+ args: {},
641
+ isClientInitiated: false,
642
+ prompt_id: 'prompt-1',
643
+ };
644
+ const response = {
645
+ callId: 'tool-1',
646
+ responseParts: [],
647
+ resultDisplay: undefined,
648
+ error: new Error('Tool failed'),
649
+ errorType: undefined,
650
+ };
651
+ adapter.emitToolResult(request, response);
652
+ const output = stdoutWriteSpy.mock.calls[0][0];
653
+ const parsed = JSON.parse(output);
654
+ const block = parsed.message.content[0];
655
+ expect(block.is_error).toBe(true);
656
+ });
657
+ });
658
+ describe('emitSystemMessage', () => {
659
+ beforeEach(() => {
660
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
661
+ });
662
+ it('should emit system message immediately', () => {
663
+ stdoutWriteSpy.mockClear();
664
+ adapter.emitSystemMessage('test_subtype', { data: 'value' });
665
+ expect(stdoutWriteSpy).toHaveBeenCalled();
666
+ const output = stdoutWriteSpy.mock.calls[0][0];
667
+ const parsed = JSON.parse(output);
668
+ expect(parsed.type).toBe('system');
669
+ expect(parsed.subtype).toBe('test_subtype');
670
+ expect(parsed.data).toEqual({ data: 'value' });
671
+ });
672
+ });
673
+ describe('getSessionId and getModel', () => {
674
+ beforeEach(() => {
675
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
676
+ });
677
+ it('should return session ID from config', () => {
678
+ expect(adapter.getSessionId()).toBe('test-session-id');
679
+ expect(mockConfig.getSessionId).toHaveBeenCalled();
680
+ });
681
+ it('should return model from config', () => {
682
+ expect(adapter.getModel()).toBe('test-model');
683
+ expect(mockConfig.getModel).toHaveBeenCalled();
684
+ });
685
+ });
686
+ describe('message_id in stream events', () => {
687
+ beforeEach(() => {
688
+ adapter = new StreamJsonOutputAdapter(mockConfig, true);
689
+ adapter.startAssistantMessage();
690
+ });
691
+ it('should include message_id in stream events after message starts', () => {
692
+ adapter.processEvent({
693
+ type: GeminiEventType.Content,
694
+ value: 'Text',
695
+ });
696
+ // Process another event to ensure messageStarted is true
697
+ adapter.processEvent({
698
+ type: GeminiEventType.Content,
699
+ value: 'More',
700
+ });
701
+ const calls = stdoutWriteSpy.mock.calls;
702
+ // Find all delta events
703
+ const deltaCalls = calls.filter((call) => {
704
+ try {
705
+ const parsed = JSON.parse(call[0]);
706
+ return (parsed.type === 'stream_event' &&
707
+ parsed.event.type === 'content_block_delta');
708
+ }
709
+ catch {
710
+ return false;
711
+ }
712
+ });
713
+ expect(deltaCalls.length).toBeGreaterThan(0);
714
+ // The second delta event should have message_id (after messageStarted becomes true)
715
+ // message_id is added to the event object, so check parsed.event.message_id
716
+ if (deltaCalls.length > 1) {
717
+ const secondDelta = JSON.parse(deltaCalls[1][0]);
718
+ // message_id is on the enriched event object
719
+ expect(secondDelta.event.message_id || secondDelta.message_id).toBeTruthy();
720
+ }
721
+ else {
722
+ // If only one delta, check if message_id exists
723
+ const delta = JSON.parse(deltaCalls[0][0]);
724
+ // message_id is added when messageStarted is true
725
+ // First event may or may not have it, but subsequent ones should
726
+ expect(delta.event.message_id || delta.message_id).toBeTruthy();
727
+ }
728
+ });
729
+ });
730
+ describe('multiple text blocks', () => {
731
+ beforeEach(() => {
732
+ adapter = new StreamJsonOutputAdapter(mockConfig, false);
733
+ adapter.startAssistantMessage();
734
+ });
735
+ it('should split assistant messages when block types change repeatedly', () => {
736
+ stdoutWriteSpy.mockClear();
737
+ adapter.processEvent({
738
+ type: GeminiEventType.Content,
739
+ value: 'Text content',
740
+ });
741
+ adapter.processEvent({
742
+ type: GeminiEventType.Thought,
743
+ value: { subject: 'Thinking', description: 'Thought' },
744
+ });
745
+ adapter.processEvent({
746
+ type: GeminiEventType.Content,
747
+ value: 'More text',
748
+ });
749
+ const message = adapter.finalizeAssistantMessage();
750
+ expect(message.message.content).toHaveLength(1);
751
+ expect(message.message.content[0]).toMatchObject({
752
+ type: 'text',
753
+ text: 'More text',
754
+ });
755
+ const assistantMessages = stdoutWriteSpy.mock.calls
756
+ .map((call) => JSON.parse(call[0]))
757
+ .filter((payload) => {
758
+ if (typeof payload !== 'object' ||
759
+ payload === null ||
760
+ !('type' in payload) ||
761
+ payload.type !== 'assistant' ||
762
+ !('message' in payload)) {
763
+ return false;
764
+ }
765
+ const message = payload.message;
766
+ if (typeof message !== 'object' ||
767
+ message === null ||
768
+ !('content' in message)) {
769
+ return false;
770
+ }
771
+ const content = message.content;
772
+ return (Array.isArray(content) &&
773
+ content.length > 0 &&
774
+ content.every((block) => typeof block === 'object' &&
775
+ block !== null &&
776
+ 'type' in block));
777
+ });
778
+ expect(assistantMessages).toHaveLength(3);
779
+ const observedTypes = assistantMessages.map((msg) => msg.message.content[0]?.type ?? '');
780
+ expect(observedTypes).toEqual(['text', 'thinking', 'text']);
781
+ for (const msg of assistantMessages) {
782
+ const uniqueTypes = new Set(msg.message.content.map((block) => block.type));
783
+ expect(uniqueTypes.size).toBeLessThanOrEqual(1);
784
+ }
785
+ });
786
+ it('should merge consecutive text fragments', () => {
787
+ adapter.processEvent({
788
+ type: GeminiEventType.Content,
789
+ value: 'Hello',
790
+ });
791
+ adapter.processEvent({
792
+ type: GeminiEventType.Content,
793
+ value: ' ',
794
+ });
795
+ adapter.processEvent({
796
+ type: GeminiEventType.Content,
797
+ value: 'World',
798
+ });
799
+ const message = adapter.finalizeAssistantMessage();
800
+ expect(message.message.content).toHaveLength(1);
801
+ expect(message.message.content[0]).toMatchObject({
802
+ type: 'text',
803
+ text: 'Hello World',
804
+ });
805
+ });
806
+ });
807
+ });
808
+ //# sourceMappingURL=StreamJsonOutputAdapter.test.js.map